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:
@@ -158,6 +158,15 @@ jobs:
|
|||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: ./skills/scripts/scan-leaks.ps1 -Path skills/field-journal
|
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:
|
version-check:
|
||||||
name: version consistency
|
name: version consistency
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -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}`
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -22,12 +22,35 @@ pwn1 为无 PIE/无 canary 的 64 位 ELF,main 使用 `gets()` 读取 0x40 缓
|
|||||||
|
|
||||||
## 4. 发现
|
## 4. 发现
|
||||||
|
|
||||||
| # | 严重度 | 描述 | 证据 |
|
### F-01
|
||||||
|---|--------|------|------|
|
|
||||||
| F-01 | High (CTF) | gets() 栈溢出,ret 偏移 0x48,可 ROP/ret2win | E-001, E-002, E-003 |
|
- 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)
|
## 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
|
```mermaid
|
||||||
graph LR
|
graph LR
|
||||||
A[下载 pwn1] --> B[checksec 侦察]
|
A[下载 pwn1] --> B[checksec 侦察]
|
||||||
|
|||||||
Reference in New Issue
Block a user