只是在順思路,wp參考了2位大佬
文章列表 | NSSCTF
[Zer0pts2020]easy strcmp 分析與加法-CSDN部落格
題目
Die
虛擬機器執行一下
沒有輸入,直接報錯退出了
IDA
很奇怪啊,就是一個比較
從我們執行直接報錯來看,我們執行時a1>1這個條件是不成立的
我的最初思路就是除錯把a1改了或者把判斷彙編指令改了,讓我進入if裡面看看
IDA動調
下好斷點
改彙編
F8到strcmp,繼續F8,出現一個彈窗
55BB41600714:得到 SIGSEGV 訊號(分段違規)(exc.code b,tid 4929)
點選OK,跳到了一個地方
F5
這個函式進行了一個簡單的每位相減操作,這裡應該就是加密函式,加密後的資料要與zer0pts{********CENSORED********}相等
如果是解題的話,思路不是很難
真正讓我思考的是NSSCTF師傅的幾行字—— 這道題的考點與原理是什麼?
知識點
1. init_array
- init_array 是一個段(section),在很多作業系統和編譯器中,這個段會包含程式啟動時需要執行的一些初始化函式。
- 當一個程式啟動時,作業系統或執行時會依次呼叫這些函式。開發者可以把一些初始化程式碼放在這些函式中,以便在主程式(main函式)執行之前執行。
2. GOT劫持
- GOT 全稱是 Global Offset Table(全域性偏移表),它是用來實現動態連結庫(DLL)的一種機制。
- 在程式執行時,函式的實際地址會被載入到 GOT 中。每次呼叫動態連結庫中的函式時,程式會透過 GOT 找到函式的實際地址。
- GOT劫持 是一種常見的攻擊技術,透過修改 GOT 中的函式地址,將其指向攻擊者的程式碼,從而劫持函式的執行流。例如,將一個常用函式(如
strcmp
)的地址改為攻擊者的程式碼地址。解題思路
1. 在init_array中hook了strcmp
- hook 是一種技術,允許開發者或攻擊者攔截並替換函式的執行。在這個題目中,透過修改 init_array 段中的某個初始化函式,將
strcmp
函式進行 hook(攔截)。- 具體來說,可能是程式在初始化時,修改了 GOT 中
strcmp
的地址,將其指向一個自定義的函式。2. 分析hook程式碼,得到flag
-
需要找到並分析這個自定義的函式,看看它如何攔截
strcmp
的呼叫。 -
通常,這個自定義的函式會包含一些邏輯,用於檢查輸入或直接返回某個特定的值(如 flag)。
-
透過逆向分析這個自定義函式,理解它的行為,從而找出程式隱藏的 flag。
那看看init函式
發現for迴圈裡面,將funcs_889地址作為指標,進行呼叫
這裡剛好就是init_array
(題外話:我搜尋了一下IDA中怎麼找init_array,但是隻找到安卓的教程,知道的師傅可以告訴我嗎?)
第一個sub_6E0,追蹤進去沒什麼東西,重點在第二個sub_795
它把strcmp的地址賦給了qword_201090
這個qword_201090有沒有覺得很熟悉?
所以return中進行的才是真正的比較函式,這也再次坐實了a1就是加密後的資料,a2就是zer0pts{********CENSORED********}——加密後的資料與其比較
接下來看看strcmp在got表中的地址:00000000002010B0
接著紅框裡的程式碼,sub_6EA就是加密函式
off_201028在IDA中其實就等於00000000002010B0
不過不知道也沒事,跟蹤一下off_201028
off_201028在_got_plt中原本應該指向strcmp的地址,但是在sub_795被改成指向加密函式sub_6EA
到這裡我才完全搞懂了大佬說的知識點與解題思路是什麼意思——在初始化的時候,init_array中呼叫sub_795,將原本在got_plt中存放strcmp的地址改成sub_6EA,而真正的strcmp變成了qword_201090
EXP
cipher = bytearray(b"zer0pts{********CENSORED********}") key = [ 0, 4686632258374338882, 796841318371695088, 5695428477452625963, 0 ] # 將 cipher 視為 unsigned long long 的陣列 for i in range(5): # 將前8個位元組轉換為 unsigned long long value = int.from_bytes(cipher[i*8:(i+1)*8], 'little') # 進行加法操作 value += key[i] # 將結果轉換回位元組並存入 cipher cipher[i*8:(i+1)*8] = value.to_bytes(8, 'little') print(cipher.decode())
flag
zer0pts{l3ts_m4k3_4_DETOUR_t0d4y}