-
-
[原创]CVE-2017-5123 waitid本地提权分析
-
发表于:
2018-9-26 15:34
9629
-
[原创]CVE-2017-5123 waitid本地提权分析
最近研究linux kernel pwn的时候发现网上有的文章对cve-2017-5123的分析存在错误,就想着自己复现一下写篇博客,最简单的利用exp无 smep
内核定义了一系列函数与用户态内存进行交互,包括copy_from_user ,copy_to_user,put_user等,这些函数中会调用access_ok检查传入的地址是否属于用户区,之后调用user_access_begin() user_access_end分别开启和禁用smap。为了减少检查开销,linux内核定义了unsafe_put_user函数,但waitid在调用前没有进行access_ok检查,因此可以传入内核地址,任意内核写,但是利用条件会将第一个int写为0x11,第二个int写为0.因此采取的方法是改写have_canfork_callback变量。将其第一个字节改为0x11进而执行未定义的can_fork,并mmap 0地址,写入shellcode。完成提权。 此次利用必须在关闭了mmap_min_addr 和 smep保护的前提下。 参照github上的利用代码进行分析 https://github.com/nongiach/CVE/blob/master/CVE-2017-5123/exploit/exploit_null_ptr_deref.c
fork系统调用最终会调用do_fork,在do_fork中,会调用copy_process函数为子进程复制一份进程信息。
copy_process源码中调用了cgroup_can_fork函数。
cgroup_can_fork函数中调用了do_each_subsys_mask()
do_each_subsys_mask会调用for_each_set_bit函数
for_each_set_bit会调用find_first_bit和find_next_bit,会搜索传入的have_canfork_callback变量,最终返回值ssid是位图中小于cgrou_subsys_count的最后一位1的索引值。
cgroup_subsys是一个全局的cgroup_subsys struct的数组,其中保存了一系列函数指针。cgroup需要用户自定义,未定以,其can_fork函数指针为null。cgroup_can_fork也不会调用cgroup_subsys的can_fork,而是直接返回0。但是waitid将第一个字节改写为0x11 即010001。默认的CGROUP_SUBSYS_COUNT值为4,因此会调用第一个cgroup_subsys的canfork,即0地址。此时,利用代码mmap了0地址,并将shellcode放置在0地址处,fork即可劫持控制流,完成提权。
采用qume起系统,gdb调试
用这个脚本生成kallsyms
在kallsyms中搜索cgroup_can_fork地址,并在gdb中下断点。
随便运行一条命令,bash会调用fork,在我们的断点处停下,查看汇编代码:
0xffffffff81f3f45a处即为全局变量have_canfork_callback变量。之后打印调用了find_first_bit之后的返回值
可以看到,如果返回值大于三即跳转到结束处。可见cgroup_subsys全局数组的数量默认是4个。如果小于3,继续执行
r12的值为0xffffffff81e4bb60,为全局cgroup_subsys数组,
普通的fork默认是没有定义cgroup的can_fork,因此have_canfork_callback的值为0x0000000000,其返回值为4,因为传入的参数为4,大于3,直接跳转至结束处
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2018-9-26 16:12
被obfuscation编辑
,原因: