看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路

Editor發表於2017-06-28


本週最後一天,看雪CTF 2017 比賽進行至第五題

截止至今天中午12點,第四題破解人數為22人!

看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路

攻擊方排名前十名稍有變動,比賽排名有人升、有人降。

第五題結束後,

HHHso一舉衝到第7位,lacoucou也突進第十位,

隨著比賽的進行,選手的表現給了我們越來越多的驚喜!

看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路

大家繼續加油!

接下來我們來回顧一下第五題

看看看雪評委和出題者是怎麼說的ヾ(๑╹◡╹)ノ"



看雪評委 netwind 點評


作者限定了註冊碼為6個字元,用驅動進行了簡單的反除錯,並在驅動裡用簡單的演算法對註冊碼進行了處理,最後在應用層透過md5對比驗證來判斷註冊碼是否正確,此題需要暴力列舉才能得到結果。


作者簡介:


獨行孤客-80後,廣西玉林人,高二即開始自學c/c++/彙編,2008年註冊看雪賬號。同年入讀柳州師專網路專業。先後任職過反病毒工程師,某事業單位資訊保安研究員,負責軟體開發與逆向,軟體漏洞的挖掘與利用,計算機病毒技術的研究等。業餘時間喜歡鑽研書法碑帖,取法多參以二王與唐楷。


看雪 CTF2017 第五題設計思路


1. CM分兩部分,分別為應用層的CrackMe.exe,以及由CrackMe.exe生成的驅動vmxdrv.sys(載入進核心後被刪除)。

2. CM只能正常執行在XP系統上。

3. 安全軟體可能會報異常,但本人並沒有在CM中新增任何惡意程式碼,除了多開幾個執行緒會多佔資源之外,以及驅動有可能不穩定產生系統崩潰,所以請選手及時備份資料。

4. 使用者層顯示GUI介面並接受選手的輸入,選手輸入完成後按回車確認。CM將對答案作簡單處理後下發到驅動層模組,由驅動對答案進行處理,具體說是對處理後的答案再進行md5計算。

由使用者層透過ReadFile讀取計算結果,並再次對中間結果進行md5計算等操作。最後比對正確答案並在正確的情況下給選手以提示。CM的正確答案為:su1986,只接受六個字元。理論上在限制的時間內可以窮舉。

5. 驅動層除了負責一部分加密運算,還負責反除錯,透過IOCTL分發函式對客戶端的eprocess中的除錯埠進行清0操作。而客戶端則開啟多個執行緒迴圈傳送此IOCTL控制碼。

6. CM會在驗證答案時檢測是否被除錯,如發現IsDebuggerPresent返回真則不執行驗證流程.

7. 對選手的tips:安全軟體報毒可放在虛擬機器中執行,儲存重要資料以防系統崩潰,軟體需要回車確認答案。

下面選取攻擊者lacoucou的破解分析


檢視程式


1. 題目提示要在xp下執行,看了看資源,發現有驅動,將檔案提取出來,用PEID的演算法外掛KANAL掃描驅動,發現有MD5演算法:


看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路


2. 用OD載入程式CrakeME,下斷點CreateFileA,一次斷在釋放驅動的時候,另一次斷在載入驅動的時候:


1
2
3
4
5
6
7
8
00401DE8  |.  53            PUSH    EBX                              ; /hTemplateFile => NULL
00401DE9  |.  68 80000000   PUSH    0x80                             ; |Attributes = NORMAL
00401DEE  |.  6A 03         PUSH    0x3                              ; |Mode = OPEN_EXISTING
00401DF0  |.  53            PUSH    EBX                              ; |pSecurity => NULL
00401DF1  |.  53            PUSH    EBX                              ; |ShareMode => 0
00401DF2  |.  68 000000C0   PUSH    0xC0000000                       ; |Access = GENERIC_READ|GENERIC_WRITE
00401DF7  |.  68 58D34200   PUSH    CrackMe1.0042D358                ; |FileName = "\\.\vmxdrv"
00401DFC  |.  FF15 88324200 CALL    NEAR DWORD PTR DS:[<&kernel32.cr>; \CreateFileA


在CreateFileA 的下一條指令下斷點,執行程式,程式直接出錯退出。

有反除錯,用IDA開啟程式,發現了IsDebuggerPresent,這個應該不會導致程式崩潰。

接著找,發現了一個執行緒:


看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路


執行緒中死迴圈在傳送控制碼,開啟驅動,找到對應的控制碼:


看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路

看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路

嘿嘿,EPROCESS,最後有個清零的動作,這裡就是反除錯了吧。沒有查這個結構體,據猜測應該是把除錯埠清零了。


解決辦法:


1. 透過資源工具匯出驅動,然後修改驅動中的sub_10486函式(即上圖的fantishi_10486):

1
2
3
4
5
and     dword ptr [eax+0BCh], 0   //*(result+47)=0
83 A0 BC 00 00 00 00
//改成
or     dword ptr [eax+0BCh], 0
83 88 BC 00 00 00 00


這樣就不會清空埠了。

然後用loadpe修改驅動的校驗和。修改方法詳見:http://bbs.pediy.com/thread-185490.htm

用winhex修復crakeme,修復後的程式見附件。


2.跟蹤流程


跟蹤了幾次之後,理出來的流程大致如下:

1.sub_4013E0 主要負責釋放驅動,啟動驅動,還有反除錯

2.sub_4013E0 是按下enter之後的處理函式


主要流程:

1)sub_4182FA((CString *)&v7);   // 獲取註冊碼

