チャレンジ一覧
正規表現マスター - ログファイル解析
/app/access.log には数千件のアクセスログが記録されています。 この中から、IPアドレスが「192.168.1.」で始まり、かつステータスコードが404のエントリをすべて抽出してください。 条件: - IPアドレス: 192.168.1.xxx - ステータスコード: 404 - 該当する行数がフラグになります ヒント: grep と正規表現を使用してください
環境変数マスター - PATH Hijacking
/app/secret_bin ディレクトリに隠されたコマンド "getflag" があります。 しかし、このディレクトリはPATHに含まれていないため、直接実行できません。 2つの方法でこのコマンドを実行してください: 1. 絶対パスで実行 2. PATHに追加して実行 コマンドを実行するとフラグが表示されます。
Docker フォレンジック - コンテナ調査
Docker デーモンの無い環境で、イメージ `registry.internal/kinoco-billing-api:2.4.1` のメタデータを調べます。`/challenge/image_history.txt`(`docker history --no-trunc` 相当、新しいレイヤーが上)と `/challenge/image_config.json`(最終的な `Config.Env` と、古い順の `History[].created_by`)があります。この Dockerfile は `DB_ADMIN_PASSWORD` を `ENV` で何度も設定し直し、途中で一度だけ `python3 scripts/bootstrap_admin.py`(環境変数 `DB_ADMIN_PASSWORD` を読む)を実行し、最後に空で上書きしました。履歴にはフラグの形をした値がいくつもあります。フラグは、bootstrap_admin.py を実行した時点で有効だった `DB_ADMIN_PASSWORD` の値、つまりビルド順でそのRUNより前にある最後の `ENV DB_ADMIN_PASSWORD=...` の値です。それより前に上書きされた値、後に設定された値、別の変数の値、別のスクリプトにだけインラインで渡した値はおとりです。
Git履歴から削除されたAPIキーを探せ
/app/repo はGitリポジトリです。開発者がAPI_KEYを誤ってコミットし、後続コミットで削除しました。 通常のGit履歴から削除前の config.py を確認し、APIキーに含まれるフラグを見つけてください。
Python自動化 - REST API データ収集
コンテナ内で `http://127.0.0.1:8000/api/records?page=N` というページ送りのローカルAPIが動いています。`next` が `null` になるまで全ページを巡回し、`tag == "flag"` のレコードだけを集めてください。各レコードは `{"seq": <int>, "part": "<断片>"}` の形式で、`seq` の昇順に `part` を連結するとフラグになります。1ページ目だけではフラグは揃わず、`login`/`metric`/`order` などのレコードはおとりです。
Python自動化 - SQLiteデータベース解析
起動のたびに作られる data.db(SQLite。users / orders / audit_log)を調べます。orders を user_id ごとに SUM(amount) で集計し、合計額が大きい社員の上位3人を求めてください(注文件数が最も多い社員や、1回の注文額が最も大きい社員はおとりで、上位3人には入りません)。audit_log には、全社員に1件ずつ action = 'security_note' の行 "Confidential clearance credential issued to this employee: <16桁16進>" があります。上位3人の credential を、合計額の大きい順に '-' でつないだものが答えです。python3 challenge.py '<答え>' に渡すと、フラグが表示されます。
Python自動化 - カスタム暗号の復号
cipher.txt には独自の暗号でエンコードされたフラグが16進で入っています。暗号化は各バイトに add(鍵加算) -> xor(位置依存) -> rotl(巡回シフト) を適用したものです。この逆変換を Python で実装してフラグを復元してください(仕様は python3 challenge.py で表示)。
Python自動化 - 暗号化ZIPのパスワードクラック
起動のたびに /challenge/secret.zip が作られます。中には flag.txt と readme.txt が入っていて、ZipCrypto で暗号化されています。パスワードは /challenge/wordlist.txt の1語のうしろに2桁の数字(00〜99)を付けたもの(例: sunshine07)で、起動のたびに選び直されます。Python 標準ライブラリの zipfile で候補を総当たりしてパスワードを見つけ、flag.txt を取り出してください。
SQLクエリマスター - 複雑な結合
SQLite データベース `/challenge/company.db` には3つのテーブルがあります。 - employees (id, name, department_id, salary, email, note) - departments (id, name, manager_id) - projects (id, name, department_id, budget) 次の条件で従業員を1人選んでください。 1. budget が 100000 以上のプロジェクトを1つ以上持つ部署(小さいプロジェクトの合計が 100000 を超えても対象外) 2. それらの部署に所属する従業員の中で salary が最も高い人 その人の note 列がフラグです。各部署の最高給の従業員の note にはどれも KINOCO{...} の形の値が入っているので、条件を1つでも外すと別の人が選ばれます。
アルゴリズム - 迷路のBFS最短経路
data.txt の S から E までの最短経路を BFS で求め、UDLR の移動列を challenge.py に入力してください。正しい経路で起動時注入 FLAG が表示されます。
システムコール追跡 - strace デバッグ
ソースコードのないプログラム `/app/mystery_program` を strace でトレースした記録 `/challenge/strace.log` を解析します。プログラムはトークンらしい中身(`KINOCO{...}` の形)のファイルをいくつも読み込みますが、(1) 隠しディレクトリ(名前が `.` で始まるディレクトリ)の中のファイルであり、かつ (2) `read` したその中身をあとで標準出力(fd 1)に `write` している、という2条件を両方満たすものはただ1つです。その中身がフラグです。普通のディレクトリにあるドットファイルは (1) を満たしません。fd 番号は `close` の後に使い回されます。
システムログ解析 - journalctl マスター
systemd ジャーナルを `journalctl -o short` 風に書き出したログ `/challenge/system.log` を解析します。各行は「日時 ホスト ユニット[PID]: 優先度: メッセージ」の形です。ユニットの欄が `authd` で、優先度の欄が `ERR` の行はただ1行で、その行のメッセージにフラグが含まれます。`KINOCO{...}` の形の文字列はほかの行にもありますが、ユニットが `authd-proxy` など別物だったり、本文に authd や ERR という文字が出てくるだけだったりします。コンテナに journalctl は無いので、`grep`/`awk` で欄の位置を見て絞り込んでください。
ネットワークマスター - Netcat リバースシェル
外部ホストへ接続せず、記録済みの artifacts/netcat/callback-transcript.log を解析してください。リスナーやシェルは起動されません。侵害されたホスト 10.0.5.23 から remote.target.com の 4444 番ポートへつながったコールバックを接続一覧から探し、その conn ID で「captured first bytes」の16進データを引き当て、文字列に戻すとフラグになります。送信元・宛先ホスト・宛先ポートのどれかが違う接続はおとりです。
ネットワーク解析 - 802.1Q VLANで分けられた通信
capture.pcapは、スイッチのトランクポートをミラーしてキャプチャした通信で、複数のVLANのフレームが802.1Qタグ付きで混ざっています。どのVLANでも同じ機器からUDP 5140番宛てに MGMT|<断片> の形で文字列が少しずつ送られ、全部が交互に混ざっています。管理VLAN 42の断片だけを届いた順につなげ、フラグを復元してください。
ネットワーク解析 - SNMP情報漏洩
弱いコミュニティ文字列(public)で SNMPv2c を喋る機器の GetResponse をキャプチャしました。配布されるパケットキャプチャ(traffic.pcap)から SNMP(UDP/161)の varbind を解析し、ベンダー独自OIDの値に含まれるフラグを回収してください。
ネットワーク解析 - SSL Stripによる平文認証情報
SSL Strip 攻撃により HTTPS が HTTP に格下げされ、被害者の認証情報が平文で流れた通信をキャプチャしました。配布されるパケットキャプチャ(traffic.pcap)から平文HTTPのPOSTを解析し、ログインのパスワード(フラグ)を抽出してください。
ネットワーク解析 - WebSocketフレームのマスク解除
capture.pcapには、ブラウザとチャットサーバーのWebSocket通信が記録されています。クライアントからサーバーへのフレームは毎回ちがう4バイトの鍵でマスクされています。フレームを解析してマスクを外し、3つのフレームに分割されたメッセージを組み立てて、デプロイ用のトークン(フラグ)を取り出してください。
ネットワーク解析 - 独自プロトコルの解読
独自の簡易バイナリプロトコルで通信するシステムのトラフィックをキャプチャしました。配布されるパケットキャプチャ(traffic.pcap)から、TCPポート9999のフレーム構造を解析し、ペイロードをデコードしてフラグを取得してください。
パフォーマンス解析 - リソースホッグを見つけろ
サーバーのスナップショット `/challenge/metrics.log` を解析します。前半は top 風のプロセス一覧(%CPU は9列目、%MEM は10列目)、後半は ps -ef 風のフルコマンドライン一覧です。%CPU が 50.0 以上かつ %MEM が 20.0 以上のプロセスはただ1つで、その PID の ps -ef 行の `--token=` 引数がフラグです。`--token=KINOCO{...}` を持つプロセスはほかにもあり、%CPU 最大・%MEM 最大のプロセスはどちらも条件を両方は満たしません。
プログラミング - SQLite証拠データベースの解析
evidence.db は起動のたびに乱数で作られる SQLite データベースです(/challenge にあります。users / sessions / access_log の3表)。trust_score が 80 以上のユーザーのセッションについて、ts がそのセッションの started 〜 ended の範囲内にある event = 'vault' の行を集め、note(6桁の16進)を ts の古い順に - でつないだ文字列を求めてください。その文字列を python3 challenge.py '<答え>' に渡すとフラグが表示されます。
プログラミング - Webスクレイピングとグラフ探索
site.json は起動のたびに乱数で作られるクロール結果です(/challenge にあります)。start と target の URL、各ページの url / links / fragment(Base64 の断片)が入っています。start から links をたどって target へ行く最短経路(一つに決まります)を求め、経路上のページ(start と target を含む)の fragment を経路の順に Base64 デコードして区切りなしでつないだ文字列を求めてください。その文字列を python3 challenge.py '<答え>' に渡すとフラグが表示されます。
プログラミング - ZIPパスワードの復元
secret.zip は起動のたびに作られる、ZipCrypto(従来の PKWARE 暗号)で暗号化された ZIP です(/challenge にあります。同じ場所に wordlist.txt もあります)。パスワードは wordlist.txt のどれか1語の後ろに、2桁の数字(00〜99)を付けたものです。パスワードを見つけて中の note.txt を取り出すと、フラグが書かれています。Python の zipfile は pwd= にパスワードを渡すと ZipCrypto の ZIP を読めます。
プログラミング - パケットログの解析
capture.txt は起動のたびに作られるパケットログです(/challenge にあります)。1行が1つのフローで、flow=<名前> payload_hex=<16進> の形をしています。payload_hex を 0x5A で XOR 復号し、flow=exfil の行を復元するとフラグが現れます。フラグは平文では置かれていません。
プログラミング - マルチスレッド結果の再構築
起動のたびに乱数で作られた並列ジョブの結果ログ worker-results.jsonl を解析します。各 slot は何度も試行されていて、途中で時間切れ(timeout)になったり後の試行に置き換えられたり(superseded)した結果も残っています。最終結果は、slot ごとに status が done のレコードのうち attempt が最大の1件だけです。その result を Base64 デコードし、レコードの worker 番号 N に対する SHA-1(worker-N の文字列) のダイジェストを先頭から繰り返し XOR して復号します。最終結果を slot の昇順につないだ40文字(小文字英数字)が答えです。答えを `python3 challenge.py '<答え>'` に渡すと、正解のときだけフラグが表示されます。