pwndbg Cheatsheet

Share
pwndbg Cheatsheet
audio-thumbnail
Disconnected Memory
0:00
/201.72

Commands

Gathering info

info functions

Obtain the functions that are stored in the binary.

info functions
  • Example output:
pwndbg> info functions
All defined functions:

Non-debugging symbols:
0x0000000000400528  _init
0x0000000000400550  puts@plt
0x0000000000400560  system@plt
0x0000000000400570  printf@plt
0x0000000000400580  memset@plt
0x0000000000400590  read@plt
0x00000000004005a0  setvbuf@plt
0x00000000004005b0  _start
0x00000000004005e0  _dl_relocate_static_pie
0x00000000004005f0  deregister_tm_clones
0x0000000000400620  register_tm_clones
0x0000000000400660  __do_global_dtors_aux
0x0000000000400690  frame_dummy
0x0000000000400697  main
0x00000000004006e8  pwnme
0x0000000000400756  ret2win
0x0000000000400780  __libc_csu_init
0x00000000004007f0  __libc_csu_fini
0x00000000004007f4  _fini

info registers

Obtain the information of the registers at the current state of the application execution.

info registers
  • Example output:
pwndbg> info registers
rax            0xb                 0xb
rbx            0x7fffffffdf68      0x7fffffffdf68
rcx            0x7ffff7ea5976      0x7ffff7ea5976
rdx            0x0                 0x0
rsi            0x7ffff7f87643      0x7ffff7f87643
rdi            0x7ffff7f887b0      0x7ffff7f887b0
rbp            0x7fffffffde50      0x7fffffffde50
rsp            0x7fffffffde50      0x7fffffffde50
r8             0x0                 0x0
r9             0x0                 0x0
r10            0x0                 0x0
r11            0x202               0x202
r12            0x0                 0x0
r13            0x7fffffffdf78      0x7fffffffdf78
r14            0x7ffff7ffd000      0x7ffff7ffd000
r15            0x0                 0x0
rip            0x4006d7            0x4006d7 <main+64>
eflags         0x206               [ PF IF ]
cs             0x33                0x33
ss             0x2b                0x2b
ds             0x0                 0x0
es             0x0                 0x0
fs             0x0                 0x0
gs             0x0                 0x0
fs_base        0x7ffff7d9e740      0x7ffff7d9e740
gs_base        0x0                 0x0
pwndbg> 

info breakpoints

Obtain the information of the breakpoints that has been set.

info breakpoints
  • Example output:
pwndbg> info breakpoints 
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004006d2 <main+59>
	breakpoint already hit 1 time
2       breakpoint     keep y   0x00000000004006d7 <main+64>

Disassemble

disas main

Disassemble a function

disas main
  • Example output:
pwndbg> disas main
Dump of assembler code for function main:
   0x0000000000001139 <+0>:	push   %rbp
   0x000000000000113a <+1>:	mov    %rsp,%rbp
   0x000000000000113d <+4>:	sub    $0x210,%rsp
   0x0000000000001144 <+11>:	mov    %edi,-0x204(%rbp)
   0x000000000000114a <+17>:	mov    %rsi,-0x210(%rbp)
   0x0000000000001151 <+24>:	mov    -0x210(%rbp),%rax
   0x0000000000001158 <+31>:	add    $0x8,%rax
   0x000000000000115c <+35>:	mov    (%rax),%rdx
   0x000000000000115f <+38>:	lea    -0x200(%rbp),%rax
   0x0000000000001166 <+45>:	mov    %rdx,%rsi
   0x0000000000001169 <+48>:	mov    %rax,%rdi
   0x000000000000116c <+51>:	call   0x1030 <strcpy@plt>
   0x0000000000001171 <+56>:	mov    $0x0,%eax
   0x0000000000001176 <+61>:	leave
   0x0000000000001177 <+62>:	ret
End of assembler dump.

disas <beginning>, <end>

Disassemble a range of memory addresses

disas 0x1144,0x115f
  • Example output:
pwndbg> disas 0x1144,0x115f
Dump of assembler code from 0x1144 to 0x115f:
   0x0000000000001144 <main+11>:	mov    %edi,-0x204(%rbp)
   0x000000000000114a <main+17>:	mov    %rsi,-0x210(%rbp)
   0x0000000000001151 <main+24>:	mov    -0x210(%rbp),%rax
   0x0000000000001158 <main+31>:	add    $0x8,%rax
   0x000000000000115c <main+35>:	mov    (%rax),%rdx
