チャレンジ一覧
AWS CLI - S3バケット調査
S3 の設定をオフラインでエクスポートした監査記録が `/challenge/s3_audit/` にあります(`buckets.json` と、バケットごとの `*_publicaccessblock.json`・`*_policy.json`・`*_acl.json`・`*_objects.json`)。機密オブジェクト(`backups/prod.env` または `credentials/service-account.json`)を持つバケットは多数あり、どの `object_preview` にもフラグの形をした値があります。フラグは、本当に世界中に公開されているただ1つのバケットの機密オブジェクトにある値です。その条件は、(1) PublicAccessBlock の4設定がすべて false で、(2) ポリシーに `Effect: Allow`・`Principal: "*"`・`Action` に `s3:GetObject` を含み・`Resource` に `arn:aws:s3:::<バケット名>/*` を含み・`Condition` が無い statement があることです。ほかのバケットは、このどれか1つだけを外したおとりです。
Androidアプリから秘密鍵を抽出せよ
安全なZIP形式APK fixture(evidence/app.apk)を展開し、Androidリソースに記録された暗号化済みAPIシークレットを解析してください。開発者がビルドに同梱してしまった秘密鍵のうち、どれがそのシークレットに対応するかを見極めて復号します。実端末や実アプリは使用しません。
Ansible自動化 - サーバー構成管理
Ansibleや実サーバーを実行せず、生成済みの実行記録 artifacts/ansible/vault-export.yml を解析してください。記録には多数のタスク結果があり、そのうち多くに vault_payload_hex が付いています。本物は、host が web-03、task が deploy-index、status が changed の3つがすべて一致する1件だけです(名前の一部だけが一致する記録や、成功していない記録はおとりです)。値は Ansible vault の本体と同じく16進で書かれていて、16進を戻すと Base64 の文字列になります。それをさらに戻すとフラグです。
CI/CDセキュリティ - GitHub Actions 脆弱性
`/challenge/repo/.github/workflows/` にある20個の GitHub Actions ワークフローを監査します。多くのステップに `# audit-ticket: KINOCO{...}` というコメントが付いています。次の3条件をすべて満たす「pwn request」脆弱性を持つワークフローは1つだけで、そのステップの audit-ticket がフラグです。(1) トリガーが `pull_request_target`。(2) あるジョブが、チェックアウトの `ref:` に `github.event.pull_request.head.sha` や `head.ref` を指定して PR の head を明示的にチェックアウトしている。(3) その同じジョブが `secrets.*` を参照している。どれか1つでも欠けるワークフローはおとりです。
CloudTrailログから不正アクセスを検出せよ
AWS CloudTrail の書き出し `/challenge/cloudtrail.json` を解析し、盗まれたアクセスキーによる不正アクセスと、シークレットの持ち出しを追ってください。 攻撃者は偵察・権限昇格・新しいアクセスキーの作成のあと、読み出したシークレットを、その新しいキーで外部バケットへ S3 PutObject として分割して送りました(CloudTrail は GetSecretValue の値を記録しません)。オブジェクトキーは `<prefix>/<連番4桁>-<16進>.part` で、16進は6バイトずつの暗号文です。連番順に連結したバイト列は、SHA-256("<新しいアクセスキーID>:<カウンタ>")(カウンタは0から始まる10進の文字列)を順に連結した鍵ストリームと XOR されています。 許可済みのレッドチーム演習(送信元 192.0.2.50)も同じ手口で記録されています。演習ではなく、実際のインシデントで持ち出されたデータを復元してください。 提供ファイル: cloudtrail.json
Dockerイメージレイヤーから秘密を抽出せよ
`/challenge/image/` は `docker save`(OCI レイアウト)の書き出しを展開したものです。レイヤーは `blobs/sha256/` にダイジェスト名の gzip 圧縮した tar として置かれ、順番は `manifest.json` から読みます。 `/root/.aws/credentials` は複数のレイヤーで書き換えられ、クリーンアップのレイヤーで whiteout(削除マーカー)され、その後に別の値で作り直されています。最終ビューからは消えている、whiteout で削除された時点の credentials を回収し、その `aws_secret_access_key` の値を答えてください。ほかの秘密ファイルや、削除前後の別の値はおとりです。
Infrastructure as Code - Terraform セキュリティ
Terraform providerを初期化せず、生成済みの terraform/terraform.tfstate を解析してください。outputs の recovery_secret_arn が、復旧用シークレットの ARN を指しています。resources の aws_secretsmanager_secret_version のうち、secret_id がその ARN と完全に一致し、version_stages に AWSCURRENT を含む版が現在の値です。その secret_string(JSON を文字列にしたもの)の recovery_token を Base64 デコードするとフラグになります。
Kubernetes入門 - クラスター調査
実Kubernetesクラスターへ接続せず、artifacts/kubernetes/ の2つのスナップショット(pod-snapshot.yaml と secret-snapshot.yaml)を調べてください。namespace security-lab の Pod suspicious-audit-pod は、環境変数 AUDIT_TOKEN を Secret から読んでいます。その secretKeyRef が指す Secret(同じ namespace で同じ名前)の、指定されたキーの値を Base64 デコードするとフラグになります。別の namespace の同名の Pod や Secret、似た名前の Secret、同じ Secret の別のキーはおとりです。
Linux-カーネルモジュール. 脆弱なドライバでroot権限を得よ
このチャレンジは、脆弱なキャラクタデバイスドライバを安全なユーザー空間シミュレーションとして解析します。実際のカーネルモジュールはロードされません。root デーモンがドライバを /run/vulnerable.sock として公開し、あなたは非特権ユーザー challenger(uid 1000)として接続します。提供されたドライバソース vulnerable.c を読み、read/write の境界不備を突いて自分の資格情報を uid 0 に書き換え、GETFLAG でフラグを取得してください。
Linux-バッファオーバーフロー. gets()の脆弱性を突け
SUIDが付与された脆弱なCバイナリが用意されています。保護機構が無効化されたこのプログラムのバッファオーバーフローを突いて、隠された関数へ制御を移してください。
Python上級 - カスタムVMバイトコードの実行
program.kvmは独自の4レジスタVM用バイトコードです。READMEの命令仕様を基にPythonでインタプリタを実装し、VMの出力を復元してください。
TLS暗号化されたHTTPS通信を復号せよ
`~/evidence/` に、あるクライアント PC の HTTPS 通信を記録したキャプチャ `traffic.pcap`(libpcap 形式)と、ブラウザが書き出した TLS の鍵ログ `sslkeylog.txt`(NSS 形式)があります。鍵ログには、このキャプチャに含まれない通信の行も混ざっています。キャプチャ内の TLS 1.2 の通信を復号し、外部へ持ち出された情報(HTTP の POST の内容)からフラグを取得してください。通信は実際に傍受したものではなく、演習のために作った記録です。python3(cryptography)と openssl が使えます。
Web-26. User Profile Managerのプロトタイプ汚染
このNode.js/Express製アプリではログイン中のユーザーが自分のプロフィールを更新できます。更新処理に使われている再帰的なマージ関数が特殊なキーをきちんと除外しているか確認してみましょう。
Web-27. GraphQL APIのイントロスペクション漏洩
このGraphQL APIはUserオブジェクトのスキーマを公開しており、イントロスペクションが有効になっています。公式には案内されていないクエリやフィールドが存在しないか調べてみましょう。
Web-28. OAuth認可コードの横取り
このOAuth 2.0認可プロバイダーはログインフローを提供していますが、redirect_uriの検証が甘い可能性があります。認可コードを横取りして管理者権限のアクセストークンを得られないか確認してみましょう。
Web-29. MongoDBログインフォームのNoSQLインジェクション
このログインポータルはMongoDBを使っており、ユーザー名・パスワードをJSONとしてそのままクエリに組み込んでいます。パスワードを知らなくても管理者としてログインできないか確認してみましょう。
Web-30. KinoVaultの安全でないデシリアライズ
レガシーなバックアップシステム「KinoVault」は、ユーザーセッションをPythonのpickleでシリアライズしてCookieに保存していると噂されています。Cookieの形式を解析し、悪意あるpickleペイロードで権限を昇格できないか調べてみましょう。
カスタムツール開発 - Webディレクトリスキャナー
ライブWebサイトを走査せず、ローカル生成された artifacts/scanner/directory-report.ndjson を解析してください。スキャナーは同じサイトを複数回(run)走査しています。最新の run で、path がちょうど /secret_admin/backup、status が 200 の記録だけが本物です。その body_b64 は gzip で圧縮した応答本文を Base64 にしたもので、戻すとフラグになります。
ネットワークトンネリング - SSH ポートフォワーディング
単一コンテナ内でSSHローカルポートフォワーディングを練習します。SSHは127.0.0.1:22、内部サービスは/run/tunnel/database.sockにあります。内部ソケットはローカルのプレイヤーから直接アクセスできません。転送専用ユーザーtunnel(パスワードpassword123)でSSH認証し、127.0.0.1:8888へ転送して応答を取得してください。外部ホストや実データベースは使用しません。
バイナリ修復 - ファームウェアヘッダーとCRC32
firmware.bin の先頭4バイトを KINO に修復し、byte 12以降の CRC32 をリトルエンディアンで byte 8-11 に書き戻してください。修正ファイルを challenge.py に渡すと起動時注入 FLAG が表示されます。
プログラミング - C2通信の解析
起動のたびに乱数で作られた合成ログ beacon.log を解析します(ネットワーク接続は不要です)。複数の端末(セッション)の通信が時刻順に混ざっています。各セッションは最初の hello で nonce を送り、そのセッションの鍵は SHA-256(b"beacon-v1" + bytes.fromhex(nonce)) の先頭8バイトです。pulse の payload を seq の順につなぐと Base64 になり、それを復号して鍵で繰り返し XOR すると `task=... code=...` のような `キー=値` の平文になります(通信が途切れると同じ seq が再送されます)。task がちょうど `exfil` のセッションの code の値(16文字)が答えです。似た名前のタスクと取り違えないでください。答えを `python3 challenge.py '<答え>'` に渡すと、正解のときだけフラグが表示されます。
プログラミング - バッファオーバーフロー・クラッシュ解析
起動のたびに乱数で作られたクラッシュ報告 crash_01.txt から crash_06.txt を解析します(実行可能なコードは含まれません)。各報告には、送った入力そのもの(input:)とクラッシュ時の命令ポインタ(32ビットは eip、64ビットは rip)が書かれています。入力には同じ4文字が2度現れない巡回パターン(英小文字)が使われ、先頭にコマンド名などの前置きが付くことがあります。signal が SIGSEGV で、かつ命令ポインタの値が送った入力のバイト列で上書きされている報告だけを対象に、その値(メモリ上ではリトルエンディアン)をバイト列に直し、入力の先頭を 0 としたとき何バイト目から始まるかを求めます。対象の報告のオフセットを報告番号の順に `-` でつないだもの(例: `52-140-88-203`)が答えです。答えを `python3 challenge.py '<答え>'` に渡すと、正解のときだけフラグが表示されます。
プログラミング - ファジング結果の解析
起動のたびに乱数で作られたファジング結果のログ fuzz-results.log を解析します(入力は保存されているだけで、何も実行されません)。1行が1ケースで、`case=<6桁16進> result=<OK|TIMEOUT|CRASH> signal=<SIGSEGV|SIGABRT|-> stack=<8桁16進|-> input=<16進>` の形です。`signal=SIGSEGV` のクラッシュだけを対象に、stack(同じ stack は同じバグ)ごとにまとめ、入力(input の16進をバイトに直した長さ)が最も短いケースを選びます(同じ長さなら case の値が小さい方)。選んだケースの case を stack の値の昇順に `-` でつないだもの(例: `1a2b3c-4d5e6f-...`)が答えです。答えを `python3 challenge.py '<答え>'` に渡すと、正解のときだけフラグが表示されます。
プログラミング - ブロックチェーンイベントの再構築
/challenge/blocks.json は、コンテナの起動のたびに乱数で作り直される、オフラインの開発用チェーンのブロック一覧です(順不同。フォークでできた、正規チェーンに入らない孤立ブロックを含みます)。height が最も大きいブロックから parent_hash をたどった正規チェーンのブロックにある、status が 1 の取引の Fragment イベントを (height, log_index) の順に並べ、data(0x の後ろ)をつないで16進デコードしたトークン(英小文字と数字)を求め、python3 challenge.py '<トークン>' に渡してください。正しいときだけフラグが表示されます。