House Of Einherjar
正常free的时候会判断上一个chunk是不是free的,是的话就合并
让指针对 本chunk处-pre_size处的chunk 执行unlink,把本chunk和pre_chunk都从bin链条中脱出
1 | /* consolidate backward */ |
那么如果我们可以同时控制一个 chunk prev_size 与 PREV_INUSE 字段,那么我们就可以将新的 chunk 指向几乎任何位置,记住唤起合并的还是一个unsorted bin的free
可以进行攻击的代码
eg:
1 | #include <stdio.h> |
exp:
1 | from pwn import * |
unlink的校验
1
2 >if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0)) \
malloc_printerr ("corrupted size vs. prev_size");P 的大小必须等于 P 后面那个 chunk 的 prev_size
校验pre_chunk的size是否等于pre_chunk+size处对应的fake_size
这个pre_size也可以是虚构的,不是真实的在那个位置上的
Seccon2016 tinypad
这个代码比较长,都汇在一起
总结就是每次操作后都会显示四个chunk的内容,只能同时存在四个chunk

delete
uaf漏洞,只是把size位置上的数置零

add

edit
思路
先泄露libc_base等计算maloc_hook,利用House of Einherjar构造overlapping chunk,再覆盖fast chunk的fd指针,指向__malloc_hook附近,将__malloc_hook覆盖成one_gadget。
House of Einherjar的构造过程
先把后面的unsorted_bin malloc出来

然后伪造chunk
add_memo(0x60, p64(0) + p64(0xd0) + p64(addr_heap +0x10) + p64(addr_heap +0x10))
这里伪造的fd和bk要用伪造chunk的头部

然后是unlink的size校验,放size

之后再把unsorted bin free唤起consolidation
1 | add_memo(0xf0, b"C" * 0x10) #1 |
之后就是正常的覆盖了
exp
1 | from pwn import * |
polar2023 夕阳下的舞者
这道题通过malloc unsorted bin 再free掉再malloc去取出以拿到libc_base
其它和上面的题目相近,这里粘个脚本
1 | from pwn import * |
House Of Husk
回炉重修之house of husk 带源码深度解析-先知社区
glibc 2.23–2.35
__printf_function_table
正常状态:NULL (0x0)
- 它的角色:这是一个开关标志。
- 存储内容:在正常程序中,它是一个空指针。
- 工作逻辑:当
printf执行时,它会首先检查这个变量。- 如果
__printf_function_table == NULL,printf走标准路径,只识别%s,%d,%f等内置格式。 - 如果
__printf_function_table != NULL,printf就会切换到“扩展模式”,认为用户注册了自定义的格式化字符(比如%y)。
- 如果
__printf_arginfo_table
正常状态:NULL (0x0)
它的角色:这是一个跳转表(函数指针数组)。
存储内容:如果被启用,它会指向一个大小为 256 的指针数组,数组的每个索引对应一个 ASCII 码。
工作逻辑:
当
printf开启了扩展模式,并在字符串中遇到了一个格式化字符(假设是%s),它会去查这个表。它以字符
's'的 ASCII 码(115)作为下标,即访问__printf_arginfo_table[115]。正常设计下:这个位置应该存储一个函数地址。
printf会调用这个函数来询问:“嘿,遇到%s时,我应该读取几个参数?每个参数是什么类型?”所以如果把__printf_arginfo_table[115]改成后门就会在printf(%s)时调用后门
👉 “利用程序中对格式化字符串(尤其是 %s / %n)的错误使用,把本来用来‘打印数据’的功能,变成‘读内存甚至写内存’的工具,从而控制程序执行流程。”
1 | 你有任意写能力 |
👉 “开表(function_table),改表(arginfo_table),借 printf 执行后门。”
easy_str

add限制只能malloc5个chunk,存在uaf漏洞,但是还有一个printf(“%X”, 0);比较特殊
house of husk
先把global_max_fast扩大,让free的chunk可以覆盖printf_function_table以及printf_arginfo_table,将其覆盖为后门
先泄露libc并且准备覆盖printf_function_table以及printf_arginfo_table的chunk
1 | add(0x500) |

因为chunk是16字节对齐的,所以distance*2
index = (chunk_size- 0x10) >> 4

之后利用uaf漏洞改unsorted bin的chunk地址让chunk malloc到global_max_fast
把global_max_fast改成一个大数,然后让chunk1和chunk2进入并且覆盖__printf_arginfo_table[0x58]为onegadget
1 | edit(0,p64(libc_base+0x3ed940-0x10)*2) |



exp
1 | from pwn import * |