ChatGPTでCTF攻略(PartⅡ 決戦SECCON14編)

SECCON14 予選 Writeup(Ez Flag Checker / Breaking Out)

SECCON14 予選 Writeup(Ez Flag Checker / Breaking Out)

はじめに

  • 日本最大級のCTFである SECCON14予選 に参加してきました
  • 結果は 267位(817チーム中)
  • ChatGPT Plus(5.2)のみ使用
  • 本Writeupも作成してもらいました(笑)
注意: 本稿はCTFの配布物(ローカルで解析可能な題材)を対象にしています。
実運用環境や第三者システムに対して同様の行為を行うことは、許可なく実施すると法令・規程違反になる可能性があります。

目次

  1. Ez Flag Checker(rev)
  2. Breaking Out(rev)
  3. 学び
  4. 参考:解法に至ったプロンプト(スクリーンショット)

(1)Ez Flag Checker

カテゴリ
Reversing(ELF)
狙い
入力検証ロジックを静的解析して「正しい入力(flag)」を導く
ポイント
固定長 / prefix / suffix チェック + XOR系変換の逆算

概要

「flag checker(入力された文字列が正しいflagか判定するプログラム)」を解析して、 “正しいflagを逆算する”タイプの問題です。

アプリケーションの挙動(ブラックボックス確認)

$ chmod +x chall
$ ./chall
Enter flag: test
wrong :(

解析方針

  1. Step 1形式チェック(長さ / prefix / suffix)を特定して入力の型を確定
  2. Step 2変換関数(暗号化/難読化)と比較対象(期待値)を見つける
  3. Step 3変換を反転(復号)して中身を復元
  4. Step 4実行で最終確認(correct flag!

具体的なペイロード(再現手順)

① 形式チェック突破用(“まず比較処理まで到達” する入力)

多くのflag checkerは、暗号チェックの前に「形式チェック」で即NGにします。 まずは prefix/suffix を満たし、長さも正しくすることで、比較処理まで到達します。

SECCON{AAAAAAAAAAAAAAAAAA}

※中身(Aの個数)はバイナリの要求長に合わせて調整します。ここは「比較処理まで到達する」ためのダミー入力です。

② “差分観測” 用(位置ずらし・1文字変更テスト)

XOR系の可逆変換では、特定位置だけ変えると差分が局所的に出ることが多く、解析の手掛かりになります。

SECCON{AAAAAAAAAAAAAAAAA!}
SECCON{AAAAAAAAAAAAAAAA!!}
SECCON{AAAAAAAAAAAAAAA!!!}
ポイント: こうした「差分入力」は、gdbで比較ループにブレークしてレジスタ/メモリを見たり、 期待値配列(暗号文)がどこに置かれているかを特定する際に役立ちます。

③ 復号スクリプト(可逆変換を反転)

変換関数の式(例:out[i] = in[i] XOR (key[i%16] + i))と期待値(暗号文)が分かれば、同じXORで復号できます。 下は “同種の可逆変換” を反転する雛形です。

# 例:XORでの復号(雛形)
# key / cipher はバイナリ解析で取得した値を入れる

key = b"expand 32-byte k"
cipher = bytes([0x03,0x15,0x13,0x03,0x11,0x55,0x1f,0x43,0x63,0x61,0x59,0xef,0xbc,0x10,0x1f,0x43,0x54,0xa8])

keystream = bytes(((key[i % 16] + i) & 0xff) for i in range(len(cipher)))
plain = bytes(c ^ k for c, k in zip(cipher, keystream))
print(plain.decode())

④ 取得できたflag

SECCON{flagc29yYW5k<b19!!}

(2)Breaking Out

カテゴリ
Reversing (Web / Game :クライアントサイド解析)
狙い
「stage100に何かある」を手掛かりに、ゲームデータを解析してflagを回収
ポイント
クライアントに復号ロジックとデータがある=到達せずに解析で抜ける

概要

ブロック崩し風のWebゲームで、問題文のヒントは 「There is something at stage 100」。 つまり “100面” に特別なデータがある想定です。

脆弱性(CTF的な弱点)

本問の“脆弱性”はサーバ侵入ではなく、 ゲームの核心データと復号ロジックがクライアント側JSに同梱されている点です。

  • ゲームを頑張って100面まで到達しなくても、JS解析でstage100のデータを抽出できる
  • 圧縮/暗号化されていても、復号ロジックが同梱なら “時間の問題”

具体的なペイロード(再現手順)

① stage100(ステージ定義)を取り出す

DevTools(F12)→ Console で、ステージ定義が配列として存在する場合は直接参照できます。 (CTF配布のソースでは stage 情報がJS内に保持されていました)

// 例:0始まりの配列なら stage100 は [99]
const stage100 = stages[99];
console.log(stage100);

② ブロック配置(layout)を 0/1 に落とす

const layout = stage100.layout;       // 例:2次元配列
const bin = layout.map(row => row.map(cell => cell ? 1 : 0));
console.log(bin);

③ 画像化(Canvasに描画してQRとして読み取る)

stage100 のレイアウトがQRコード状の二値画像になっていたため、Canvasに描画して読み取りました。

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

const size = bin.length;        // 正方形を想定
canvas.width = canvas.height = size;

// 1セル=1px(小さければ後で拡大してもOK)
for (let y = 0; y < size; y++) {
  for (let x = 0; x < size; x++) {
    ctx.fillStyle = bin[y][x] ? "black" : "white";
    ctx.fillRect(x, y, 1, 1);
  }
}

document.body.appendChild(canvas);
読み取りのコツ: Canvasが小さすぎる場合は、描画倍率を上げて fillRect(x*scale, y*scale, scale, scale) にするとQRリーダーが認識しやすくなります。

④ QRの中身(最終ペイロード=flag)

flag: SECCON{H4ve_y0u_3ver_p14yed_Atari?_SQiOIVX6HPtRekE1vTn4}
ポイント: “ゲームを攻略して先へ進む” が正攻法に見えても、CTFでは「データがクライアントにあるなら解析で抜く」が最短になることが多いです。

学び

共通して言えること

  • 入力検証は “どこで何を比較しているか” を見つけると勝ち筋が見える
  • クライアントサイドは攻撃者が自由に観測/改変できる前提で設計する
  • 難読化・圧縮・暗号化は、復号ロジックも同梱なら “時間の問題”

実務に活かす観点(チェックリスト)

  • クライアントに「秘密情報」や「判定の最終権限」を置いていないか?
  • ライセンスキー/フラグ/トークンのような “価値のあるもの” をフロントに埋めていないか?
  • 「検証」や「権限確認」をサーバ側でやっているか?
  • ローカル保存(localStorage等)の値を信用していないか?

※本Writeupは攻撃の考え方を中心にまとめています。

参考:解法に至ったプロンプト(スクリーンショット)

参考として、2問の回答を導いたプロンプト(やり取り)をスクリーンショットした画像を掲載します。

Ez Flag Checker

Breaking Out

コメント

このブログの人気の投稿

ProxmoxでLet's Encryptを使用した証明書セットアップをやってみた

AIと共に「考える」エンジニアに!

ルーティングって何で必要で、何してるの?を React Routerで理解する