前言
这是一道XCTF分站赛ACTF的内核题目😮
CHECK
基础配置
竟然没开smap和smep😮,后来据出题人说这是失误😊
init如下:
可以看到设备的名字使/dev/arandom;
cache
似乎没有cg隔离🤔
逆向分析
函数__kmalloc_noprof:
https://elixir.bootlin.com/linux/v6.14.2/source/mm/slub.c#L4304
全局变量AAA
init
可以看到AAA的三个成员在最开始的时候都被初始化为随机值;
IOCTL
ioctl接口提供了如下5个功能:
get_info
可以通过ioctl的的这个接口获取AAA的三个随机值;
alloc
只有一次alloc的机会,可以看到分配的obj的大小使随机值,根据前面的init可以看到这个随机值的大小是在1~0x8000之间。
free
释放只有一次机会,buffer没有清零;
edit
可以造成uaf;随机偏移写4字节数据;
leak
可以向分配的内存中写入一个内核函数的值,这里可以被用作uaf写,然后读出这个地址用于泄露;
调试
调试相关用到的地址如下:
bash-5.2# cat /proc/kallsyms | grep arandom
ffffffffc0203040 d arandom_miscdev [arandom]
ffffffffc0201010 t arandom_release [arandom]
ffffffffc0201040 t arandom_open [arandom]
ffffffffc0201070 t arandom_ioctl [arandom]
ffffffffc02031c0 d arandom_mutex [arandom]
ffffffffc0203710 b buffer [arandom]
ffffffffc020370d b allocated [arandom]
ffffffffc020370c b freed [arandom]
ffffffffc0201230 t arandom_exit [arandom]
ffffffffc02031e0 d __UNIQUE_ID___addressable_cleanup_module276 [arandom]
ffffffffc02030a0 d arandom_fops [arandom]
ffffffffc0201000 t __pfx_arandom_release [arandom]
ffffffffc0201030 t __pfx_arandom_open [arandom]
ffffffffc0201060 t __pfx_arandom_ioctl [arandom]
ffffffffc0201220 t __pfx_arandom_exit [arandom]
ffffffffc020516c r _note_19 [arandom]
ffffffffc0205184 r _note_18 [arandom]
ffffffffc020519c r orc_header [arandom]
ffffffffc0203200 d __this_module [arandom]
ffffffffc0203700 b AAA [arandom]
ffffffffc0201230 t cleanup_module [arandom]
ffffffffc0201220 t __pfx_cleanup_module [arandom]
在分配后的地方查看cache,感觉怪怪的🤔:
漏洞利用
LEAK
通过分析发现,当我们分配的内存大小超过了0x2000字节之后,就超过了最大的cache——kmalloc-8k了,这个时候笔者分析应该是从buddy system中直接分配的,因此笔者在利用上述uaf漏洞之后使用pipe的页占有这个页,然后利用uaf写内核函数地址的方法将这个地址写入到pipe的页中,之后利用pipe的读功能即可实现地址的泄露:
这里笔者用的方法是每个pipe只写一个页的内容,然后通过读、比对,来找到命中的pipe页,这个页我们后边还会有用。😊
这里可能是pipe的数量不够?总之笔者通常要运行两次到三次才能泄露出来内核地址。
控制流劫持
下面我们要通过修改pipe的大小为0x8000(其实笔者前面还用别的size喷射了,但是最终发现都会落在0x8000的上面),以此来修改pipe_buffer的大小,这样就可以喷射大量的pipe_buffer,从而导致kmem_cache-512从buddy system中将我们的uaf-page回收回来,这样我们就可以通过题目给我们提供的uaf写随机数来写pipe_buffer的空间啦!😊
但是现在问题来了,写的内容是随机数,因此笔者使用了如下小trick:
笔者首先需要撞这个随机数,保证这个随机数能够被卸载pipe_buffer的8个ops中的一个(不用完全对应,只要8字节中的部分字节被修改了就有机会),然后笔者可以在一开始就根据get_info得到的随机数的值推断出ops的位置被写成了什么,然后我们将这个值通过mmap映射成一个合法的用户态地址,由于没有smap的保护,我们可以直接在这个用户态地址中部署fake ops,然后还由于没有开启smep保护,我们直接一步ret2usr!😊
远程攻击
由于环境中没有lib库,因此笔者使用musl-gcc进行编译,然后就是一通撞,最终攻击成功:
ACTF{Y0u_h4v3_b3c0m3_4_m4573r_0f_r4nd0m_num83r5}
EXP
|