litclaude-ai 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +155 -0
- package/LICENSE +21 -0
- package/README.md +369 -0
- package/README_ko-KR.md +374 -0
- package/RELEASE_CHECKLIST.md +165 -0
- package/bin/litclaude-ai.js +643 -0
- package/cover.png +0 -0
- package/docs/agents.md +67 -0
- package/docs/hooks.md +134 -0
- package/docs/lsp.md +40 -0
- package/docs/migration.md +209 -0
- package/docs/workflow-compatibility-audit.md +119 -0
- package/generate_cover.py +123 -0
- package/package.json +48 -0
- package/plugins/litclaude/.claude-plugin/plugin.json +25 -0
- package/plugins/litclaude/.lsp.json +13 -0
- package/plugins/litclaude/.mcp.json +9 -0
- package/plugins/litclaude/agents/boulder-executor.md +12 -0
- package/plugins/litclaude/agents/librarian-researcher.md +15 -0
- package/plugins/litclaude/agents/oracle-verifier.md +16 -0
- package/plugins/litclaude/agents/prometheus-planner.md +13 -0
- package/plugins/litclaude/agents/qa-runner.md +16 -0
- package/plugins/litclaude/agents/quality-reviewer.md +17 -0
- package/plugins/litclaude/bin/litclaude-hook.js +110 -0
- package/plugins/litclaude/bin/litclaude-hud.js +271 -0
- package/plugins/litclaude/bin/litclaude-lsp-doctor.js +15 -0
- package/plugins/litclaude/bin/litclaude-mcp.js +70 -0
- package/plugins/litclaude/commands/deep-interview.md +21 -0
- package/plugins/litclaude/commands/dynamic-workflow.md +36 -0
- package/plugins/litclaude/commands/lit-loop.md +40 -0
- package/plugins/litclaude/commands/lit-plan.md +35 -0
- package/plugins/litclaude/commands/litgoal.md +30 -0
- package/plugins/litclaude/commands/review-work.md +35 -0
- package/plugins/litclaude/commands/start-work.md +36 -0
- package/plugins/litclaude/hooks/hooks.json +54 -0
- package/plugins/litclaude/lib/context-pressure.mjs +25 -0
- package/plugins/litclaude/lib/hud-accent-palette.mjs +58 -0
- package/plugins/litclaude/lib/litgoal/cli.mjs +266 -0
- package/plugins/litclaude/lib/litgoal/ledger.mjs +16 -0
- package/plugins/litclaude/lib/litgoal/paths.mjs +7 -0
- package/plugins/litclaude/lib/litgoal/state.mjs +67 -0
- package/plugins/litclaude/lib/mutated-file-paths.mjs +63 -0
- package/plugins/litclaude/lib/start-work-continuation.mjs +99 -0
- package/plugins/litclaude/lib/workflow-check.mjs +83 -0
- package/plugins/litclaude/skills/ai-slop-remover/SKILL.md +142 -0
- package/plugins/litclaude/skills/comment-checker/SKILL.md +55 -0
- package/plugins/litclaude/skills/debugging/SKILL.md +70 -0
- package/plugins/litclaude/skills/debugging/references/methodology/00-setup.md +108 -0
- package/plugins/litclaude/skills/debugging/references/methodology/02-investigate.md +126 -0
- package/plugins/litclaude/skills/debugging/references/methodology/04-oracle-triple.md +106 -0
- package/plugins/litclaude/skills/debugging/references/methodology/05-escalate.md +69 -0
- package/plugins/litclaude/skills/debugging/references/methodology/06-fix.md +116 -0
- package/plugins/litclaude/skills/debugging/references/methodology/08-qa.md +94 -0
- package/plugins/litclaude/skills/debugging/references/methodology/09-cleanup.md +164 -0
- package/plugins/litclaude/skills/debugging/references/methodology/partial-runtime-evidence.md +228 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/go.md +252 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/native-binary.md +484 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/node.md +260 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/python.md +248 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/rust.md +234 -0
- package/plugins/litclaude/skills/debugging/references/tools/ghidra.md +212 -0
- package/plugins/litclaude/skills/debugging/references/tools/playwright-cli.md +194 -0
- package/plugins/litclaude/skills/debugging/references/tools/pwndbg.md +263 -0
- package/plugins/litclaude/skills/debugging/references/tools/pwntools.md +265 -0
- package/plugins/litclaude/skills/deep-interview/SKILL.md +323 -0
- package/plugins/litclaude/skills/deep-interview/scripts/render_progress.py +193 -0
- package/plugins/litclaude/skills/frontend-ui-ux/SKILL.md +62 -0
- package/plugins/litclaude/skills/lit-loop/SKILL.md +144 -0
- package/plugins/litclaude/skills/lit-plan/SKILL.md +125 -0
- package/plugins/litclaude/skills/litgoal/SKILL.md +219 -0
- package/plugins/litclaude/skills/lsp/SKILL.md +63 -0
- package/plugins/litclaude/skills/programming/SKILL.md +106 -0
- package/plugins/litclaude/skills/programming/references/go/README.md +90 -0
- package/plugins/litclaude/skills/programming/references/go/backend-stack.md +641 -0
- package/plugins/litclaude/skills/programming/references/go/bootstrap.md +328 -0
- package/plugins/litclaude/skills/programming/references/go/bubbletea-v2.md +360 -0
- package/plugins/litclaude/skills/programming/references/go/cobra-stack.md +468 -0
- package/plugins/litclaude/skills/programming/references/go/concurrency.md +362 -0
- package/plugins/litclaude/skills/programming/references/go/data-modeling.md +329 -0
- package/plugins/litclaude/skills/programming/references/go/error-handling.md +359 -0
- package/plugins/litclaude/skills/programming/references/go/golangci-strict.md +236 -0
- package/plugins/litclaude/skills/programming/references/go/grpc-connect.md +375 -0
- package/plugins/litclaude/skills/programming/references/go/libraries.md +337 -0
- package/plugins/litclaude/skills/programming/references/go/one-liners.md +202 -0
- package/plugins/litclaude/skills/programming/references/go/sqlc-pgx.md +471 -0
- package/plugins/litclaude/skills/programming/references/go/testing.md +467 -0
- package/plugins/litclaude/skills/programming/references/go/type-patterns.md +298 -0
- package/plugins/litclaude/skills/programming/references/python/README.md +314 -0
- package/plugins/litclaude/skills/programming/references/python/async-anyio.md +442 -0
- package/plugins/litclaude/skills/programming/references/python/data-modeling.md +233 -0
- package/plugins/litclaude/skills/programming/references/python/data-processing.md +133 -0
- package/plugins/litclaude/skills/programming/references/python/error-handling.md +218 -0
- package/plugins/litclaude/skills/programming/references/python/fastapi-stack.md +316 -0
- package/plugins/litclaude/skills/programming/references/python/httpx2-optimization.md +360 -0
- package/plugins/litclaude/skills/programming/references/python/libraries.md +307 -0
- package/plugins/litclaude/skills/programming/references/python/one-liners.md +268 -0
- package/plugins/litclaude/skills/programming/references/python/orjson-stack.md +378 -0
- package/plugins/litclaude/skills/programming/references/python/pydantic-ai.md +285 -0
- package/plugins/litclaude/skills/programming/references/python/pyproject-strict.md +232 -0
- package/plugins/litclaude/skills/programming/references/python/textual-tui.md +201 -0
- package/plugins/litclaude/skills/programming/references/python/type-patterns.md +176 -0
- package/plugins/litclaude/skills/programming/references/rust/README.md +317 -0
- package/plugins/litclaude/skills/programming/references/rust/async-tokio.md +299 -0
- package/plugins/litclaude/skills/programming/references/rust/axum-stack.md +467 -0
- package/plugins/litclaude/skills/programming/references/rust/cargo-strict.md +317 -0
- package/plugins/litclaude/skills/programming/references/rust/clap-stack.md +409 -0
- package/plugins/litclaude/skills/programming/references/rust/concurrency.md +375 -0
- package/plugins/litclaude/skills/programming/references/rust/libraries.md +439 -0
- package/plugins/litclaude/skills/programming/references/rust/one-liners.md +291 -0
- package/plugins/litclaude/skills/programming/references/rust/proptest-insta.md +429 -0
- package/plugins/litclaude/skills/programming/references/rust/type-state.md +354 -0
- package/plugins/litclaude/skills/programming/references/rust/unsafe-discipline.md +250 -0
- package/plugins/litclaude/skills/programming/references/rust/zero-cost-safety.md +527 -0
- package/plugins/litclaude/skills/programming/references/rust-ub/README.md +289 -0
- package/plugins/litclaude/skills/programming/references/rust-ub/miri-sanitizers-loom.md +411 -0
- package/plugins/litclaude/skills/programming/references/rust-ub/ub-taxonomy.md +269 -0
- package/plugins/litclaude/skills/programming/references/typescript/README.md +195 -0
- package/plugins/litclaude/skills/programming/references/typescript/backend-hono.md +672 -0
- package/plugins/litclaude/skills/programming/references/typescript/bootstrap.md +199 -0
- package/plugins/litclaude/skills/programming/references/typescript/data-modeling.md +202 -0
- package/plugins/litclaude/skills/programming/references/typescript/error-handling.md +169 -0
- package/plugins/litclaude/skills/programming/references/typescript/tsconfig-strict.md +152 -0
- package/plugins/litclaude/skills/programming/references/typescript/type-patterns.md +196 -0
- package/plugins/litclaude/skills/programming/scripts/go/check-no-excuse-rules.sh +173 -0
- package/plugins/litclaude/skills/programming/scripts/go/new-project.py +138 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/.editorconfig +13 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/.golangci.yml +95 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/AGENTS.md.tmpl +24 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/README.md.tmpl +12 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/Taskfile.yml +40 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/ci.yml +37 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/config.go +24 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/gitignore +15 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/main.go.tmpl +22 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/run.go +15 -0
- package/plugins/litclaude/skills/programming/scripts/python/check-no-excuse-rules.py +687 -0
- package/plugins/litclaude/skills/programming/scripts/python/new-project.py +172 -0
- package/plugins/litclaude/skills/programming/scripts/python/new-script.py +116 -0
- package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.py +296 -0
- package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.sh +158 -0
- package/plugins/litclaude/skills/programming/scripts/rust/new-project.py +175 -0
- package/plugins/litclaude/skills/programming/scripts/typescript/check-no-excuse-rules.ts +282 -0
- package/plugins/litclaude/skills/programming/scripts/typescript/new-project.ts +177 -0
- package/plugins/litclaude/skills/refactor/SKILL.md +73 -0
- package/plugins/litclaude/skills/remove-ai-slops/SKILL.md +52 -0
- package/plugins/litclaude/skills/review-work/SKILL.md +331 -0
- package/plugins/litclaude/skills/rules/SKILL.md +66 -0
- package/plugins/litclaude/skills/start-work/SKILL.md +132 -0
- package/scripts/audit-plan-checkboxes.mjs +37 -0
- package/scripts/doctor.mjs +41 -0
- package/scripts/inspect-agent-tools.mjs +27 -0
- package/scripts/postinstall.mjs +50 -0
- package/scripts/qa-claude-plugin-smoke.sh +60 -0
- package/scripts/qa-portable-install.sh +136 -0
- package/scripts/validate-plugin.mjs +72 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# pwndbg — GDB With the Useful Views Always On
|
|
2
|
+
|
|
3
|
+
**https://github.com/pwndbg/pwndbg**
|
|
4
|
+
|
|
5
|
+
pwndbg is a GDB plugin that turns GDB into something humans can actually use for binary debugging. It's strictly a superset of plain GDB — every vanilla GDB command still works, and pwndbg adds views and commands that make you productive.
|
|
6
|
+
|
|
7
|
+
**If you'd reach for plain `gdb`, reach for pwndbg instead.** The only reason not to is if pwndbg isn't installed on the machine, and that's a 2-minute fix.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# macOS
|
|
15
|
+
brew install pwndbg
|
|
16
|
+
# Or from source:
|
|
17
|
+
git clone https://github.com/pwndbg/pwndbg
|
|
18
|
+
cd pwndbg && ./setup.sh
|
|
19
|
+
|
|
20
|
+
# Linux
|
|
21
|
+
# Most distros: apt/dnf/pacman install pwndbg (check availability)
|
|
22
|
+
# Or the same git + ./setup.sh
|
|
23
|
+
|
|
24
|
+
# Verify
|
|
25
|
+
gdb --version
|
|
26
|
+
gdb ./any-binary
|
|
27
|
+
# At gdb prompt, you should see pwndbg banner + colorful context view
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Once installed, pwndbg auto-loads every time you start `gdb`. You don't source anything manually.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## The `context` view — the one feature that changes everything
|
|
35
|
+
|
|
36
|
+
Plain GDB: you run `info registers`, then `bt`, then `x/10xw $rsp`, then `disas`. Four commands to see what's going on.
|
|
37
|
+
|
|
38
|
+
pwndbg: `context` (or it auto-shows at every break). One command. Everything on screen:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
──── registers ────
|
|
42
|
+
RAX 0x0
|
|
43
|
+
RBX 0x7ffffffde158
|
|
44
|
+
RCX 0x7fffff7abf10
|
|
45
|
+
...
|
|
46
|
+
──── disasm ────
|
|
47
|
+
► 0x401234 mov rdi, rax
|
|
48
|
+
0x401237 call 0x401190
|
|
49
|
+
...
|
|
50
|
+
──── stack ────
|
|
51
|
+
00:0000│ rsp 0x7ffffffde0a0 → 0x7fffff7c4000
|
|
52
|
+
01:0008│ 0x7ffffffde0a8 → 0x0
|
|
53
|
+
...
|
|
54
|
+
──── backtrace ────
|
|
55
|
+
► f 0 0x401234 parse_input+0x3c
|
|
56
|
+
f 1 0x401180 main+0x120
|
|
57
|
+
f 2 0x7fffff7a5083 __libc_start_main+0xf3
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
You always know where you are, what the CPU state is, what's on the stack, and how you got here. This is why pwndbg is the default.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Launch recipes
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Debug an existing binary
|
|
68
|
+
gdb ./target
|
|
69
|
+
|
|
70
|
+
# With args
|
|
71
|
+
gdb --args ./target arg1 arg2
|
|
72
|
+
|
|
73
|
+
# Attach to a running process
|
|
74
|
+
gdb -p $(pgrep target)
|
|
75
|
+
|
|
76
|
+
# With a core dump
|
|
77
|
+
gdb ./target ./core
|
|
78
|
+
|
|
79
|
+
# Headless / remote (for automation or IDE attach)
|
|
80
|
+
gdbserver :2345 ./target # on the target box
|
|
81
|
+
gdb ./target # on your box
|
|
82
|
+
(gdb) target remote <host>:2345
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
At the pwndbg prompt:
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Essential commands (pwndbg additions)
|
|
90
|
+
|
|
91
|
+
### Layout / view
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
context # reprint the context view (usually auto)
|
|
95
|
+
context regs stack # only show registers + stack sections
|
|
96
|
+
tel $rsp 20 # telescope — walk pointers at $rsp for 20 slots (KEY COMMAND)
|
|
97
|
+
tel $rdi 10 # walk pointers at $rdi (e.g. to dump a struct)
|
|
98
|
+
stack 20 # 20 entries of stack
|
|
99
|
+
vmmap # virtual memory map of the process
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**`telescope` is pwndbg's killer command.** Given an address, it walks pointers recursively:
|
|
103
|
+
```
|
|
104
|
+
00:0000│ 0x7ffd... → 0x601010 (heap) → 0x2a (unknown, i.e. a number 42)
|
|
105
|
+
01:0008│ 0x7ffd... → 0x7fff... (stack) → 'hello world'
|
|
106
|
+
```
|
|
107
|
+
This single view resolves 80% of "what is at this address" questions.
|
|
108
|
+
|
|
109
|
+
### Heap debugging
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
heap # overview of chunks
|
|
113
|
+
bins # tcache / fastbin / unsorted / smallbin / largebin state
|
|
114
|
+
malloc_chunk <addr> # inspect a specific chunk
|
|
115
|
+
find_fake_fast <addr> # (exploit context) find fake-fast overlap candidates
|
|
116
|
+
vis_heap_chunks # visualize heap layout
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
For use-after-free / double-free / heap overflow hypotheses, `heap` + `bins` is usually sufficient to see the corruption.
|
|
120
|
+
|
|
121
|
+
### Exploitation-adjacent (useful for bug understanding too)
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
checksec # NX, PIE, RELRO, canary status
|
|
125
|
+
rop --grep 'pop rdi' # find ROP gadgets
|
|
126
|
+
nx # step over (aliased nicely)
|
|
127
|
+
ni # step over single instruction
|
|
128
|
+
si # step into single instruction
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Search
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
search -t byte 0x41 # find byte 0x41 anywhere in memory
|
|
135
|
+
search -t string "admin" # find string
|
|
136
|
+
search -p <addr> # find pointers to <addr>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Standard GDB commands still work
|
|
142
|
+
|
|
143
|
+
pwndbg doesn't replace GDB; it augments it. Everything you know still works:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
break main # breakpoint at function
|
|
147
|
+
b *0x401234 # breakpoint at address
|
|
148
|
+
b file.c:42 # breakpoint at file:line
|
|
149
|
+
c # continue
|
|
150
|
+
n # next (source-level step over)
|
|
151
|
+
s # step (source-level step into)
|
|
152
|
+
finish # step out
|
|
153
|
+
info breakpoints # list breakpoints
|
|
154
|
+
delete <n> # delete breakpoint
|
|
155
|
+
watch <var> # break on write to variable
|
|
156
|
+
rwatch <var> # break on read
|
|
157
|
+
awatch <var> # break on access
|
|
158
|
+
p <expr> # print expression
|
|
159
|
+
p/x <expr> # print in hex
|
|
160
|
+
x/20xw <addr> # examine 20 words as hex
|
|
161
|
+
bt # backtrace
|
|
162
|
+
frame <n> # switch frame
|
|
163
|
+
info registers # registers (but `context` is better)
|
|
164
|
+
disassemble <func> # disasm a function
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Python scripting inside GDB
|
|
170
|
+
|
|
171
|
+
pwndbg exposes a full Python API. Useful for automating observations across many breakpoints:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
(gdb) python
|
|
175
|
+
import gdb
|
|
176
|
+
def on_break():
|
|
177
|
+
frame = gdb.selected_frame()
|
|
178
|
+
pc = frame.read_register('pc')
|
|
179
|
+
print(f'hit at {hex(int(pc))}')
|
|
180
|
+
# Dump args, locals, anything
|
|
181
|
+
end
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Or scripted runs from outside:
|
|
185
|
+
```bash
|
|
186
|
+
gdb -batch -ex 'source script.gdb' -ex 'run' ./target
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Common workflows by bug type
|
|
192
|
+
|
|
193
|
+
### Segfault / crash
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
gdb ./target
|
|
197
|
+
(gdb) run <args>
|
|
198
|
+
# ... crash ...
|
|
199
|
+
(gdb) context # see the crash site
|
|
200
|
+
(gdb) bt # how did we get here?
|
|
201
|
+
(gdb) info registers # what state
|
|
202
|
+
(gdb) tel $rsp 20 # what's on the stack
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### "Function returns wrong value"
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
gdb ./target
|
|
209
|
+
(gdb) break <function>
|
|
210
|
+
(gdb) run <args>
|
|
211
|
+
# At breakpoint:
|
|
212
|
+
(gdb) finish # let it run to the return
|
|
213
|
+
# pwndbg shows RAX (return value) in context
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### "Variable has unexpected value at point X"
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
gdb ./target
|
|
220
|
+
(gdb) break <point-X>
|
|
221
|
+
(gdb) run
|
|
222
|
+
# At breakpoint:
|
|
223
|
+
(gdb) p <var> # its value
|
|
224
|
+
(gdb) watch <var> # set a watchpoint — break when it changes
|
|
225
|
+
(gdb) c # continue; next stop is where it was modified
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### "Memory corruption / heap bug"
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
gdb ./target
|
|
232
|
+
(gdb) run
|
|
233
|
+
# Crash at free():
|
|
234
|
+
(gdb) heap # heap state
|
|
235
|
+
(gdb) bins # bin state — often shows corruption here
|
|
236
|
+
(gdb) vis_heap_chunks # visualize
|
|
237
|
+
(gdb) malloc_chunk <suspicious-addr>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Gotchas
|
|
243
|
+
|
|
244
|
+
- **`bt` looks weird on stripped binaries** — function names become offsets. Use Ghidra's function labels to map back (see [ghidra.md](ghidra.md)).
|
|
245
|
+
- **PIE binaries have randomized base addresses.** Addresses you see in Ghidra are unslid; addresses in pwndbg are slid. The `vmmap` command shows the base, and pwndbg's `piebase` command gives you the offset.
|
|
246
|
+
- **Optimized builds inline functions.** You'll set a breakpoint on `my_function` and it won't hit because the function was inlined. Either disable optimizations or break on callers.
|
|
247
|
+
- **Stack canaries trigger `__stack_chk_fail`.** If you see that in a backtrace, the bug caused a stack-smash; look one frame up.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Phase 9 cleanup specifics
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Kill gdb / pwndbg sessions
|
|
255
|
+
pkill -f 'gdb' || true
|
|
256
|
+
pkill -f 'gdbserver' || true
|
|
257
|
+
|
|
258
|
+
# Remove core dumps generated during session
|
|
259
|
+
rm -f ./core ./core.* ~/core.*
|
|
260
|
+
|
|
261
|
+
# Remove any scripted GDB files
|
|
262
|
+
rm -f /tmp/debug-*.gdb
|
|
263
|
+
```
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# pwntools — Scripted Binary / Network Interaction
|
|
2
|
+
|
|
3
|
+
**https://docs.pwntools.com/en/stable/ · https://github.com/Gallopsled/pwntools**
|
|
4
|
+
|
|
5
|
+
pwntools is a Python framework for building reproducible interactions with binaries and network services. Originally built for CTF exploitation, it's the correct tool for any situation where you need:
|
|
6
|
+
|
|
7
|
+
- A crafted input sent to a binary or network service, repeatably
|
|
8
|
+
- A "failing test" equivalent for a bug that only manifests with specific byte-level input
|
|
9
|
+
- A fuzz harness
|
|
10
|
+
- An exploit PoC
|
|
11
|
+
- Anything where you're tempted to use `echo ... | ./binary` but need more control than shell allows
|
|
12
|
+
|
|
13
|
+
**Use pwntools for Phase 5 reproduction of binary bugs and Phase 7 tests against binaries.**
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install pwntools
|
|
21
|
+
# Or in a venv:
|
|
22
|
+
python -m venv .venv && source .venv/bin/activate
|
|
23
|
+
pip install pwntools
|
|
24
|
+
|
|
25
|
+
# Verify
|
|
26
|
+
python -c 'from pwn import *; print("ok")'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
On some Linux distros you may need build deps: `apt install python3-dev libssl-dev`.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## The core API in five idioms
|
|
34
|
+
|
|
35
|
+
### 1. Process / Remote — the same interface
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from pwn import *
|
|
39
|
+
|
|
40
|
+
# Local process
|
|
41
|
+
p = process('./target')
|
|
42
|
+
|
|
43
|
+
# Remote service
|
|
44
|
+
p = remote('example.com', 1337)
|
|
45
|
+
|
|
46
|
+
# SSH (tunnel to a remote process)
|
|
47
|
+
shell = ssh('user', 'host', password='...')
|
|
48
|
+
p = shell.process('./target', cwd='/tmp')
|
|
49
|
+
|
|
50
|
+
# Same methods on all of the above — this is the value proposition
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. I/O — the only five methods you need
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
p.send(b'data') # send bytes
|
|
57
|
+
p.sendline(b'data') # send bytes + \n
|
|
58
|
+
p.recv(n) # receive up to n bytes
|
|
59
|
+
p.recvuntil(b'> ') # receive until pattern (blocks)
|
|
60
|
+
p.recvline() # receive until \n
|
|
61
|
+
p.interactive() # hand control to your terminal (for manual exploration)
|
|
62
|
+
|
|
63
|
+
# Combined
|
|
64
|
+
p.sendlineafter(b'prompt> ', b'payload')
|
|
65
|
+
p.sendafter(b'key:', key)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Timeouts:
|
|
69
|
+
```python
|
|
70
|
+
try:
|
|
71
|
+
data = p.recvuntil(b'done', timeout=5)
|
|
72
|
+
except pwnlib.exception.EOFError:
|
|
73
|
+
print('process died')
|
|
74
|
+
except TimeoutError:
|
|
75
|
+
print('no response in 5s')
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 3. context — set arch/OS once, tools align
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
context.binary = elf = ELF('./target') # auto-sets arch/os/endianness
|
|
82
|
+
# or explicitly:
|
|
83
|
+
context.update(arch='amd64', os='linux', endian='little', bits=64)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
After setting context, helpers like `asm()`, `disasm()`, `cyclic()`, and `ROP()` produce correct output for that target automatically.
|
|
87
|
+
|
|
88
|
+
### 4. ELF — parse without reverse-engineering by hand
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
elf = ELF('./target')
|
|
92
|
+
|
|
93
|
+
elf.symbols['main'] # address of main
|
|
94
|
+
elf.plt['printf'] # address in PLT (dynamic linkage)
|
|
95
|
+
elf.got['printf'] # GOT entry
|
|
96
|
+
elf.address = 0x555555554000 # set base for PIE binaries
|
|
97
|
+
elf.search(b'/bin/sh') # find string or bytes in the binary
|
|
98
|
+
elf.functions['main'].address # same as elf.symbols['main']
|
|
99
|
+
list(elf.functions)[:10] # first 10 function names
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
For the libc that's linked:
|
|
103
|
+
```python
|
|
104
|
+
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
|
|
105
|
+
libc.symbols['system']
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 5. cyclic — find offsets without counting
|
|
109
|
+
|
|
110
|
+
For "where exactly does user input reach this variable" bugs:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
p = process('./target')
|
|
114
|
+
p.sendline(cyclic(256)) # send a De Bruijn pattern
|
|
115
|
+
# Crash occurs; note the crash value (e.g. RIP = 0x6161616c)
|
|
116
|
+
offset = cyclic_find(0x6161616c) # returns 12 (or wherever in the pattern)
|
|
117
|
+
# Now you know: byte 12 of your input lands at RIP
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Saves an hour of "pad by N bytes then check" iteration.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Logging during debug
|
|
125
|
+
|
|
126
|
+
pwntools logs output by default. Configure level in the script:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
context.log_level = 'debug' # very verbose — shows sent/received bytes
|
|
130
|
+
context.log_level = 'info' # default
|
|
131
|
+
context.log_level = 'warning' # quiet
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
For long scripts, log milestones:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
log.info('Connected to target')
|
|
138
|
+
log.success('Bypassed the check')
|
|
139
|
+
log.failure('Canary corrupted')
|
|
140
|
+
log.progress('brute-forcing').status('attempt %d' % i)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Typical debug-session patterns
|
|
146
|
+
|
|
147
|
+
### Reproduce a crash with a specific input
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
# /tmp/debug-repro.py
|
|
151
|
+
from pwn import *
|
|
152
|
+
context.binary = './target'
|
|
153
|
+
|
|
154
|
+
p = process('./target')
|
|
155
|
+
p.sendlineafter(b'> ', b'<bad input that crashes>')
|
|
156
|
+
p.wait()
|
|
157
|
+
# If it crashed, p.poll() returns non-zero
|
|
158
|
+
assert p.poll() is not None and p.poll() != 0, 'expected crash, got clean exit'
|
|
159
|
+
log.success(f'confirmed crash (exit {p.poll()})')
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Journal this script path. Run it as your "red test":
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
python /tmp/debug-repro.py
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Fuzz harness for a suspected input class
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
# /tmp/debug-fuzz.py
|
|
172
|
+
from pwn import *
|
|
173
|
+
import random
|
|
174
|
+
|
|
175
|
+
context.binary = './target'
|
|
176
|
+
context.log_level = 'warning' # keep quiet in the loop
|
|
177
|
+
|
|
178
|
+
crashes = []
|
|
179
|
+
for i in range(1000):
|
|
180
|
+
payload = bytes(random.randint(0, 255) for _ in range(random.randint(1, 100)))
|
|
181
|
+
p = process('./target')
|
|
182
|
+
p.sendline(payload)
|
|
183
|
+
p.wait()
|
|
184
|
+
if p.poll() is not None and p.poll() < 0: # crashed by signal
|
|
185
|
+
crashes.append((payload, p.poll()))
|
|
186
|
+
log.success(f'iter {i}: crash sig={-p.poll()}')
|
|
187
|
+
|
|
188
|
+
open('/tmp/debug-crashes.txt', 'w').write(repr(crashes))
|
|
189
|
+
log.info(f'found {len(crashes)} crashes')
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Automated exploit harness (CTF or self-testing a known CVE)
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
from pwn import *
|
|
196
|
+
context.binary = elf = ELF('./target')
|
|
197
|
+
libc = elf.libc or ELF('/lib/x86_64-linux-gnu/libc.so.6')
|
|
198
|
+
|
|
199
|
+
p = process('./target')
|
|
200
|
+
|
|
201
|
+
# Leak
|
|
202
|
+
p.sendline(b'A' * 64 + p64(elf.plt['puts']) + p64(elf.symbols['main']) + p64(elf.got['puts']))
|
|
203
|
+
leak = u64(p.recv(6).ljust(8, b'\x00'))
|
|
204
|
+
libc.address = leak - libc.symbols['puts']
|
|
205
|
+
log.success(f'libc base: {hex(libc.address)}')
|
|
206
|
+
|
|
207
|
+
# Exploit
|
|
208
|
+
rop = ROP(libc)
|
|
209
|
+
rop.system(next(libc.search(b'/bin/sh')))
|
|
210
|
+
p.sendline(b'A' * 64 + rop.chain())
|
|
211
|
+
|
|
212
|
+
p.interactive()
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Integration with gdb / pwndbg
|
|
218
|
+
|
|
219
|
+
pwntools can launch your process under gdb:
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
p = gdb.debug('./target', gdbscript='''
|
|
223
|
+
break main
|
|
224
|
+
continue
|
|
225
|
+
''')
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Or attach to a running pwntools-launched process:
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
p = process('./target')
|
|
232
|
+
gdb.attach(p, gdbscript='break *0x401234')
|
|
233
|
+
# continues in a new terminal window with gdb attached
|
|
234
|
+
p.sendline(b'trigger input')
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
This is the best way to debug a specific crash repeatably — pwntools drives input, gdb/pwndbg observes runtime state.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Gotchas
|
|
242
|
+
|
|
243
|
+
- **Python version**: pwntools supports Python 3.8+. Very old distros may not have it.
|
|
244
|
+
- **`p.interactive()` blocks.** It's for manual exploration; remove it from automated scripts.
|
|
245
|
+
- **ASLR on local runs**: turn off for reproducibility during debugging: `echo 0 | sudo tee /proc/sys/kernel/randomize_va_space` (remember to revert — journal this!).
|
|
246
|
+
- **`gdb.debug()` requires `gdb-multiarch`** for cross-arch binaries.
|
|
247
|
+
- **Subprocess cleanup**: if your script crashes, orphan `./target` processes may linger. Kill them at Phase 9 or add `atexit` cleanup.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Phase 9 cleanup specifics
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Remove pwntools debug scripts
|
|
255
|
+
rm -f /tmp/debug-*.py
|
|
256
|
+
rm -f /tmp/debug-crashes.txt
|
|
257
|
+
|
|
258
|
+
# Kill orphan target processes from failed runs
|
|
259
|
+
pkill -f './target' || true # adjust to actual binary name
|
|
260
|
+
|
|
261
|
+
# Restore ASLR if disabled
|
|
262
|
+
# echo 2 | sudo tee /proc/sys/kernel/randomize_va_space # Linux default
|
|
263
|
+
|
|
264
|
+
# Revert any binary patches applied for testing (see native-binary.md for details)
|
|
265
|
+
```
|