前言
這次隊名關於一群資安麻瓜為了打進決賽拿到名次而組成一隊努力練習這檔事
初賽第 43 名,其他不想寫,直接進正文
WP
Day31- 水落石出!真相大白的十一月預告信?
這題找了很久~~
前面以為是個資 Leak 一直找各種沒碼到的 Mail,找到一兩個,但沒啥資料
然後發現行不通,就開始在出題者 Kazma 的 Blog 和 iThome 用 Google Hacking 找各種 "kazma" "Day31"
,也是沒東西
最後還找到 Kazma Blog 在 Github 的倉庫,整個 Clone 下來繼續找,還是找不到
然後最後隊友和我說他有看到很像 TG Token 的東西,我看完罵髒話後大概十分鐘就用出來了。
題目給了一個標的:https://ithelp.ithome.com.tw/users/20168875/ironman/7849
而最後是在 https://ithelp.ithome.com.tw/articles/10363058 這邊文章發現 TG Bot Token Leak
裡面的程式有一行 https://api.telegram.org/bot7580842046:AAEKmOz8n3C265m2_XSv8cGFbBHg7mcnbMM/sendPhoto
洩漏了 Token 7580842046:AAEKmOz8n3C265m2_XSv8cGFbBHg7mcnbMM
然後根據 Telegram API 說明,可以知道 https://api.telegram.org/bot<token>/getUpdates
可以取得聊天內容
所以就進入 https://api.telegram.org/bot7580842046:AAEKmOz8n3C265m2_XSv8cGFbBHg7mcnbMM/getUpdates
取得 Flag
Preview Site
先上原始碼
from flask import Flask, request, redirect, render_template, session, url_for, flash
import urllib.request
import urllib.error
import urllib.parse
import os
app = Flask(__name__)
app.secret_key = os.urandom(24)
users = {'guest': 'guest'}
def send_request(url, follow=True):
try:
response = urllib.request.urlopen(url)
except urllib.error.HTTPError as e:
response = e
redirect_url = response.geturl()
if redirect_url != url and follow:
return send_request(redirect_url, follow=False)
return response.read().decode('utf-8')
@app.route('/login', methods=['GET', 'POST'])
def login():
next_url = request.args.get('next', url_for('index'))
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if users.get(username) == password:
session['username'] = username
flash('login success')
return redirect(next_url)
else:
error = 'login failed'
return render_template('login.html', error=error, next=next_url)
return render_template('login.html', next=next_url)
@app.route('/logout')
def logout():
session.pop('username', None)
next_url = request.args.get('next', url_for('index'))
return redirect(next_url)
@app.route('/fetch', methods=['GET', 'POST'])
def fetch():
if 'username' not in session:
return redirect(url_for('login'))
if request.method == 'POST':
url = request.form.get('url')
if not url:
flash('Please provide a URL.')
return render_template('fetch.html')
try:
if not url.startswith(os.getenv("DOMAIN", "http://previewsite/")):
raise ValueError('badhacker')
resp = send_request(url)
return render_template('fetch.html', content=resp)
except Exception as e:
error = f'error:{e}'
return render_template('fetch.html', error=error)
return render_template('fetch.html')
@app.route('/')
def index():
username = session.get('username')
return render_template('index.html', username=username)
首先 guest/guest 登入
然後可以看到 /fetch
會透過 send_request
去戳 http://previewsite/
的網頁,然後把內容 Show 出來
然後丟 http://previewsite/
可以看到他又把這個題目網頁丟出來了,所以繼續看這題的原始碼。
可以看到 /login
和 logout
都有:
next_url = request.args.get('next', url_for('index'))
return redirect(next_url)
可以知道可以帶一個網址進去 next_url
達到 Open Redirect,然而,/login
限制使用 HTTP POST,因此無法利用。
所以使用 /logout
做 Open Redirect
Payload http://previewsite/logout?&next=file:///flag
PS.因為機器是 Linux,所以是 file://
/flag
,三個斜線。
proxy
這題沒解出來,但賽後看大家討論覺得值得筆記一下,供以後參考。
<?php
function proxy($service) {
// $service = "switchrange";
// $service = "previewsite";
// $service = "越獄";
$requestUri = $_SERVER['REQUEST_URI'];
$parsedUrl = parse_url($requestUri);
$port = 80;
if (isset($_GET['port'])) {
$port = (int)$_GET['port'];
} else if ($_COOKIE["port"]) {
$port = (int)$_COOKIE['port'];
}
setcookie("service", $service);
setcookie("port", $port);
$ch = curl_init();
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$filter = '!$%^&*()=+[]{}|;\'",<>?_-/#:.\\@';
$fixeddomain = trim(trim($service, $filter).".cggc.chummy.tw:".$port, $filter);
$fixeddomain = idn_to_ascii($fixeddomain);
$fixeddomain = preg_replace('/[^0-9a-zA-Z-.:_]/', '', $fixeddomain);
curl_setopt($ch, CURLOPT_URL, 'http://'.$fixeddomain.$parsedUrl['path'].'?'.$_SERVER['QUERY_STRING']);
curl_exec($ch);
curl_close($ch);
}
if (!isset($_GET['service']) && !isset($_COOKIE["service"])) {
highlight_file(__FILE__);
} else if (isset($_GET['service'])) {
proxy($_GET['service']);
} else {
proxy($_COOKIE["service"]);
}
這題官方解是 xn--a
,意圖是讓 idn_to_ascii
爛掉,其他參賽者有人用一堆 a 塞爆 php 成功讓它爛掉,也有人用前一題的 open redirect 破出來。
而我們自己以為是要繞他的防護,idn_to_ascii
可以用全形字符來 Bypass 前面的兩次 trim
,但最後還是卡在後面的 .cggc.chummy.tw:
和正則表達繞不掉。