看雪.WiFi萬能鑰匙 CTF 2017第十二 點評及解題思路
看雪CTF 2017 比賽進行至第十二題
截止至今天中午12點,第十二題破解人數為 5 人!
防守方 hsadkhk 依然位居首位~,第十二題作者衝進第二位!
此題過後,風間仁依然處於第一位,前十名排名基本保持不變。
期待ing......
接下來我們來回顧一下第十二題
看看 看雪評委和出題者是怎麼說的ヾ(๑╹◡╹)ノ"。
看雪評委 netwind 點評
作為一道安卓平臺破解題,作者在反除錯和加密演算法上對apk檔案進行了很好的防護。透過對dex檔案進行hash校驗,隱藏函式名,在so層檢查是否被附加除錯來進行反除錯。在演算法上採用了DES和RC6演算法,需要暴力列舉來破解此題。
作者簡介
liuluping,四川大學資訊電子資訊學院在讀研究生,目前研究方向為軟體安全和漏洞分析,正在進行符號執行和程式自動化分析分析相關的研究,從碩士開始接觸軟體安全,從事程式分析,惡意程式碼分析和檢測的相關方向的研究。
在程式分析上比較擅長協議逆向分析,常見加密演算法識別以及惡意程式碼分析等,在實驗室的日常工作中,接觸較多各種零散類的工作,在安全研究路上還有待成長。
看雪 CTF 2017 第十二題設計思路
題目Flag
Flag:kxuectf{D3crypted1sV3rylntere5tin91}
題目設定時需要說明flag格式:kxuectf{},否則後面涉及到暴力破解,可能會出現題目無解。
安全策略
1. DEX 修改和反除錯檢測
(1)對DEX檔案的SHA-1值進行檢測:從/data/dalvik-cache/目錄中讀出應用安裝儲存的DEX檔案,獲取裡面DEX檔案的SHA-1值,並與應用原始的SHA-1值比較,不相等則退出,隱藏在動態註冊中;
(2)為了防止解題者直接nop掉exit()函式,在進入so中的check函式後首先再進行一次DEX是否修改和反除錯檢測,如果檢測到任意一個就將DES演算法金鑰的第5個和第6個值改掉。
2. 隱藏MainActivity,使得程式不執行配置檔案中的MainActivity 。
安全策略
1.採用符號隱藏策略,將函式名隱藏
2.動態註冊
使用動態註冊將java層的check函式動態註冊為ab函式
Java層演算法
1. 在配置檔案的MainActivity 即Main類中新增了多餘的迷惑解題者的簽名驗證,實際並沒有執行。
2. Java層演算法一共三個,ab.a()、ba.a()、ca.a(),但是真正有用的是ab.a(),一個簡單的移位加密。
Main類中的呼叫順序是:
str=ca.a(input)+ba.a(input)+ab.a(input)
uv類中的呼叫順序是:
str= ab.a(input)+ba.a(input)+ca.a(input)
ab.a()、ba.a()函式密文和輸入長度一樣,ca.a()函式密文與輸入長度有關,所以演算法需要對輸入位數的判斷,來確定輸入為多少位。
3. 真正用於so中驗證的只取前36位,也就是真正有用的加密函式只有ab.a()。
Native 層演算法
1. Native層演算法思路簡單,使用兩層加密演算法,分別是RC6和DES。
2. 演算法基本步驟如下:
3. 首先將輸入利用DES進行加密,其中DES金鑰硬編碼在程式中,需要進行5輪。
4. 將加密後的資料分成兩部分,前4輪組成0x20個位元組作為第一部分,而後面一輪的前4個位元組作為另外一部分。
5. 將步驟2中得到的最後一輪前4個位元組替換掉硬編碼的0x10個位元組後作為下一步驟進行加密的RC6金鑰。
6. 利用步驟3中得到的RC6金鑰對步驟1中加密後得到的前半部分(0x20)進行加密後和硬編碼的資料進行比較。
7. 最後根據比較結果得到True或者False並返回。
8. Native層的加密演算法整個流程見PPT第二頁。
相關思路
1. 在步驟1中使用的DES加密演算法為標準的加密演算法,使用的Paddting填充模式,填充資料為(8-(加密長度%8))
2. 在RC6演算法中,對兩個固定引數中的一個稍微進行了修改,引數Q由0x9E3779B9變成了0x61c88647。
3. 為了增加一點難度,這裡沒有直接將輸入經過兩次加密後直接和硬編碼資料進行比較,而是將第一次加密後的部分作為第二次金鑰的一部分。這裡不會造成無解。因為在程式中已經進行了提示flag開頭為kxuectf{,因此前8個位元組固定,經過java層相關變換以及到了native層第一次DES加密時,由於DES也是8位元組分組加密,因此DES加密後輸出8位元組也是固定的,為“\x4c\xd9\xa3\xe6\xed\xfe\xd1\x05”。
這樣在進行解題中,由於知道最後比較結果,知道RC6金鑰的前12個位元組,以及知道RC6加密前的明文的前8個位元組格式,因此這裡一般思路是可以暴力列舉4個位元組,將比較結果進行解密判斷前8個位元組是否等於上面的結果,從而得到RC6的金鑰,進而逆推還原。
4. 但其實只需要破解3個位元組就ok,透過分析程式可知,flag為36個字元,最後一個為},經過java層加密後得到固定字元‘{’,在進行DES加密時,採用padding模式,因此最後一組肯定是”xxx{\x04\x04\x04\x04”。
從這個地方推過去,由於最後一組進行DES加密後會去前4個位元組來替換掉RC6的金鑰,因此列舉最後一組前的3個字元即可,這樣將最後一組進行列舉並一次進行DES加密然後將結果中的前四個位元組取出來替換到硬編碼的RC6金鑰,然後利用RC6金鑰對最後比較的0x20個位元組進行解密,如果接的得到的前8個位元組為“\x4c\xd9\xa3\xe6\xed\xfe\xd1\x05”則表示最後flag的最後四個字元已經確定,並且RC6的金鑰也確定,這樣在再對硬編碼資料進行解密並依次逆推後即可順利得到最後的flag:kxuectf{D3crypted1sV3rylntere5tin91}。
下面選取攻擊者 loudy 的破解分析
使用工具:IDA6.8(so修改、反彙編分析、動態除錯) notepad(記錄) vc6.0(程式設計解碼) android sdk emulator(android4.4虛擬機器)、jeb(dex反編譯)ApkIDE(修改DEX、重打包)
步 驟:
一、反逆向手段繞過
(1)dex層
直接JEB分析,如下圖3處紅線標註的地方有MD5校驗。
繞過方法也很簡單,ApkIDE反編譯,修改下圖61行的if-eqz為if-neq,並重新打包,即可直接跳過MD5檢測。打包時,也許會提示某個styles.xml的幾行有問題,刪除那幾行即可。
(2)so層
用IDA連線,程式直接退出,故肯定有反除錯手段。用winrar對apk檔案解包後,發現lib目錄有3個不同的so檔案,如下,其中armeabi-v7a資料夾下的libenjoy.so檔案才是我的android4.4系統需要的,分析此檔案。
IDA載入,靜態分析,沒有發現.init表,那麼我們重點分析JNI_OnLoad函式。其中sub_24B8和sub_281C是兩個主要的反除錯函式。
而sub_2350和sub_2378都是同一種形式的解碼函式,即按位元組依次與0x16異或,解密結果都是字串,這種函式後面還有很多,不一一介紹。
JNI_OnLoad中第14行解碼結果為“check”,也即dex呼叫的本地函式,再看17行,跟蹤到如下位置,發現check函式的實際地址為sub_3748。
而此處作者也用了一個小手段,自己新建了一個名為.mytext的可執行段,sub_3748在其中實現,導致IDA在預設的.text段找不到該函式,有一定的反逆向效果。
再看JNI_OnLoad函式呼叫的sub_24B8函式,該函式的主要作用是讀取/data/dalvik-cache/目錄下的data@app@com.game.kxctf-1.apk@classes.dex檔案或者data@app@com.game.kxctf-2.apk@classes.dex檔案的校驗值,結果與“E07784C2A2923354F18952BBDB5D81916D24D2F5”比較,不等於則exit(0)退出程式。
繞過方法也很簡單直接將JNI_OnLoad中對該函式的呼叫以0x00覆蓋即可。
JNI_OnLoad函式呼叫的sub_281C函式,實際就是呼叫sub_1B04如下,該函式建立了一個執行緒。
跟進後,發現執行緒主體如下。其中sub_25A8函式獲取/proc/%d/status的State,看其中是否包含“R/S/T”。sub_2628獲取/proc/%d/status的TracerPid,看是否為非0值。sub_2688執行cat/proc/%d/wchan,看結果中是否包含sys_epoll或者ptrace_stop。sub_24B8之前已經分析。
從分析可以知道,該執行緒沒有影響演算法流程,因此也可以直接在JNI_OnLoad中將對sub_281C的呼叫以0x00覆蓋,實現繞過。
最後在check函式sub_3748開頭還有一處反除錯,如下,分析發現sub_27B4功能和sub_24B8一模一樣,不再累述,直接將呼叫處用0x00覆蓋實現繞過。
二、演算法流程分析
反逆向手段清除後就可以大膽除錯,跟蹤演算法流程了。流程分dex層和so層兩個方面講。
(1)dex層
JEB分析結果很直觀,將三個函式分別對輸入字串的處理結果連線起來,送入so層處理,如果so層處理結果為1,則正確。
ca.a是base64編碼,ba.a、ab.a也分別是一種編碼,雖然有三種編碼,但實際分析後發現,ca.a和ba.a都不起作用,實際只有ab.a參與了演算法流程,該函式如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | publicstaticStringa(Stringinput) { returnab.encrypt(input); } publicstaticStringencrypt(Stringinput) { Stringv3 = "" ; intv2; for (v2 = 0; v2<input.length(); ++v2) { intv0 = input.charAt(v2); if (v0<97 v0="">109) { if (v0>= 65&&v0<= 77) { v3 = String.valueOf(v3) + ((( char )(v0 + 13))); gotolabel_20; } if (v0>= 110&&v0<= 122) { v3 = String.valueOf(v3) + ((( char )(v0 - 13))); gotolabel_20; } if (v0>= 78&&v0<= 90) { v3 = String.valueOf(v3) + ((( char )(v0 - 13))); gotolabel_20; } if (v0>= 48&&v0<= 57) { v3 = String.valueOf(v3) + ((( char )(v0 ^ 7))); gotolabel_20; } v3 = String.valueOf(v3) + ((( char )(v0 ^ 6))); } else { v3 = String.valueOf(v3) + ((( char )(v0 + 13))); } label_20: } returnv3; } |
此時無需更加深入分析,可以等so反推之後再爆破。
(2)so層
so層流程其實很簡單。
1、 判斷dex層傳來的資料是否大於0x78(其實此時就是0x78),大於則over。
2、 擷取前0x24位(即dex層ab.a函式處理結果),並在結尾補4個4成0x28位。
3、 用金鑰{0xFD, 0xB4, 0x68, 0x54, 0x08, 0xCD, 0x56, 0x4E}對此0x28位進行DES加密(非標準)(實際操作時,金鑰轉換為子金鑰總有一兩位不同,故直接在記憶體提取子金鑰表,取消金鑰生成過程)
4、 DES結果第0x20、0x21、0x22,0x23位替換金鑰{0x65, 0x48, 0x32, 0xEF, 0xBA, 0xCD, 0x56, 0x4E, 0x0F, 0x9B, 0x1D,0x27, 0x0, 0x0, 0x0, 0x0}的最後四位。
5、 用上一步的金鑰對DES結果前0x20位進行RC6加密。
6、 RC6加密(非標準)結果與0x42D3C3C2, 0xF12AE92D, 0x66C92822, 0x2CEB540E,0x9407E577, 0x4A92B792, 0x2E5DFDF0, 0xF3549FC6比較,全部相等則註冊成功。
三、破解過程
流程梳理清楚就好了,首先透過除錯修改標準DES和RC6與程式所用一致。
其中DES修改較小,RC6修改較大,分別如下。一般RC6加密Q值為0x9E3779B9,而靜態分析可知此程式為0x61C88647(即-0x9E3779B9)。
另外RC6的金鑰會有個反饋,不是每次塊(0x10位元組)加密都用同一個金鑰,對照IDA將C程式碼做如下修改,其中kerr為下一次加解密的金鑰。
這兩個函式調整好後(這是一個漫長的跟蹤過程),事情就好辦了。
由於DES為ECB模式,8位元組獨立加密。根據已知條件前8位元組為“kxuectf{”得到加密結果0x4C,0xD9, 0xA3, 0xE6, 0xED, 0xFE, 0xD1,0x05。
由最後一個位元組為“}”, ab.a函式處理後為“{”,所以DES加密的最後8位元組為x,x,x,{,4,4,4,4,其中x為未知數。編寫如下程式碼爆破,得到結果“a>6”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | for ( char i=0x20;i<0x7f;i++)< code=""> for ( char j=0x20;j<0x7f;j++)< code=""> for ( char k=0x20;k<0x7f;k++)< code=""> { str[0] = i; str[1] = j; str[2] = k; memset ( str2, 0, sizeof ( str2 ) ); Des_Run ( str2, str, ENCRYPT ); key1[12]=str2[0]; key1[13]=str2[1]; key1[14]=str2[2]; key1[15]=str2[3]; rc6_key_setup(key1, 16); rc6_block_decrypt(ct, pt); if (pt[0]==stro[0] &&pt[1]==stro[1]) { printf ( "%c%c%c%c\n" ,str[0],str[1],str[2],str[3]); } } |
由此得到正確RC6金鑰{0x65, 0x48, 0x32,0xEF, 0xBA, 0xCD, 0x56, 0x4E, 0x0F, 0x9B, 0x1D, 0x27, 0x13, 0x6a, 0x7e, 0x1F}。
利用此金鑰對0x42D3C3C2, 0xF12AE92D, 0x66C92822, 0x2CEB540E,0x9407E577, 0x4A92B792, 0x2E5DFDF0, 0xF3549FC6解密,得到結果“xkhrpgs}Q4pelcgrq6fI4elyagrer2gv”,加上“a>6{”,即“xkhrpgs}Q4pelcgrq6fI4elyagrer2gv a>6{”為正確的進入so的字串。
透過如下函式爆破。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include char test[] = "xkhrpgs}Q4pelcgrq6fI4elyagrer2gva>6{" ; char getit( char a){ if (a<97 a="">109){ if (a>=48 && a <=57){< code=""> return a^7; } else if (a>=65&&a<=77){< code=""> return a+13; } else if (a>=78&&a<=90){< code=""> return a-13; } else if (a>=110 && a<=122){< code=""> return a-13; } else { return a^6; } } else { return a+13; } } int main(){ for ( int j=0;j<36;j++){< code=""> printf ( "%d " ,j); for ( char a=0x20;;a++){ if (getit(a)==test[j]){ printf ( "%c " ,a); } if (a==0x7f) break ; } printf ( "\n" ); } return 0; } |
得到結果如下。
如果剔除掉特殊字元,得到註冊碼為
“kxuectf{D3crypted1sV3rylntere5tin91}”輸入模擬器,正確。
最後感謝 WiFi 萬能鑰匙安全應急響應中心的贊助支援,
接下來的比賽大家一定要使出洪荒之力哦!↖(^ω^)↗
比心 ❤
上海連尚網路科技有限公司成立於 2013 年,是一家專注於提供免費上網和內容服務的移動網際網路企業。連尚網路自主研發的核心產品 WiFi 萬能鑰匙,以分享經濟的模式,透過雲端計算和大資料技術,利用熱點主人分享的閒置WiFi資源,為使用者提供免費、穩定、安全的上網服務,以幫助更多的人上網,找到屬於他們的機會,改變自己的命運。
相關文章
- 看雪.WiFi萬能鑰匙 CTF 2017第十題 點評及解題思路2017-06-28WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路2017-06-28WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第四題 點評及解題思路2017-06-29WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第三題 點評及解題思路2017-06-29WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第七題 點評及解題思路2017-06-22WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第八題 點評及解題思路2017-06-22WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第十三題 點評及解題思路2017-06-28WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第十一題 點評及解題思路2017-06-28WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第十四題 點評及解題思路2017-06-30WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第十五題 點評及解題思路2017-08-10WiFi
- 看雪.萬能鑰匙 CTF 2017第一題 WannaLOL 解題思路2017-06-29
- 萬能wifi鑰匙2020-12-24WiFi
- 看雪.騰訊TSRC 2017 CTF 秋季賽 第二題點評及解析思路2017-10-28
- 看雪.騰訊TSRC 2017 CTF 秋季賽 第三題點評及解析思路2017-10-30
- 看雪.騰訊TSRC 2017 CTF 秋季賽 第七題點評及解析思路2017-11-07
- 看雪.騰訊TSRC 2017 CTF 秋季賽 第八題點評及解析思路2017-11-09
- 看雪.騰訊TSRC 2017 CTF 秋季賽 第五題點評及解析思路2017-11-03
- 看雪.騰訊TSRC 2017 CTF 秋季賽 第四題點評及解析思路2017-11-02
- 看雪.騰訊TSRC 2017 CTF 秋季賽 第六題點評及解析思路2017-11-06
- 看雪.騰訊TSRC 2017 CTF 秋季賽 第九題點評及解析思路2017-11-13
- WiFi萬能鑰匙安全應急響應中心贊助看雪 CTF 安全攻防大賽,5 萬大獎等你來拿!2017-05-24WiFi
- 看雪.紐盾 KCTF 2019 Q3 | 第十二題點評及解題思路2019-10-08
- WiFi萬能鑰匙蹭網原理詳細剖析2020-08-19WiFi
- 看雪CTF.TSRC 2018 團隊賽 第十二題『移動迷宮』 解題思路2018-12-25
- WiFi萬能鑰匙加入“中國網路安全產業聯盟”2017-07-05WiFi產業
- 看雪.紐盾 KCTF 2019 Q3 | 第一題點評及解題思路2019-09-25
- 看雪.紐盾 KCTF 2019 Q3 | 第四題點評及解題思路2019-09-29
- 看雪.紐盾 KCTF 2019 Q3 | 第七題點評及解題思路2019-09-30
- 看雪.紐盾 KCTF 2019 Q3 | 第六題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第八題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第九題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第十題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q2 | 第九題點評及解題思路2019-07-04
- 看雪.紐盾 KCTF 2019 Q2 | 第十題點評及解題思路2019-07-05
- 看雪.紐盾 KCTF 2019 Q2 | 第一題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第二題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第三題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第五題點評及解題思路2019-07-01