My student got to work for DSO

November 23, 2007 by lamer · Leave a Comment 

He is a brilliant guy. Under his usual silence is the loud noise of his neuron machine cranking up and down. I am talking about Jeremy, a student in my software exploitation training in October.

Few days ago, he messaged me that he had been offered an internship with DSO (used to stand for Defense Science Organization), Singapore. This organization, among others, deals with national security and only accepts top Singapore citizens to join its rank. Being able to join DSO as a Software Pentester (I assume it deals with analysis and exploitation here) proved Jeremy a technically smart guy.

Congratulation to you, Jeremy!

And for me, I am so glad my training paid off well.

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

Software Exploitation Training – Successfully Completed

October 23, 2007 by lamer · Leave a Comment 

During the HITB 2007 Malaysia I met a young smart group of students from Singapore Polytechnic. They took part in the Capture the Flag competition and managed to score better than some professionals (need I make it clear?) in total contrast to their name: t3nth (they ranked eighth, by the way).

I thought that was impressive enough for these young chaps and maybe if they had proper training, they could turn as capable as any other qualified security engineer. And so I offered them a free workshop on software exploitation to serve as a primer. It was received enthusiastically.

An intensive four (or five, I dont quite remember)-session training was given on every week end through out last month. It covered all basic concepts, techniques, and some few advanced skills. I don’t know but it seemed like the boys grasped them pretty quickly. Actually, they surprised me! I didn’t expect that Paul could understand the stack diagram I drew on the white board in an instance, Louis would get the return-to-libc technique immediately when I mentioned it, Jeremy were able to analyze binary files in a few minutes, and Choon Rui mastered format string with no difficulty at all.

Through out the training, challenges from the CtF (no, not the binary, but with reconstructed source by yours truly) were used but these boys weren’t informed at all. They solved them, fluidly. What others weren’t able to do in Dubai 2007, and Malaysia 2007, they did it in only one or a few hours. Brilliant, ain’t they?

I hope it was a conducive workshop to them and that they loved it as much as I loved teaching them. It’s always a pleasure to work with smart guys. I believe these chaps will score much better in subsequent challenges. And if you are looking for interns, get them!

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

hashcrack v1.0

October 9, 2007 by lamer · Leave a Comment 

hashcrack is a fast (as fast as OpenSSL allows) hash cracker. It features an additive hash checking to speed up the process. For example, to check for the hashes of abc and abd, hashcrack only computes the hash of ab, then computes one round each for c and d totaling 4 rounds (two for ab, one for c and one for d). This eliminates a good number of rounds if we calculate hashes from the beginning (6 in this case). The longer the key, the more the saving.

A draw back to this feature is it does not work with non-additive hash algorithms. Luckily, popular algorithms, such as SHA-1, RIPEMD160, MD5, are additive.

Compared to vshark (another hash cracker by rd), hashcrack is so much faster. An unscientific benchmark to RIPEMD160-scan the whole 6-character a-zA-Z0-9 space ended in about 6 minutes with hashcrack, and more than 2 hours with vshark. To be fair to vshark, there was another version of hashcrack written in pure Python. It was 6 times slower than vshark.

Download hashcrack

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

HITB 2007 CTF report

September 16, 2007 by longld · Leave a Comment 

We decided to join HITB 2007 CTF in Kualar Lumpur just after the VNSECON ‘07 in August. Our team, Sao Vang from vnSecurity, is the last (10th) team registered, and we had only 1 month to prepare for the competition. It’s unbelievable that we win the game!

Day 1 – 05/09

The game, which had been planned to start at 10:30 AM, was delayed because the organizer had not completed setting it up. Teams had to find something fun to do while waiting. We sat on the ground playing bzflag. Other guys checked email, or set up the hardware. We felt a bit nervous because there was only one network cable on each team’s table and other teams brought their own switch.

Finally, CTF crew announced the game would start at 2:00 PM. At 2:45pm, it really started. While the crew setting up vmware images (Gentoo 2007 hardened) for teams’ servers, some guys looked over their shoulders and captured (guessed) the root’s password. It’s a bad password (qwe123). We got it too ;).

The organizer sent out crackme1 for Windows and the main switch would only be plumbed after it had been cracked. I changed our root’s password, copied the vmware image for backup, tried to upload the tools to server with USB HDD, and ran the defense script while lamer and sieukhung were cracking the binary on their laptop. They took it down only within 20 minutes!

Then the game really started. The organizer announced the root password to all teams. Before that, one team (perhaps Qb1t?) had used it to accessed other servers, installed backdoor user (lalala?) and unwisely changed their root passwords. The organizer identified and removed it easily. We had also prepared a script just for this situation. Had we run install_backdoor script (silently, without changing root password), we could have owned most of the boxes. But then, where is the fun?

