pwnsmith
A GDB plugin made for solving pwn challenges.
Find at https://github.com/idktheflag/pwnsmith
How to install
Section titled “How to install”curl -sL https://raw.githubusercontent.com/idktheflag/pwnsmith/main/install.sh | sudo bashThis installs system dependencies (gdb, python3, binutils), Python packages (pwntools, pyelftools, capstone), clones the repo to ~/.pwnsmith, installs the binary to /bin/pwnsmith, and configures ~/.gdbinit.
How to update
Section titled “How to update”pwnsmith updateChecks the remote VERSION file on GitHub. If a newer version exists, downloads the updated binary from GitHub Releases and installs it to /bin/pwnsmith.
How to launch
Section titled “How to launch”pwnsmith # bare GDB with PwnSmith loadedpwnsmith ./binary # debug a specific binarypwnsmith -p 1234 # attach to a running processpwnsmith ./binary core # load a core dumpPwnSmith launches GDB in quiet mode with the plugin pre-loaded. All GDB arguments pass through. The prompt changes to pwnsmith>.
Subcommands (shell)
Section titled “Subcommands (shell)”These run from your terminal, not inside GDB.
| Command | Description |
|---|---|
pwnsmith setup | Add PwnSmith to ~/.gdbinit so plain gdb loads it too |
pwnsmith unsetup | Remove PwnSmith from ~/.gdbinit |
pwnsmith update | Check for and install the latest version |
pwnsmith version | Print the installed version |
pwnsmith --help | Show usage |
Commands Reference
Section titled “Commands Reference”Everything below runs inside PwnSmith (at the pwnsmith> prompt).
analyze
Section titled “analyze”Auto-scans the loaded binary and reports security properties, dangerous imported functions, win/flag functions, ROP gadgets, interesting strings, and a suggested attack plan.
pwnsmith> analyzepwnsmith> analyze quick # just checksec + dangerous functionspwnsmith> analyze vulns # focus on vulnerable importspwnsmith> analyze gadgets # quick ROP gadget summarypwnsmith> analyze strings # interesting strings in the binarypwnsmith> analyze all # everything with full detailWhat it checks:
- Security: NX, PIE, RELRO, stack canary
- Dangerous functions:
gets,strcpy,sprintf,printf,system,malloc/free,read,memcpy— rated CRITICAL, HIGH, MEDIUM, CHECK, or INFO - Win functions: scans for functions named
win,flag,shell,backdoor,secret, etc. - ROP gadgets: quick scan of
.textforpop rdi; ret,pop rsi; ret,ret, etc. - Strings:
/bin/sh,flag,%n,%s,cat,system,password - Attack summary: suggests techniques (ret2win, ret2libc, format string, heap) with the command to try next
payload
Section titled “payload”Generates exploit payloads and runs them against local or remote targets without leaving PwnSmith.
Generate payloads
Section titled “Generate payloads”pwnsmith> payload gen ret2win # auto-detect offset + win functionpwnsmith> payload gen ret2win 72 # with known offsetpwnsmith> payload gen ret2win 72 0x4011a6 # with known offset and target addresspwnsmith> payload gen rop 72 # system("/bin/sh") ROP chainpwnsmith> payload gen shellcode 64 # NOP sled + execve shellcodepwnsmith> payload gen cyclic 200 # de Bruijn pattern for offset findingpwnsmith> payload gen padding 64 # just A'sret2win auto-detects the buffer size from disassembly (sub $0xN, %rsp), finds functions named win/flag/shell, and locates a ret gadget for stack alignment. Override any of these by passing arguments.
Run payloads
Section titled “Run payloads”pwnsmith> payload run # run against local binarypwnsmith> payload run pwn.ctf.com 9001 # run against remote targetSpawns a pwntools process/remote in the background, sends the payload, and prints the output. No need to exit GDB.
Remote targets
Section titled “Remote targets”pwnsmith> payload remote pwn.ctf.com 9001 # set default remotepwnsmith> payload run # now sends to remote by defaultpwnsmith> payload remote # show current remoteSave and script
Section titled “Save and script”pwnsmith> payload show # display last generated payloadpwnsmith> payload save payload.bin # save to file (use: run < payload.bin)pwnsmith> payload script exploit.py # generate pwntools exploit scriptpwnsmith> payload script exploit.py ctf.com 9001 # script with remote targetpwnsmith> payload find offset # help determine overflow offsetGenerated scripts support python3 exploit.py for local and python3 exploit.py REMOTE for remote.
Display all registers with change highlighting. Values that changed since the last stop are shown in red with the previous value.
pwnsmith> regs # all registerspwnsmith> regs general # general-purpose only (rax, rbx, rcx, ...)pwnsmith> regs special # rip, eflags, segment registerspwnsmith> regs rax # single registerPointer values are automatically dereferenced — if a register points to readable memory, the target value or string is shown.
Aliases: rg
Telescope the stack, showing hex values, pointer chains, strings, and frame annotations.
pwnsmith> stack # 16 entries from $rsppwnsmith> stack 32 # 32 entriespwnsmith> stack 16 $rbp # start from $rbppwnsmith> stack -r # reverse orderpwnsmith> stack frames # show call frame boundariesEach line shows:
- Offset from starting address
- Stack address and value
← $rsp/← $rbpmarkers← ret addr (frame N) [function_name]for detected return addresses← saved rbp (frame N)for saved frame pointers- Dereferenced pointer chains or string content
- Symbol names for code addresses
stack frames walks the saved RBP chain and displays each frame in a box with function name, return address, saved RBP, and local variable region size.
Aliases: st
Parse and display glibc malloc heap chunks.
pwnsmith> heap # walk all chunks from heap basepwnsmith> heap 0x555555559000 # walk from specific addresspwnsmith> heap -n 64 # show at most 64 chunkspwnsmith> heap chunk 0x... # detailed view of one chunkpwnsmith> heap bins # show fastbin chainspwnsmith> heap tcache # show tcache bins (glibc 2.26+)pwnsmith> heap top # show the top (wilderness) chunkpwnsmith> heap check # walk heap and report corruptionEach chunk shows:
- Address and status:
INUSE(green),FREE(red),MMAP(magenta) - Size with human-readable notation for large chunks
- Flag bits: P (prev_inuse), M (mmapped), N (non_main_arena)
fd/bkpointers for free chunks- Corruption warnings: size misalignment, invalid pointers, broken doubly-linked lists
heap tcache handles safe-linking deobfuscation (glibc 2.32+).
Aliases: hp
Enhanced breakpoint management with automation.
pwnsmith> bp main # break at functionpwnsmith> bp 0x401234 # break at addresspwnsmith> bp *main+0x20 # break at offsetpwnsmith> bp main -c "stack 8" # break + run command on hitpwnsmith> bp read@plt -t # temporary (one-shot) breakpointpwnsmith> bp list # list all breakpointspwnsmith> bp del 1 # delete breakpoint #1pwnsmith> bp del all # delete allpwnsmith> bp enable 1 # enable breakpointpwnsmith> bp disable 1 # disable breakpointpwnsmith> bp auto 1 "regs" # add automation to existing breakpointThe -c flag runs a PwnSmith or GDB command every time the breakpoint is hit — useful for auto-displaying state at key points.
Find ROP gadgets and auto-generate chains.
pwnsmith> rop # find all known gadgets in .textpwnsmith> rop pop rdi # search for specific patternpwnsmith> rop --libc # also search in libcpwnsmith> rop --libc pop rdi # specific gadget in libcpwnsmith> rop --bytes 5fc3 # search for custom byte sequencepwnsmith> rop --all # show all instances (not just first)pwnsmith> rop --section .plt # search specific sectionpwnsmith> rop chain system # auto-build system("/bin/sh") chainpwnsmith> rop chain execve # auto-build execve("/bin/sh", 0, 0) chainpwnsmith> rop chain mprotect # auto-build mprotect() chainpwnsmith> rop one_gadget # find one_gadget addresses in libcrop chain searches libc for the required gadgets (pop rdi; ret, etc.), locates /bin/sh and the target function, assembles the chain, and outputs both a visual layout and a copyable pwntools flat() snippet.
rop one_gadget requires the one_gadget Ruby gem (gem install one_gadget).
Aliases: gadgets
fmtstr
Section titled “fmtstr”Format string exploitation helpers.
pwnsmith> fmtstr offset 20 # generate probe with 20 %p specifierspwnsmith> fmtstr read 0x404040 6 # generate %s read payload (offset 6)pwnsmith> fmtstr write 0x404040 0xdeadbeef 6 # generate %hhn write payloadpwnsmith> fmtstr write 0x404040 0xdead 6 --short # use %hn writespwnsmith> fmtstr pwntools 0x404040 0x42 6 # generate pwntools fmtstr_payload()offset: Generates a probe string (AAAABBBB%1$p.%2$p.%3$p...) to send as input. Look for 4242424241414141 in the output — the position number is your format string offset.
write: Calculates the byte-by-byte %hhn write sequence needed to write an arbitrary value to an arbitrary address. Shows the math for each byte.
pwntools: Outputs a ready-to-use fmtstr_payload() call.
Aliases: fmt
Configure the auto-context display that shows registers + disassembly + stack on every program stop.
pwnsmith> ctx # show context nowpwnsmith> ctx off # disable auto-contextpwnsmith> ctx on # re-enable auto-contextpwnsmith> ctx regs off # hide registerspwnsmith> ctx stack off # hide stackpwnsmith> ctx code off # hide disassemblypwnsmith> ctx bt on # show backtracepwnsmith> ctx depth 16 # set stack telescope depthpwnsmith> ctx lines 10 # set disassembly line countpwn-connect
Section titled “pwn-connect”Manage pwntools connections for send/recv interaction alongside GDB debugging.
pwnsmith> pwn-connect remote 10.0.0.1 9001 # connect to remote targetpwnsmith> pwn-connect process ./vuln # start local processpwnsmith> pwn-connect attach # attach to GDB's current inferiorpwnsmith> pwn-connect status # show connection infopwnsmith> pwn-connect close # close connectionpwn-send / pwn-recv
Section titled “pwn-send / pwn-recv”Send and receive data through a pwn-connect connection.
pwnsmith> pwn-send hello # send raw stringpwnsmith> pwn-send -l "1" # send with newlinepwnsmith> pwn-send -x 4141414142424242 # send hex bytespwnsmith> pwn-send -p64 0x00007ffff7a52000 # send packed 64-bit valuepwnsmith> pwn-send -p32 0x08048000 # send packed 32-bit valuepwnsmith> pwn-send -f payload.bin # send file contents
pwnsmith> pwn-recv # receive available datapwnsmith> pwn-recv 64 # receive up to 64 bytespwnsmith> pwn-recv -u ": " # receive until delimiterpwnsmith> pwn-recv -l # receive one linepwn-leak
Section titled “pwn-leak”Parse a leaked address from hex bytes. Stores the result in GDB convenience variable $leak.
pwnsmith> pwn-leak 00a0f7ff7f000000 # parse hex as 64-bit addresspwnsmith> pwn-leak -r 6 # receive 6 bytes and parsepwnsmith> pwn-leak -r 6 --32 # parse as 32-bitAfter running, use $leak in GDB expressions: print $leak, x/gx $leak, etc.
pwn-checksec
Section titled “pwn-checksec”Display binary security properties (like checksec).
pwnsmith> pwn-checksec # check loaded binarypwnsmith> pwn-checksec /path/to/other # check specific binaryShows NX, PIE, RELRO (none/partial/full), and stack canary status.
pwn-libc
Section titled “pwn-libc”Display libc information for the running process.
pwnsmith> pwn-libc # show base, symbols, gadgetspwnsmith> pwn-libc system # look up specific symbolShows: libc base address, common symbol offsets (system, __free_hook, __malloc_hook, environ), /bin/sh string address, and common gadget addresses.
pwn-template
Section titled “pwn-template”Generate a pwntools exploit script template.
pwnsmith> pwn-template # print to screenpwnsmith> pwn-template -o exploit.py # save to filepwnsmith> pwn-template -r ctf.com 9001 # include remote setuppwn-script
Section titled “pwn-script”Multi-step exploit scripting. Load a Python script that defines steps, then run them sequentially with shared state.
pwnsmith> pwn-script load exploit_steps.py # load scriptpwnsmith> pwn-script run # run all stepspwnsmith> pwn-script step # run next steppwnsmith> pwn-script step 2 # run specific steppwnsmith> pwn-script status # show progress + variablespwnsmith> pwn-script reset # reset to step 0pwnsmith> pwn-script set libc_base 0x7f... # set a variablepwnsmith> pwn-script clear # unload scriptScript format:
def setup(script): def leak(vars): # do leak logic, return new variables return {"libc_base": 0x7ffff7a00000}
def exploit(vars): base = vars["libc_base"] # build and send payload
script.add_step("leak libc", leak) script.add_step("send exploit", exploit)Aliases: pws
pwn-config
Section titled “pwn-config”View and modify PwnSmith settings. Persists to ~/.pwnsmith.conf.
pwnsmith> pwn-config # show all settingspwnsmith> pwn-config set context.stack_depth 16pwnsmith> pwn-config set heap.detect_corruption truepwnsmith> pwn-config save # write to diskpwnsmith> pwn-config reset # reset to defaultspwnsmith> pwn-config reload # reload from diskAvailable settings:
| Section | Key | Default | Description |
|---|---|---|---|
context | enabled | true | Auto-context on stop |
context | show_regs | true | Show registers |
context | show_stack | true | Show stack |
context | show_code | true | Show disassembly |
context | show_backtrace | false | Show backtrace |
context | stack_depth | 8 | Stack entries to show |
context | code_lines | 6 | Disassembly lines |
heap | max_chunks | 32 | Max chunks to walk |
heap | detect_corruption | true | Check for corruption |
heap | tcache_support | true | Parse tcache bins |
stack | default_depth | 16 | Default telescope depth |
stack | detect_ret_addrs | true | Highlight return addrs |
cache | enabled | true | Memory read caching |
pwn-sections
Section titled “pwn-sections”Display binary sections with addresses and sizes.
pwnsmith> pwn-sectionspwn-interactive
Section titled “pwn-interactive”Drop into interactive pwntools mode with the connected target. Press Ctrl+C to return to PwnSmith.
pwnsmith> pwn-interactiveAliases
Section titled “Aliases”| Alias | Command |
|---|---|
aa | analyze |
pl | payload |
rg | regs |
st | stack |
hp | heap |
gadgets | rop |
fmt | fmtstr |
pws | pwn-script |
Adding Custom Commands
Section titled “Adding Custom Commands”Create a .py file in pwnsmith/commands/. It’s auto-discovered on next load — no edits to gdbinit.py needed.
import gdbfrom pwnsmith.commands import register_command
@register_command("mycmd", "Short description", aliases=["mc"])class MyCommand(gdb.Command): """Full help text shown by 'help mycmd'."""
def __init__(self): super().__init__("mycmd", gdb.COMMAND_USER)
def complete(self, text, word): return [c for c in ["sub1", "sub2"] if c.startswith(word)]
def invoke(self, arg, from_tty): gdb.write(f"Args: {arg}\n")The @register_command decorator takes:
name— the GDB command namedescription— shown in the startup banneraliases— optional list of shorthand names
Architecture
Section titled “Architecture”~/.pwnsmith/ ← install directory (git clone)├── VERSION ← single source of truth for version├── install.sh ← curl installer├── dist/pwnsmith ← compiled binary (PyInstaller)├── pwnsmith.spec ← build spec├── setup.py ← pip package metadata├── pwnsmith/│ ├── cli.py ← binary entry point + update system│ ├── gdbinit.py ← GDB loader, auto-discovers commands│ ├── __init__.py ← reads VERSION│ ├── commands/│ │ ├── __init__.py ← @register_command decorator + registry│ │ ├── analyze.py ← auto-analysis│ │ ├── payload.py ← payload gen + run│ │ ├── regs.py ← register display│ │ ├── stack.py ← stack telescope│ │ ├── heap.py ← heap visualization│ │ ├── breakpoints.py ← enhanced breakpoints│ │ ├── rop.py ← ROP gadgets + chains│ │ ├── fmtstr.py ← format string helpers│ │ ├── exploit.py ← pwntools commands│ │ └── script.py ← multi-step scripting│ ├── utils/│ │ ├── memory.py ← safe memory access + page cache│ │ ├── printer.py ← ANSI colors + formatting│ │ ├── libc.py ← libc symbols + gadgets│ │ ├── parser.py ← ELF parsing + checksec│ │ ├── pwntools_helper.py ← connection manager│ │ └── config.py ← config file system│ └── events/│ └── stop_handler.py ← auto-context on stop└── challenges/ ← practice CTF challenges ├── Makefile ├── 01-smashville/ ← ret2win (easy) ├── 02-leaky-pipes/ ← format string (medium) └── 03-heap-of-trouble/ ← heap UAF (hard)How it loads
Section titled “How it loads”pwnsmithbinary extracts the bundled Python package to~/.pwnsmith/lib/pwnsmith/- Launches
gdb -q -x ~/.pwnsmith/lib/pwnsmith/gdbinit.py gdbinit.pyusespkgutil.iter_modulesto discover all files incommands/- Each file’s
@register_commanddecorators populate a global registry register_all()instantiates every command class + creates alias commands- Event hooks connect to GDB’s stop/exit/new_objfile events
- Memory cache is invalidated on each stop event
How update works
Section titled “How update works”pwnsmith updatefetchesVERSIONfromraw.githubusercontent.com- Compares against the bundled
VERSION - If newer, downloads the binary from
github.com/imattas/pwnsmith/releases/download/v{version}/pwnsmith - Installs to
/bin/pwnsmithviasudo cp - Clears the cached lib so it re-syncs on next run
- Falls back to
git pullif no release binary exists