init_array與got劫持——[zer0pts 2020]easy strcmp

demo41發表於2024-06-09

只是在順思路,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}

相關文章