From e554f2e7e93ea1bbf961dfe822cac1e961923874 Mon Sep 17 00:00:00 2001 From: yhc <1964366186@qq.com> Date: Mon, 10 Aug 2026 19:52:56 +0800 Subject: [PATCH] ci: add strict case-contract test for examples/ctf-demo (P1-3) - Refactor examples/ctf-demo to satisfy the review_case.py contract: split evidence/E-001-E-003.md into per-record E-001/E-002/E-003.md with ### E-xxx headings and severity/status/repro_command fields - Add evidence/checksec-output.txt artifact with matching content_hash so --verify-hashes has a real object to verify - Convert report.md finding/path sections to structured F-01/P-01 blocks - New case-contract CI job runs review_case.py --verify-hashes --strict on examples/ctf-demo; local result: PASS (0 errors, 0 warnings) --- .github/workflows/ci.yml | 9 ++++ examples/ctf-demo/evidence/E-001-E-003.md | 42 ------------------- examples/ctf-demo/evidence/E-001.md | 19 +++++++++ examples/ctf-demo/evidence/E-002.md | 15 +++++++ examples/ctf-demo/evidence/E-003.md | 14 +++++++ .../ctf-demo/evidence/checksec-output.txt | 5 +++ examples/ctf-demo/report/report.md | 29 +++++++++++-- 7 files changed, 88 insertions(+), 45 deletions(-) delete mode 100644 examples/ctf-demo/evidence/E-001-E-003.md create mode 100644 examples/ctf-demo/evidence/E-001.md create mode 100644 examples/ctf-demo/evidence/E-002.md create mode 100644 examples/ctf-demo/evidence/E-003.md create mode 100644 examples/ctf-demo/evidence/checksec-output.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a9d2d2..6ba590e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,6 +158,15 @@ jobs: shell: pwsh run: ./skills/scripts/scan-leaks.ps1 -Path skills/field-journal + case-contract: + name: case contract test (ctf-demo) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Review examples/ctf-demo under strict contract + shell: bash + run: python3 skills/case-review/scripts/review_case.py examples/ctf-demo --verify-hashes --strict + version-check: name: version consistency runs-on: ubuntu-latest diff --git a/examples/ctf-demo/evidence/E-001-E-003.md b/examples/ctf-demo/evidence/E-001-E-003.md deleted file mode 100644 index 770078f..0000000 --- a/examples/ctf-demo/evidence/E-001-E-003.md +++ /dev/null @@ -1,42 +0,0 @@ -# Evidence E-001 — Binary triage - -- **id**: E-001 -- **date**: 2026-08-02T00:15:00 -- **title**: pwn1 ELF triage (checksec) -- **finding**: ELF 64-bit x86-64, no PIE, NX enabled, partial RELRO, no canary on main -- **repro_command**: `file ./pwn1 && checksec --file=./pwn1` -- **output**: - ```text - ./pwn1: ELF 64-bit LSB executable, x86-64, dynamically linked - RELRO: Partial RELRO - Stack: No canary found - NX: NX enabled - PIE: PIE disabled - ``` -- **path**: Evidence → Finding → Path (skills/ops/evidence-finding-path.md) - ---- - -# Evidence E-002 — Overflow confirmation - -- **id**: E-002 -- **date**: 2026-08-02T00:40:00 -- **title**: gets() stack overflow in main -- **finding**: main reads into buf[0x40] via gets(); return offset 0x48; no canary -- **repro_command**: `python3 -c "print('A'*0x48 + 'B'*8)" | ./pwn1` (segfault at 0x4242424242424242) -- **output**: - ```text - Program received signal SIGSEGV, Segmentation fault. - RIP=0x4242424242424242 - ``` - ---- - -# Evidence E-003 — Flag captured - -- **id**: E-003 -- **date**: 2026-08-02T01:10:00 -- **title**: remote exploit success -- **finding**: ret2win payload works remotely, flag captured -- **repro_command**: `python3 exploit.py REMOTE` -- **output**: `ctf{example_flag_do_not_use}` diff --git a/examples/ctf-demo/evidence/E-001.md b/examples/ctf-demo/evidence/E-001.md new file mode 100644 index 0000000..1e440f5 --- /dev/null +++ b/examples/ctf-demo/evidence/E-001.md @@ -0,0 +1,19 @@ +### E-001 + +- title: pwn1 ELF triage (checksec) +- severity: info +- status: observed +- observed_at: 2026-08-02T00:15:00 +- source_type: command +- source_ref: recon phase +- repro_command: | + file ./pwn1 && checksec --file=./pwn1 +- raw_excerpt: | + ./pwn1: ELF 64-bit LSB executable, x86-64, dynamically linked + RELRO: Partial RELRO + Stack: No canary found + NX: NX enabled + PIE: PIE disabled +- artifact_path: evidence/checksec-output.txt +- content_hash: 395aa1546e0e22873e10334c4225097e9111f1b8fb5dcd1a2a3b7640d6fcc6ed +- linked_workitem: WI-002 diff --git a/examples/ctf-demo/evidence/E-002.md b/examples/ctf-demo/evidence/E-002.md new file mode 100644 index 0000000..f0b6c92 --- /dev/null +++ b/examples/ctf-demo/evidence/E-002.md @@ -0,0 +1,15 @@ +### E-002 + +- title: gets() stack overflow in main +- severity: info +- status: observed +- observed_at: 2026-08-02T00:40:00 +- source_type: command +- source_ref: static analysis +- repro_command: | + python3 -c "print('A'*0x48 + 'B'*8)" | ./pwn1 +- raw_excerpt: | + Program received signal SIGSEGV, Segmentation fault. + RIP=0x4242424242424242 +- content_hash: n/a +- linked_workitem: WI-003 diff --git a/examples/ctf-demo/evidence/E-003.md b/examples/ctf-demo/evidence/E-003.md new file mode 100644 index 0000000..bf6c3d5 --- /dev/null +++ b/examples/ctf-demo/evidence/E-003.md @@ -0,0 +1,14 @@ +### E-003 + +- title: remote exploit success +- severity: high +- status: validated +- observed_at: 2026-08-02T01:10:00 +- source_type: command +- source_ref: exploit phase +- repro_command: | + python3 exploit.py REMOTE +- raw_excerpt: | + ctf{{example_flag_do_not_use}} +- content_hash: n/a +- linked_workitem: WI-004 diff --git a/examples/ctf-demo/evidence/checksec-output.txt b/examples/ctf-demo/evidence/checksec-output.txt new file mode 100644 index 0000000..6b6593f --- /dev/null +++ b/examples/ctf-demo/evidence/checksec-output.txt @@ -0,0 +1,5 @@ +./pwn1: ELF 64-bit LSB executable, x86-64, dynamically linked +RELRO: Partial RELRO +Stack: No canary found +NX: NX enabled +PIE: PIE disabled diff --git a/examples/ctf-demo/report/report.md b/examples/ctf-demo/report/report.md index 684c2c3..eae5fc8 100644 --- a/examples/ctf-demo/report/report.md +++ b/examples/ctf-demo/report/report.md @@ -22,12 +22,35 @@ pwn1 为无 PIE/无 canary 的 64 位 ELF,main 使用 `gets()` 读取 0x40 缓 ## 4. 发现 -| # | 严重度 | 描述 | 证据 | -|---|--------|------|------| -| F-01 | High (CTF) | gets() 栈溢出,ret 偏移 0x48,可 ROP/ret2win | E-001, E-002, E-003 | +### F-01 + +- title: gets() stack overflow in main (ret2win) +- severity: high +- status: validated +- confidence: high +- evidence_ids: [E-001, E-002, E-003] +- location: pwn1:main — gets() into buf[0x40], return offset 0x48, no canary +- impact: Remote code execution as the pwn1 process user; flag disclosure in CTF context. +- repro_steps: + 1. Triage the binary (E-001) + 2. Confirm the overflow offset with a cyclic/crash test (E-002) + 3. Send the ret2win payload against the remote service (E-003) +- remediation: Replace gets() with fgets/read; enable canary, PIE and full RELRO; rely on ASLR. ## 5. 攻击路径(Evidence → Finding → Path) +### P-01 + +- title: pwn1 ret2win solve path +- path_type: solve +- start: challenge binary download +- goal: flag capture +- steps: + 1. action: download and triage pwn1 — evidence: E-001 — finding: F-01 | none + 2. action: decompile main and confirm gets() overflow — evidence: E-002 — finding: F-01 + 3. action: craft ret2win payload and verify remotely — evidence: E-003 — finding: F-01 +- residual_risks: none (isolated CTF lab) + ```mermaid graph LR A[下载 pwn1] --> B[checksec 侦察]