End of assembler dump.

Alternatively, we can do this:

disas main+13,main+36
  • Example output:
pwndbg> disas main+13,main+36
Dump of assembler code from 0x1186 to 0x119d:
   0x0000000000001186 <main+13>:	call   0x1070 <malloc@plt>
   0x000000000000118b <main+18>:	mov    %rax,-0x8(%rbp)
   0x000000000000118f <main+22>:	mov    -0x8(%rbp),%rax
   0x0000000000001193 <main+26>:	mov    %rax,%rsi
   0x0000000000001196 <main+29>:	lea    0xe6b(%rip),%rax        # 0x2008
End of assembler dump.
(gdb)

layout asm

Display a table that show the assembly code:

layout asm

PD: To close the table you must press Ctrl + x and a.

set disassembly-flavor intel

Change the syntax of the assembly language:

set disassembly-flavor intel
  • Example output:
pwndbg> set disassembly-flavor intel
pwndbg> disas 0x1144,0x115f
Dump of assembler code from 0x1144 to 0x115f:
   0x0000000000001144 <main+11>:	mov    DWORD PTR [rbp-0x204],edi
   0x000000000000114a <main+17>:	mov    QWORD PTR [rbp-0x210],rsi
   0x0000000000001151 <main+24>:	mov    rax,QWORD PTR [rbp-0x210]
   0x0000000000001158 <main+31>:	add    rax,0x8
   0x000000000000115c <main+35>:	mov    rdx,QWORD PTR [rax]
End of assembler dump.
pwndbg>

Breakpoints

break

Set a breakpoint in a specific memory address

break *0x0000000000001169
  • Example output:
pwndbg> break *0x0000000000001169
Breakpoint 1 at 0x1169: file vuln.c, line 6.

delete

Delete the all breakpoints

delete
  • Example output:
pwndbg> delete
Delete all breakpoints, watchpoints, tracepoints, and catchpoints? (y or n) y

Executing the binary

run

Executes the binary that's being debugged inside the own debugger. If a breakpoint has been set, the execution will stop on the previous instruction of the breakpoint.

run
  • Example output:
pwndbg> run
Starting program: /home/usuario/daemon/labs/ropemporium/ret2win/ret2win 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
...

run <<< command

You can run the binary and, if it asks for input, you can use <<< in order to fetch input to the running program. Also, you can execute commands from the shell inside the debugger in order to fetch the binary a specific input. This is demonstrated in the following post:

ret2win - ROPEmporium
Third District0:00/274.3771421× Antes de continuar Las prácticas que se realizan en este Captura la bandera (CTF) se trata meramente de prácticas formativas que no deberían nunca ser aplicadas a la vida real con fines maliciosos. Han sido avisados. * Sistema operativo: Debian 13 * Herramientas: pwntools, pwndbg, radare2 Un
run <<< $(command)
  • Example output:
pwndbg> run <<< $(whoami)
Starting program: /home/usuario/daemon/labs/ropemporium/ret2win/ret2win <<< $(whoami)
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
ret2win by ROP Emporium
x86_64

For my first trick, I will attempt to fit 56 bytes of user input into 32 bytes of stack buffer!
What could possibly go wrong?
You there, may I have your input please? And don't worry about null bytes, we're using read()!

> Thank you!

Exiting
[Inferior 1 (process 656030) exited normally]

Detect offsets

cyclic

With cyclic it is possible to create a string that uses the Bruijn sequence in order to perform ROP or buffer overflows.

cyclic
  • Example output:
pwndbg> cyclic 100
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
pwndbg> 

This can be used to fetch the the input of a program in order to perform a stack/buffer overflow.

$(python3 -c 'from pwn import *; print(cyclic(100).decode())')
  • Example output:
pwndbg> run <<< $(python3 -c 'from pwn import *; print(cyclic(100).decode())')
Starting program: /home/usuario/daemon/labs/ropemporium/ret2win/ret2win <<< $(python3 -c 'from pwn import *; print(cyclic(100).decode())')
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
ret2win by ROP Emporium
x86_64

