2018强网杯 - core
程序提取
提取镜像:
1 | mkdir core |
在目录下有一个 gen_cpio.sh
,内容如下:
1 | find . -print0 \ |
可以发现是一个方便打包的脚本,我们添加如下代码:
1 | mv ../exp ./tmp/exp |
然后使用如下命令重打包:
1 | ./gen_cpio.sh core.cpio |
之后修改 start.sh
脚本
1 | sudo qemu-system-x86_64 \ |
运行即可
程序分析
ioctl
函数有三个功能:
- 0x6677889B :调用
core_read
函数 - 0x6677889C :设置
off
变量 - 0x6677889A :调用
core_copy_func
函数
其中 core_read
函数如下:
其可以读出栈上的内容,用于泄漏 cannary
core_copy_func
函数如下:
会从 name
开始读取 a1
长度的内容到栈上造成栈溢出
然后是 core_write
函数,可以向 name
处写入任意大小的数据
漏洞利用
首先修改 init
脚本,使其以 root
启动:
1 |
|
注意到我们可以通过读取 /tmp/kallsyms
文件来得到函数地址
1 | size_t commit_creds = 0, prepare_kernel_cred = 0; |
然后通过一下命令获得 .text
段的地址
1 | / # cat /sys/module/core/sections/.text |
我们便可以在 gdb
中设置基地址
1 | pwndbg> add-symbol-file ./core.ko 0xffffffffc018b000 |
回到漏洞利用,首先我们通过 ioctl
设置 off
,然后使用 core_read
函数来带出输入:
1 |
|
得到结果:
1 | [+] Open fd |
之后通过 core_write
将 payload
写入 name
,然后通过 core_copy_func
栈溢出来 rop
即可:
1 | // gcc exp.c -static -masm=intel -g -o exp |
其中的 gadgets
我们可以通过下面的指令收集:
1 | ropper -f vmlinux --nocolor > gadget.txt |
然后这里:
1 | rop[i++] = offset + 0xffffffff81000b2f; // pop rdi; ret |
之所以需要 pop rcx; ret
是因为 call rdx
的时候会将该指令的下一条指令 push
到栈顶(方便之后 ret
回来),所以其可以将下一条指令吃掉然后直接调用 commit_creds
至于之后的:
1 | rop[i++] = offset + 0xffffffff81a012da; // swapgs; popfq; ret |
这是为了:
- 通过
swapgs
指令恢复用户态GS
的值; - 通过
sysretq
或者iretq
指令恢复到用户控件继续执行;如果使用iretq
指令则还需要给出用户空间的一些信息(CS, eflags/rflags, esp/rsp
等);比如这里利用的iretq
指令,在栈中就给出CS,rflags,sp,ss
等信息:
Ret2usr
另外还有一种 ret2usr
的做法:
1 | // gcc exp.c -static -masm=intel -g -o exp |
可以很清楚的看出来其是先返回到了用户态然后再进行的commit_creds(prepare_kernel_cred(0))
ret2usr
攻击利用了 用户空间的进程不能访问内核空间,但内核空间能访问用户空间 这个特性来定向内核代码或数据流指向用户控件,以ring 0
特权执行用户空间代码完成提权等操作