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)
This commit is contained in:
yhc
2026-08-10 19:52:56 +08:00
parent 91d737b775
commit e554f2e7e9
7 changed files with 88 additions and 45 deletions
+9
View File
@@ -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
-42
View File
@@ -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}`
+19
View File
@@ -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
+15
View File
@@ -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
+14
View File
@@ -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
@@ -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
+26 -3
View File
@@ -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 侦察]