-
-
[原创]BCTF 2018 House of Atum分析
-
发表于: 2021-8-27 18:51 11811
-
这道题主要考察tcache bin、double free、伪造chunk并利用、glibc中chunk分配与释放机制等知识点熟练掌握和运用程度,比较典型,值得深入研究。
一、house of Atum结构分析
二、Double Free 利用
(一)分析基础
(二)泄露heap地址
(三)伪造chunk
(四)泄露libc地址
三、劫持_free_hook函数
四、总结
house of Atum共有4个功能,分别为新建(new)、编辑(edit)、删除(delete)、显示(show),其中alloc()函数最多只能分配2个堆块(0x48字节),漏洞函数存在于del()函数中,当clear操作选择'n'时,不会将notes数组上的指针置0,存在UAF漏洞。
关键函数部分代码如下:
notes[i]指针指向分配的chunk数据区,readn函数直接读入0x48个字符串,没有对字符串末尾进行截断处理,只对字符串末尾添加'\0a',导致存在泄露内存地址的可能。
选择删除(delete)时,如果在clear选项后面选择'n',notes[v1]将不会置0,导致存在uaf漏洞。
以上就是有用的信息,我们所能执行的操作就限定在以上范围之中。
给定一个这样的题目,怎们办?根据已有的知识,存在uaf漏洞,那么就可以触发double free,double free后,位于tcache bin中的chunk的next指针将指向next所在位置,即指向自己。从这点出发,我们可以动态得到next指针的值。
我们的目标是最终执行system('/bin/sh'),而且是通过堆来完成。上一篇《HITB CTF 2018 gundam分析》中,我们通过动态获得libc基地址,进而计算出_free_hook地址和system地址,想方设法在_free_hook地址处写入system地址,再创建1个内容为'/bin/sh'的chunk,然后释放,就可以触发_free_hook,最终执行system('/bin/sh')。这道题同样可以采取这种思路。1.要动态获得libc基地址,就要用到unsorted bin,在tcache的count为7的情况下,将符合unsorted bin大小的chunk释放到unsorted bin中。该chunk前向指针fd和后向指针bk的值就是要泄露的地址(详细分析见上一篇《HITB CTF 2018 gundam分析》)。
2.题目中创建的house of Atum chunk的大小为0x51。显然,这样chunk释放后只能进入tcache bin和fast bin,要想使其进入unsorted bin,就得改变指定chunk的大小。
3.要在_free_hook地址处写入system地址,就得构建1个以_free_hook地址为数据区地址的chunk,即_free_hook-0x10为起始地址的chunk,以system地址作为内容参数。
以下分析和调试过程基于以上3点考虑,通过对堆块chunk的灵活操作,成功执行获得shell。
我们知道,创建house of atum chunk时,系统分配的chunk大小为0x51,如果只创建1个chunk,size为0x51的chunk后面紧跟着top chunk。而我们后面还要改写指定chunk的size大于fastbin的最大值0x80,显然只申请1个大小为0x51的chunk,并在这唯一一个chunk上来回操作是不能满足要求的。
考虑到2个chunk的大小加起来为0xa1,后面需要紧跟着1个大小为0x11的chunk来标识前一chunk的prev_inuse状态,故后续操作中将指定chunk的大小由0x51改为0x91。开始先申请2个chunk,chunk0的内容为一个字符‘A’,chunk1的内容为p64(0)*7+p64(0x11),即56个字节的0,加上1个长度为8个字节的0x11,把chunk0、chunk1看作1个大的chunk正好满足后面将chunk0的大小改为0x91的要求。
这里需要特别注意的是:chunk1最后8个字节必须是p64(0x11),而不能是p64(0x10)。如果是p64(0x10),后面释放7次大小为0x91的chunk0时,chunk0能够正常释放到tcache中,但是第8次再释放该chunk0时,会出现错误,而错误的原因就是把0x11写成了0x10。通过查看glibc的源代码,在_int_free()函数中,存在以下代码:
在chunk被释放到unsorted bin之前系统会通过下一个chunk的prev_inuse标志位来检查该chunk是否已经被释放。写成0x10之后,glibc检测发现prev_inuse为0,就会触发异常"double free or corruption (!prev)",而在放入tcachebin之前是没有这种检查机制的。
以上分析是以下所有chunk操作的起点。
1.先将chunk1释放到0x51大小的tcache中;
2.连续将chunk0释放6次,chunk0将放入0x51大小的tcache中,同时chunk1将从tcache中移除,chunk0的next指针将指向自身next地址,通过show('0'),可以获得chunk0的内容,即next指针地址,定义为heap_addr。
动态获得了heap_addr,即chunk0的next指针,后面该如何利用?
根据前面分析,要获得libc的基地址,就要改变chunk0的大小为0x91。chunk0的size域位于chunk0头部16个字节的后半部分中,可以考虑创建1个以chunk0-0x10为起始地址的chunk1,将chunk0的新的size值(0x91)作为chunk1的内容。要从tcachebin中分配chunk1时,前提是chunk1在tcachebin中,有两种方式可以使chunk1(chunk0-0x10为起始地址)进入tcachebin:一种是释放已经存在的chunk1到tcache中,另一种是将chunk1链接到fastbin中某个chunk后面,这样当chunk被从fastbin中分配时,其后面的chunk1就会被移到tcache中。显然前一种方式不现实,我们采用第二种方式。
通过前面7次释放chunk,tcachebin 已有7个chunk,再释放1次chunk0,chunk0将进入fastbin。这时,chunk0同时存在于fastbin和tcachebin中。
chunk0进入fastbin后,我们继续按上面的思路走。创建chunk,chunk0将从tcachebin中分配,将p64(heap_addr-0x20)作为参数写入chunk0数据区,fastbin中的chunk0后面链接着以heap_addr-0x20为起始地址的chunk。此时tcache中count变成了6,并且tcache为空。
从上图可以看到,fastbin中增加了1个chunk(从heap_addr-0x20开始)。
此时,如果我们再申请创建1个chunk,即chunk1,该chunk将会从fastbin中分配,同时fastbin中的剩余chunk将会移到tcachebin中。
由于tcachebin中next指针指向chunk的数据区,fastbin中next指针指向chunk起始地址(两者相差0x10),因此写入tcache的entries的值为heap_addr-0x10,即chunk0起始地址。
再释放掉chunk1,chunk1会进入fastbin中。
到目前为止,我们已经成功实现伪造chunk(heap_addr-0x20作为起始地址),并使其进入tcachebin。如果我们再次申请创建chunk,chunk1将会从tcache中分配。在这里,我们把p64(0)+p64(0x91)作为参数创建chunk,chunk1(从heap_addr-0x20开始)的数据区heap_addr-0x10处将会写入0x91,heap_addr-0x10正是chunk0的起始地址,成功改变chunk0的大小为x91。
连续释放chunk0 7次,将会使chunk0进入0x91大小的tcachebin中,再释放1次,chunk0将会进入unsortedbin。
根据上一篇《HITB CTF 2018 gundam分析》,chunk0+0x10处的以7f开头的地址就是泄露的地址。
而libc的基地址如上图标红处所示,为0x7fe3b0f45000,由此可以计算出libc基地址与泄露的指向unsortedbin的fd指针之间的偏移为:
泄露地址0x00007fe3b12f0c78-libc基地址0x7fe3b0f45000=0x3abc78,进而可以计算出__free_hook函数地址和system函数地址。
第一部分第3点我们谈到,要在_free_hook地址处写入system地址,就得构建1个以_free_hook地址为数据区地址的chunk,即_free_hook-0x10为起始地址的chunk,以system地址作为内容参数。
我们知道fastbin中chunk被分配后,该chunk后面链接的chunk会被移到tcachebin中,后面再分配chunk时,移到tcache中的chunk会被分配。我们继续按这个思路分配和释放chunk。
此时我们完成了libc基地址的获取,需要将chunk0的大小从0x91改回到0x51,以便创建大小为0x51的house of atum chunk。
从上图可以看到fastbin中chunk0后面链接的是指向unsortedbin的指针,如果我们将链接的指针修改为__free_hook-0x10,那么再创建大小为0x51的chunk时,glibc会从fastbin中分配chunk0,同时将_free_hook地址写入tcache。
如何将chunk0大小改回到0x51并修改chunk0后面的链接指针?我们继续使用前面伪造的chunk1(从heap_addr-0x20开始),利用house of Atum 程序的edit功能,将chunk1的内容编辑为p64(0)+p64(51)+_free_hook-0x10,成功实现修改chunk0大小和chunk0后面链接指针的目的。
继续创建大小为0x51的chunk,chunk0将从fastbin中分配,同时_free_hook地址被写入0x51大小的tcache中。
释放chunk0,chunk0被释放到fastbin中,再次申请创建chunk0, 将从tcache中分配chunk0(_free_hook-0x10开头),以system函数地址为参数,把system函数地址写入_free_hook地址,实现_free_hook函数与system函数的绑定。
释放伪造的chunk1,再次创建chunk1,chunk1将从fastbin中分配,以‘/bin/sh\x00’为参数,字符串‘/bin/sh\x00’被写入chunk1数据区。
再次释放chunk1,实际上执行del操作的前两步,触发_free_hook函数,最终执行system(‘/bin/sh\x00’),成功得到shell。
本题的解题思路是从题目本身出发,分析题目本身能够直接获取的信息,然后思考如何建立与解题目标(成功获得shell)之间的联系,包括如何利用double free后得到泄露的heap_addr?为什么以及如何伪造以heap_addr-0x20开头的chunk?如何从伪造的chunk出发获得泄露的libc基地址?弄清这些内在联系对于逆向解题至关重要。网上流传较多的版本是最后通过one_gadget获得系统控制权,本文采用执行system函数的方式成功实现这一目的。
int
alloc()
{
int
i;
/
/
[rsp
+
Ch] [rbp
-
4h
]
for
( i
=
0
; i <
=
1
&& notes[i];
+
+
i )
;
if
( i
=
=
2
)
return
puts(
"Too many notes!"
);
printf(
"Input the content:"
);
notes[i]
=
malloc(
0x48uLL
);
readn((void
*
)notes[i],
0x48LL
);
return
puts(
"Done!"
);
}
int
alloc()
{
int
i;
/
/
[rsp
+
Ch] [rbp
-
4h
]
for
( i
=
0
; i <
=
1
&& notes[i];
+
+
i )
;
if
( i
=
=
2
)
return
puts(
"Too many notes!"
);
printf(
"Input the content:"
);
notes[i]
=
malloc(
0x48uLL
);
readn((void
*
)notes[i],
0x48LL
);
return
puts(
"Done!"
);
}
unsigned __int64
del
()
{
int
v1;
/
/
[rsp
+
0h
] [rbp
-
10h
]
char v2[
2
];
/
/
[rsp
+
6h
] [rbp
-
Ah] BYREF
unsigned __int64 v3;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v3
=
__readfsqword(
0x28u
);
printf(
"Input the idx:"
);
v1
=
getint();
if
( v1 >
=
0
&& v1 <
=
1
&& notes[v1] )
{
free((void
*
)notes[v1]);
printf(
"Clear?(y/n):"
);
readn(v2,
2uLL
);
if
( v2[
0
]
=
=
'y'
)
notes[v1]
=
0LL
;
puts(
"Done!"
);
}
else
{
puts(
"No such note!"
);
}
return
__readfsqword(
0x28u
) ^ v3;
}
unsigned __int64
del
()
{
int
v1;
/
/
[rsp
+
0h
] [rbp
-
10h
]
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
- [原创]large chunk分配过程调试 12781
- [原创]BCTF 2018 House of Atum分析 11812
- [原创]HITB CTF 2018 gundam分析 17315
- [原创][原创]Unsorted Bin 利用后续 5785