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特权执行用户空间代码完成提权等操作