2)sub_4182FA((CString *)&v7);   //註冊碼轉小寫  CString::MakeLower

3)sub_41830C((CString *)&v7);   //註冊碼倒序    CString::MakeReverse

4)  if ( *(_DWORD *)(v7 - 8) != 6 || IsDebuggerPresent() )  判斷註冊碼長度是否等於6 加反除錯

5)Sub_401D50(v1, v3, (size_t)v5);  這個函式主要功能:把獲取到的註冊碼傳送到驅動層,計算 hash後載讀取回來。

看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路

DeviceIoControl 這個地方是個坑,原來以為只是用來反除錯的,後續發現它會設定一個全域性變數dword_114D8 = 1; 

這個變數在驅動層計算md5中要使用,沒有這個,每次不管輸入的是什麼,驅動層返回的md5都一樣。

WriteFile 用來傳送我們輸入的註冊碼。

ReadFile 用來讀取計算出來的hash.

接著說說計算hash(md5)的演算法--驅動中:

看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路

圓圈中圈住的就是上邊說的全域性變數。

方框中圈的也與正規的md5演算法不同:

看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路

多了一些莫名其妙的操作。是一個變形的MD5演算法。


6)獲取到驅動返回的MD5之後:


(1).sub_417D43((CString *)&v4, (LPCSTR *)v1 + 23);  


返回類似md5值的字串形式  md5_like=md5_(userInput)


(2).sub_401920(v4, (CString *)v5);  將上述md5字串再計算一次md5


   Md5=sub_401920(md5_like)


(3).mid_415A78((LPCSTR *)&v8, (int)&v9, 2, 0xAu);


   subMd5=mid(md5,2,10)


   將md5字串從位置2處擷取10個字元。


(4)if ( _mbsicmp(v8, a888aeda4ab) ) 


  擷取的字串與888aeda4ab 比較。


(5)show_success_402030  拼接字串Success^^! 並顯示在窗體上。


整個演算法用虛擬碼描述就是:


1
subString=string_substr(md5(md5_like(CString::MakeReverse(CString::MakeLower(userInPut)))),2,10)


已知條件,輸入字串長度為6最終的subString 為888aeda4ab 。求輸入字串。


所以只能乖乖的爆破。


由於驅動中的md5是非標準版演算法,這裡也不再詳細跟了,直接自己寫程式呼叫他的驅動,Crakeme內的驅動為標準演算法,直接找一個md5原始碼就可以了。


找一個載入驅動的工具載入匯出的驅動,然後執行下面的演算法:

程式碼如下:


string Mem2String(unsigned char* psz,int nLen)
{
    string strText;
    unsigned char szBuf[4]={0};
    for (int i=0;i
    {
        sprintf_s((char*)szBuf,4,"%02x",psz[i]);
        strText+=(char*)szBuf;
    }
    return strText;
}
void calc_hash()
{
    unsigned char szMd5[0x10]={0};
    char szBuf[10]={0};
    char* pszFileName="\\\\.\\vmxdrv";
    HANDLE  hFile=CreateFileA(pszFileName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0x80,NULL);
    if (hFile==0)
    {
        printf("CreateFileA error!");
        return;
    }
    char OutBuffer[0x100]={0};
    DWORD BytesReturned=0;
    int result = DeviceIoControl(hFile, 0x222004u, 0, 0, OutBuffer, 0x100u, &BytesReturned, 0);
    if (!result)
    {
        printf("DeviceIoControl error! %d ",result);
        return;
    }              
    int nnumcount=0;
    char szKEY[7]={0};
    char szKeys[]="987654321zyxwvutsrqponmlkjihgfedcba";
    int nCount=strlen(szKeys);
    for (int i=0;i
    {
        for (int i1=0;i1
        {
            for (int i2=0;i2
            {
                for (int i3=0;i3
                {
                    for (int i4=0;i4
                    {
                        for (int i5=0;i5
                        {
                            szKEY[0]=szKeys[i];
                            szKEY[01]=szKeys[i1];
                            szKEY[02]=szKeys[i2];
                            szKEY[03]=szKeys[i3];
                            szKEY[04]=szKeys[i4];
                            szKEY[05]=szKeys[i5];
                            DWORD NumberOfBytesWritten=0;
                            DWORD NumberOfBytesRead=0;
                            if ( WriteFile(hFile, szKEY,7, &NumberOfBytesWritten, 0) )
                            {
                                ReadFile(hFile, szMd5, 0x10, &NumberOfBytesRead, 0);
                                string xxx=Mem2String(szMd5,16);
                                MD5((unsigned char*)xxx.c_str(),xxx.

終:

看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路


程式中沒有出來倒序的問題,因此這裡反過來輸入就可以了。


看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路


相關文章