首頁>科技>

雖然我們已經知道這是一個棧溢出,但在沒有逆向輔助的情況下,需要逐字節增加進行爆破,直到程序崩潰。此時buf(64)+ebp(8)=72字節。由於程序沒有開啟canary,就跳過爆破過程。

首先,我們需要找到stop gadget,這在程序中可能會存在多個,任選一個即可。

該stop gadget之所以有效是因為調用了puts()函數(忽略前三條無效指令),執行完之後不會導致程序崩潰,維持了socket的連接。其實原程序正確的偏移應該是0x4005e0。我們從0x400000開始搜索,是因為程序沒有啟用PIE,所以會被加載到這個默認地址。

通過stop gadget,我們就可以根據需要尋找其他有用的gadgets。由於是64位程序,考慮尋找通用gadget,偏移0x9字節的地方就是賦值RDI寄存器的“pop rdi;ret”。

接下來,尋找用於內存轉儲的函數,這裡是puts(),比起write(),它只需要一個參數。為了分辨gadgets,可以打印出地址0x400000的內存,這裡就是程序的開頭,前4個字符為“\x7fELF”。

這裡找到了一條call puts指令,“call”將返回地址壓棧,然後跳轉到puts@plt 0x004005f0,這樣做相比直接跳轉到puts@plt可能會更穩定。然後就可以轉儲內存了。

由於puts()函數會被“\x00”截斷,並且在每一次輸出末尾會加上換行符“\x0a”,所以有一些特殊情況需要處理。首先,去掉末尾自動添加的“\n”;其次,如果收到單獨一個“\n”,說明此處內存是“\x00”;再次,如果收到一個“\n\n”,說明此處內存是“\x0a”。p.recv(timeout=0.1)使用了超時是因為函數本身的設定,在接收“\n\n”時,它很可能收到第一個“\n”就返回了,加上超時可以讓它全部接收完。

這裡選擇的內存範圍從0x400000到0x401000,對於本題已經足夠了。如果需要轉儲.data段的數據,那麼大概從0x600000開始。在使用radare2打開轉儲文件時,使用“-B”參數可以指定程序基地址。這樣我們就得到了puts@got地址0x00601018。

到這裡我們就相當於拿到了二進制文件,只是缺少libc。解決辦法是先調用puts()打印出保存在puts@got裡的內存地址,然後在libc-database裡查詢匹配的libc.so,進而計算得到system()和“/bin/sh”的偏移。

最後,調用system("/bin/sh")即可獲得shell。

解題代碼

8
最新評論
  • 整治雙十一購物亂象,國家再次出手!該跟這些套路說再見了
  • 短視頻日活用戶量有6億,為什麼你還是很長時間沒做好?