ZCTF note3:一種新解法

最近在學習unlink做到了這道題,網上有兩種做法:一種是利用edit功能讀入id時整數溢出使索引為-1,一種是設置塊大小為0使得寫入時利用整數溢出漏洞可以將數據溢出到下一個塊中 。我采取了另一種思路:程序在分配id=7塊時雖然提示塊已滿 , 但沒有采取措施,依然分配了一個塊,并將塊地址放在了存放塊0 size的位置,使得可以往塊0寫入足夠多的數據溢出到下一個塊中 。
我先分析我的解法,然后再簡單敘述一下另外兩種解法的原理 。
程序分析一般步驟查看程序保護措施 。

ZCTF note3:一種新解法

文章插圖
該程序有4個功能:
  • New note
  • Show note(假的,只打印一個字符串)
  • Edit note
  • Delete note
New功能添加note函數如下圖,主要流程已通過注釋標注 。值得注意的是當i=7時,雖然提示note已滿,添加失敗,但沒有return語句,后面依然為它分配塊并將地址保存在&ptr+7處 。(注意:i=0時塊的size保存在qword_6020C0[0+8]處)
ZCTF note3:一種新解法

文章插圖
需要關注的是qword_6020C0和ptr的關系,其內存關系如下所示
.bss:00000000006020C0 ; __int64 qword_6020C0[].bss:00000000006020C0 qword_6020C0    dq ?                    ; DATA XREF: sub_400A30+D1↑w.bss:00000000006020C0                                         ; sub_400A30+E6↑w ....bss:00000000006020C8 ; void *ptr.bss:00000000006020C8 ptr             dq ?                    ; DATA XREF: sub_400A30+16↑r.bss:00000000006020C8                                         ; sub_400A30+BC↑w ....bss:00000000006020D0                 dq ?.bss:00000000006020D8                 dq ?.bss:00000000006020E0                 dq ?.bss:00000000006020E8                 dq ?.bss:00000000006020F0                 dq ?.bss:00000000006020F8                 dq ?.bss:0000000000602100                 dq ?.bss:0000000000602108                 dq ?可以看到ptr所在位置等同于qword_6020C0[1]所在位置,所以當i=7時分配的塊地址保存在&ptr+7等同于保存在qword_6020C0[8]處,即表示i=0塊的大小 。通過分配i=7塊可實現i=0塊大小被新分配塊地址覆寫,而塊地址所代表的大小足夠我們溢出到后面的塊內 。
Show功能該功能沒什么用,只打印一串字符串 。
ZCTF note3:一種新解法

文章插圖
Edit功能如圖,主要操作通過注釋的方式介紹 。
ZCTF note3:一種新解法

文章插圖
Delete功能
ZCTF note3:一種新解法

文章插圖
qword_6020C0[0]可以理解為最近操作過的塊地址 。
漏洞利用漏洞利用思路如下:
1.unlink
添加7個塊后 , 再添加一個塊(i=7),這時塊0的大小會被改的很大(值為塊7的地址) , 然后在塊0中構造fake_chunk并溢出到下一個塊修改header數據實現unlink 。需要注意第i=1個塊時大小要超過fastbin的范圍 。
2.泄露地址
unlink后可以實現任意寫 。為了泄露函數地址 , 需要執行輸出函數,可以將free@got值改為puts@plt值,然后將塊i的地址改為puts@got的地址,這時調用刪除功能free(塊i)就可以輸出puts@got的值 , 從而得到動態鏈接庫加載地址,進一步得到system地址 。

推薦閱讀