All teams started looking at the vulnerability daemons (01 to 08) and defending their servers. Some teams chown‘d all the flags so that no other team could get it, even the score server ;-). There was glitches in the score server. Only Sao Vang got positive defensive score while the rest got negative. After crackme1 was done, the organizer sent out crackme2 binary. By the end of day 1, no daemon was exploited and we earned 350 bonus points for crackme1.

There was not much to say about day 1 because it just happened in less than 3 hours. We managed to crack crackme1 and identified the vulnerabilities in some daemons. Our dreaded vmware host running on WinXP hang 2 times and continued to hang 3 or 4 times on day 2.

Day 1.5

We got back to our place and continued the job overnight. crackme2 (md5 crack) was solved first by sieukhung. Then, we found the vuln in daemon05 (trivial buffer overflow; shamelessly, we weren’t successful in exploiting it remotely) and daemon07 (trivial format string) but there were “bugs” that made them un-exploitable. After few hours, we could exploit daemon02 (vtable overwrite) and daemon04 (buffer overflow with multithreaded complication). We went to bed (and sofa ;)) at 4:30 AM and woke up at 7:30 AM. Crazyyy!

The next morning, while waiting for taxi, lamer managed to exploit daemon01 (reverse crc32 and buffer overflow). All of our exploits were coded by lamer with his excellent Python framework.

Day 2 – 06/09

The game started at 11:00 AM and ran smoothly.

It was more exciting on day 2. We continued to lead from the beginning by submitting crackme2 and getting flags from other servers. The organizer also sent out fixed binaries for daemon05 and daemon07.

After 2 hours, we raked in lots of points for captured flags from daemon 1, 2, 4, and 7. According to the detail score log, we should have gained breakthrough points for 5 daemons (daemon08 later) instead of 4 as displayed on the official score board and Padocon (from Korea) would have had no breakthrough. We guessed they just replayed our exploits. And maybe other teams did the same too. We raked in more than 3000 points while the next closest team 700.

After that, we settled down to work on daemon 3, 6 and 8. At 2:00 PM, the organizer sent out crackme3 and source code of daemon08. sieukhung cracked crackme3 in half an hour and we earned many bonus points (800). Right after that, lamer finished his work on daemon08 and we got breakthrough for it. We decided to take a break and have lunch with McDonald hamburgers (thanks BlueMood, and Valmont for your support). We intended to give up daemon 3 and 6 to play bzflag (hey, they had a crowded bzflag server there) till the game ended.

But WsLabi (from Switzerland) managed to decode daemon03 and got breakthrough for it. They also ran exploits for other daemons and earned many offensive points. We felt their hot breath when their offensive score was just one flag behind us. I thought there was something wrong with our exploits and reviewed them. We found out that exploit for daemon04 was stuck by blocking socket behavior. We changed it and got more points.

Team Army Strong had best defensive score at that time and it seemed like we could not get valid flags from them. When trying to run exploit for daemon08 against Army Strong, I found that the first byte of the flag changed from time to time. It inspired us to write a brute force script to submit score to the server and with just a few Python loops we successfully captured their flag (thank you Army Strong for this inspration ;)).

Some of our exploits were not really stable (e.g. daemon07), flag data sometimes were 40 bytes or more instead of 20 bytes (fixed flag’s length). We modified the above brute force script to submit flag in any size and raked in more points. By 4:30 PM the organizer set new flags for some daemons (they set new flags only 1 time on day 2) and we easily gained more offensive points with our scripts.

When there was only 30 minutes left, the organizer announced bonus points for crackmes’ and daemons’ exploits write-ups (brief). It was quite rush. We decided to shutdown the server because score server did not check for defensive things anymore and focus on write-ups. We submitted write-ups for all challenges we solved and got more than 1000 bonus points.

Finally, we won the 1st place with a total of 8900 points, with best offensive (5280), second-best defensive (510) and highest bonus (3110). WsLabi won the 2nd place with a total of 5540 points and Padocon came next with 3165.

Conclusion

  • The CTF this year was very interesting and attracted a lot of people (though it started late as normal)
  • Some teams had more than 3 players (4 to 6) and played in turn. It is more fun this way.
  • Best defensive strategy is to keep the daemons running and modify nothing.
  • Because defensive score is far lower than offensive score, “good” defensive strategy is to remove read permission from flags so that no other team can get it. “Best” defensive strategy is to follow Army Strong.
  • Capturing then replaying is a good offensive strategy and can help team win if they do it effectively.
  • python rox!
  • Team must plan and prepare well to have good result.

References

Credits

To all vnSecurity members

More detailed write ups will be posted at http://www.vnsecurity.net.

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

Next Page »