For my first trick, I will attempt to fit 56 bytes of user input into 32 bytes of stack buffer!
What could possibly go wrong?
You there, may I have your input please? And don't worry about null bytes, we're using read()!

> Thank you!

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400755 in pwnme ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
─────────────────────────────────────────────────────────────────────────────[ LAST SIGNAL ]──────────────────────────────────────────────────────────────────────────────
Program received signal SIGSEGV (fault address: 0x0).

step

Makes the program run into the next instruction.

step
  • Example output:
pwndbg> run
Starting program: /home/usuario/daemon/labs/ropemporium/callme/callme <<< $(python3 -c 'from pwn import *; print(cyclic(100).decode())')
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
callme by ROP Emporium
x86_64
Breakpoint 1, 0x0000000000400882 in main ()
pwndbg> step
Hope you read the instructions...

> 

cyclic_find / cyclic -l

This can be used to find the offset after receiving a SIGSEGV (crash) from the program using the hex value that is left in the RIP after the crash.

cyclic -l <hex_value_inside_rip>
  • Example output:
pwndbg> cyclic -l 0x6161616c6161616b
Finding cyclic pattern of 4 bytes: b'kaaa' (hex: 0x6b616161)
Found at offset 40
pwndbg> 

Examining memory

x/o

Displays the memory inside the specified address/register in octal format.

x/o <memory_address/register>
  • Example output:
pwndbg> x/o 0x0000555555555141
0x555555555141 <main+8>:	077042707

x/x

Displays the memory inside the specified address/register in hexadecimal format.

x/x <memory_address/register>
  • Example output:
pwndbg> x/x $rip
0x555555555141 <main+8>:	0x00fc45c7

x/u

Displays the memory inside the specified address/register in unsigned standard base-10 decimal format.

x/u <memory_address/register>
  • Example output:
pwndbg> x/u $rip
0x555555555141 <main+8>:	16532935

x/t

Displays the memory inside the specified address/register in binary format.

x/t <memory_address/register>
  • Example output:
pwndbg> x/t $rip
0x555555555141 <main+8>:	00000000111111000100010111000111

x/b

Displays the memory inside the specified address/register in single byte format.

x/b <memory_address/register>
  • Example output:
pwndbg> x/b $rip
0x555555555141 <main+8>:	0xc7

x/h

Displays the memory inside the specified address/register in halfword format (two bytes).

x/h <memory_address/register>
  • Example output:
pwndbg> x/h $rip
0x555555555141 <main+8>:	0x45c7

x/w

Displays the memory inside the specified address/register in word format (four bytes).

x/w <memory_address/register>
  • Example output:
pwndbg> x/w $rip
0x555555555141 <main+8>:	0xfc45c7

x/g

Displays the memory inside the specified address/register in giant format (eight bytes).

x/g <memory_address/register>
  • Example output:
pwndbg> x/g $rip
0x555555555141 <main+8>:	0xeb00000000fc45c7

Additional info

Not only is it possible to examine what's inside an address, but also the addresses that follow them. For example, it is possible to examine the address range from 0x0000555555555141 to the address 0x0000555555555160 (32 bytes in memory) using the following command:

x/32<o/h/u/t/b> <memory address>
  • Example output:
pwndbg> x/32b $rip
0x555555555141 <main+8>:	0307	0105	0374	0	0	0	0	0353
0x555555555149 <main+16>:	023	0110	0215	05	0263	016	0	0
0x555555555151 <main+24>:	0110	0211	0307	0350	0327	0376	0377	0377
0x555555555159 <main+32>:	0203	0105	0374	01	0203	0175	0374	011

It is also possible to mix formats, for example, to print 32 bytes formatted in hexadecimal, I'd do this:

x/32xb <address/register>
  • Example output:
pwndbg> x/32xb $rip
0x555555555141 <main+8>:	0xc7	0x45	0xfc	0x00	0x00	0x00	0x00	0xeb
0x555555555149 <main+16>:	0x13	0x48	0x8d	0x05	0xb3	0x0e	0x00	0x00
0x555555555151 <main+24>:	0x48	0x89	0xc7	0xe8	0xd7	0xfe	0xff	0xff
0x555555555159 <main+32>:	0x83	0x45	0xfc	0x01	0x83	0x7d	0xfc	0x09