チャレンジ一覧
プログラミング - 非同期スキャン結果の解析
/challenge/scan-events.jsonl は、コンテナの起動のたびに乱数で作り直される、非同期ポートスキャナーのイベント記録です(行は順不同で、同じイベントが重複していることもあります)。state イベントは (host, port) ごとに t が最も大きいものが最終状態で、banner イベントは stream の中を seq の順につなぎ16進デコードすると1行のテキストになります。最終状態が open の 443/tcp を持つホストについて、443 のバナーから cert-fp=(8桁の16進)を取り出し、ホストの IP アドレスの数値順に - でつないだもの(例: 0a1b2c3d-4e5f6a7b)を、python3 challenge.py '<答え>' に渡してください。正しいときだけフラグが表示されます。
メモリからマルウェアのペイロードを抽出せよ
`/challenge/memstrings.txt` は、不審なプロセスのアドレス空間から取り出した文字列です。ローダーが展開した第2段ペイロード(Base64)が、おとりの文字列や Base64 に紛れています。`/challenge/malfind_region.txt` には、ファイルの裏付けが無い RWX 領域にある、ローダーのデコード処理の逆アセンブルと、同じ領域のデータ部の16進ダンプがあります。逆アセンブルからローダーが何をしているかを読み取り、第2段ペイロード(無害なドロッパーの記録で、何も実行しません)を復元して、campaign tag からフラグを取得してください。
メモリから隠されたカーネルモジュールを検出せよ
LKM ルートキットに感染した疑いのある Linux ホストのメモリから、モジュールの情報を3つ復元しました。`/challenge/modules_list.txt` はカーネルの modules 連結リスト(lsmod 相当)、`/challenge/sysfs_modules.txt` は `/sys/module/<name>/` の kobject とモジュールのアドレス情報、`/challenge/module_area.lime` は各モジュールのコア領域の先頭 8 KiB を LiME 形式(ヘッダー32バイト: magic, version, 開始アドレス, 終了アドレス, 予約)で並べたものです。連結リストから自身を外した隠しモジュールを特定し、その設定を取り出してフラグを取得してください。設定は、そのモジュールのコア領域の先頭から 0x200 バイト目に「長さ(2バイト、リトルエンディアン)+暗号化された本文」の形で置かれています。本文は、sysfs_modules.txt のそのモジュールの SrcVersion を材料に、SHA-256(`<SrcVersion>:<カウンタ>`)(カウンタは 0,1,2... の10進数)を連ねた鍵ストリームと XOR したものです。sysfs にしか無い名前には、組み込みコンポーネントやアンロード中のモジュールも混ざり、隠しモジュール以外にもおとりの設定を持つモジュールがあります。
多段階ステガノグラフィを解読せよ
`/challenge/cover.png` と `/challenge/notes.txt` に、3段階のステガノグラフィが仕掛けられています。各段階に、次の段階を読むための鍵(パスフレーズや符号の対応表)が入っていて、鍵は起動のたびに変わるため、途中を飛ばすことはできません。`cover.png` のピクセルの最下位ビット(先頭32ビットがバイト数)、PNG の `IEND` の後ろに付け足されたデータ、`notes.txt` に紛れたゼロ幅文字、の順にたどってフラグを取得してください。各段階におとりも混ざっています。
断片化されたJPEGファイルを復元せよ
`/challenge/fragments/` に、メモリーカードの未割り当て領域から回収した 256 バイトのクラスタ(`clus_NNNN.bin`)があります。番号は元の並びと無関係で、別のカメラの写真やゴミも混ざっています。`index.txt` が指す持ち主(owner=kinoco-cam-07)の JPEG を、JPEG の構造(マーカーの長さ、DRI と RSTn、EOI)から組み直してください。COM コメントの `note_enc=` は、組み直したスキャンデータ(SOS ヘッダーの直後から EOI の直前まで。RSTn マーカーとバイトスタッフィングはそのまま含む)の SHA-256 を小文字16進にした文字列を材料に、SHA-256(`<その文字列>:<カウンタ>`)(カウンタは 0,1,2... の10進数)を連ねた鍵ストリームで、メモを XOR して16進にしたものです。メモを復号してフラグを取得してください。
暗号化通信 - GPG公開鍵暗号
GnuPG の復号を練習します。`/challenge/keys/` にある秘密鍵をすべてインポートし、`/challenge/messages/` の各暗号文を復号してください。フラグを含む平文になるのは、本物の受信者鍵で暗号化された1通だけです。他は無害な業務連絡のおとりで、宛先鍵IDの突合でも一意に絞れます。本物の GnuPG が非特権環境で動作します。
暗号解析 - DSA nonce再利用による秘密鍵復元
起動のたびに新しい鍵で作られる /challenge/signatures.json には、DSA の公開パラメーター(p は1024ビット、q は160ビット、g、y)、4つの署名(message, h, r, s。h は SHA-256(message) を整数にして mod q)、暗号化されたフラグ encrypted_flag_hex が入っています。4つの署名のうち2つは同じ nonce k を使っています。同じ r を持つ2つの署名から nonce k と秘密鍵 x を復元し、SHA256(str(x)) を繰り返した XOR 鍵で encrypted_flag_hex を復号してフラグを得てください。
暗号解析 - RSAのWiener攻撃
組み込み機器の開発チームが、復号を速くするためRSAの秘密指数dをとても小さくして鍵を作りました。public_key.txtの公開指数eはnと同じくらい大きな数です。e/nの連分数展開からdを求めて ciphertext.txt を復号し、フラグを取り出してください。
暗号解析 - 線形合同法の内部状態の復元
あるサービスは、セッショントークンも暗号化の鍵ストリームも、パラメーターa, c, mが秘密の線形合同法 x_{k+1} = (a×x_k + c) mod m から作っていました。tokens.txtの連続した10個の出力からa, c, mを復元し、続きの出力を8バイトずつ並べた鍵ストリームで暗号化された secret.enc.hex を復号して、フラグを取り出してください。
破損したRAID5アレイを復元せよ
ファイルサーバー fs01 の RAID5 アレイ `/dev/md0`(4台構成)が、メンバー sdd の故障で組み上がらなくなりました。`~/evidence/` に、各メンバーのイメージ(`sdb.img`・`sdc.img`・`sde.img`、空の `sdd.img`、予備ベイにあった `sdf.img`)と、初動担当者のメモ `mdadm-examine.txt` があります。各イメージの先頭には key=value のヘッダー(NUL 詰め)があり、データ領域は `data_offset` から始まります。同じ世代のメンバーだけを使って、失われたメンバーのチャンクをパリティから復元し、チャンクを正しい順に並べて、財務共有にあった金庫のリカバリーメモを取り出してください。ブロックデバイスや mdadm は使いません(ファイルとして扱います)。
脆弱性スキャン - Nmap NSE 高度活用
社内サブネット `10.66.13.0/24` に `nmap -sV -sC --script vuln` を実行した結果が `/challenge/scan_results/nmap_scan.nmap`(通常形式)と `nmap_scan.gnmap`(grep 形式)にあります。ライブのターゲットは無く、レポートを読み解く問題です。NSE の vuln スクリプトの判定ブロックにはどれも `Finding ID: KINOCO{...}` が付いています。フラグは、`IDs:` が CVE-2020-1938(AJP の Ghostcat)で、かつ `State: VULNERABLE (Exploitable)` の判定ブロックの Finding ID です(1件だけ)。Ghostcat の LIKELY VULNERABLE / NOT VULNERABLE や、ほかの CVE の VULNERABLE (Exploitable) はおとりです。
複数のログを統合して攻撃シナリオを再構築せよ
`/challenge/web.log`、`/challenge/auth.log`、`/challenge/db.log` に、同じ侵入が多数の正規の通信に紛れて記録されています。Web への攻撃から認証の成功、データベースの機密テーブルの読み出しまでをたどり、持ち出された値からフラグを取得してください。db.log は機密テーブルの値を平文では記録せず、`value_enc`(16進)としてマスクしています。マスクは、`<セッションID>:<クライアントIP>:<端末ID>:<カウンタ>`(カウンタは 0,1,2... の10進数)の SHA-256 を連ねた鍵ストリームと値を XOR したものです。クライアント IP と端末 ID は db.log には出てきません(端末 ID は auth.log の login success の行にだけ出ます)。正規の DBA のセッションも機密テーブルを読むため、攻撃者のセッションを見分ける必要があります。
静的解析 - コード脆弱性スキャン
社内メモアプリのPythonソースコードが `/challenge/src/` にあります。前回の静的解析で指摘された9行には、行末に `# finding: KINOCO{...}` という指摘IDが付いていますが、ほとんどは偽陽性です。次の3条件をすべて満たす1行だけが本物のOSコマンドインジェクションで、その行の指摘IDがフラグです。(1) シェル経由で実行している(`subprocess.run(..., shell=True)` か `os.system(...)`)。(2) コマンド文字列に、HTTPリクエストから取った値(`request.args` / `form` / `json` / `values`)が入っている。(3) その値が途中で無害化・検証されていない(`shlex.quote`、許可リストでの確認、`int()` 変換などが無い)。指摘IDはどれも同じ形なので、grep で拾うだけでは決まりません。