Unlink
Principle
将堆块从双向链表(smallbin&unsortedbin)中取出时会合并,触发unlink操作,这个过程中存在漏洞(详情参考源码),有两个检查需要绕过
size检查
第一个要检查的是需要解链bin的size。在堆中有两个地方存储了p的size。第一个是当前p->size。第二个是next_chunk§->prev_size。比较两个大小。
fd和bk检查
检查p是否在双向链表中。在双向链表中有两个指针指向p。第一个是FD->bk,第二个是BK->fd。
Premise
存在small bin或unsorted bin大小的chunk
可以改写fd&bk指针
Exploit
1. UAF
利用条件
- 存在UAF可以修改p的fd和bk
- 存在一个指针指向p
利用方法
- 通过UAF漏洞修改chunk0->fd=G_ptr-0x18,chunk0->bk=G_ptr-0x10,绕过fd和bk检查
- free下一个chunk,chunk0和chunk1合并,chunk0发生unlink,修改了G_ptr的值
2. 堆指针可知
利用条件
- 可以修改p的下一个chunk->pre_size和inuse位
- 存在一个指针指向chunk p的内容部分
利用方法
- 伪造fake_chunk。fakechunk->size=chunk0-0x10,可以绕过size检查。fakechunk->fd=&G_ptr-0x18,fakechunk->bk=&G_ptr-0x10,绕过fd和bk检查。
- 修改下一个chunk的prev_size=chunksize§-0x10。因为fakechunk比chunk0小0x10。
- 修改下一个chunk的inuse位。
- free下一个堆块chunk1。fakechunk和chunk1合并,fakechunk发生unlink,修改了G_ptr的值。
Example
stkof
RELRO: Partial RELRO
PIE: No PIE (0x400000)
1–>add 2–>edit 3–>free 4–>check
2明显存在堆溢出,3指针置零且在bss段
利用思路:fake –> free chunk–>hijack free@got–>”free” ‘/bin/sh’
起手式
1 | import requests |
先创建几个chunk看下堆布局
1 | pwndbg> parseheap |
可以看见chunk0于chunk1间出现了一个大堆块,是由于未进行setbuf操作造成的
但是可以知道我们这里无法利用chunk0进行后续操作
1 | pwndbg> x/10wx 0x00602140 |
因此,这里我们可以选取0x602150
1 | #fake fd&bk |
Before Edit
After Edit
Free chunk2 触发 unlink
可以看见chunks中原本指向chunk1的地方变成了chunk1-0x18,因此我们修改chunk
现在我们可以往bss端上写东西,也就是可以控制chunks中元素了
进一步地,我们把chunks[0]改成got,就能劫持got
1 | payload2 = p64(0)*2+p64(free_got)+p64(puts_got) |
我们能够随意调用的函数唯有free耳,故劫持free为puts用来打印got表可以实现leak
可以看见原本chunks[0]的地方变成了free@got,chunks[1]的地方变成了puts@got
1 | #Overwrite free@got with puts@plt |