前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >人见人爱的vDSO机制,如今也靠不住了

人见人爱的vDSO机制,如今也靠不住了

作者头像
安恒信息
发布2018-04-09 17:03:38
1.2K0
发布2018-04-09 17:03:38
举报
文章被收录于专栏:安恒信息安恒信息

本文旨在介绍vDSO在内核提权中绕过SMEP/PXN的应用

0x01 vDSO

是什么

孙子兵法最核心的价值观就是:知己知彼,百战不殆。

为了搞清楚vDSO在内核提权中的应用,首先就要搞清楚vDSO到底是什么,我们来看下vDSO的定义:

The "vDSO" (virtual dynamic shared object) is a small shared library that the kernel automatically maps into the address space of all user-space applications. Applications usually do not need to concern themselves with these details as the vDSO is most commonly called by the C library. This way you can code in the normal way using standard functions and the C library will take care of using any functionality that is available via the vDSO.

用通俗的话来讲

就是有一些内核调用

使用的频率实在太高了

但是这个内核调用开销太大了

经常被C的库函数或者直接被程序调用到

不划算啊,怎么办?

干脆直接用户态映射一段内存

把内核调用的结果存在这里

哪个进程用到

直接在本地进行内存读取就好了

这样就把一个开销大的内核

调用转换成了开销很低的

用户态函数调用和一点内存访问

vDSO的功能就是这个了,具体实现形式是啥呢?

就是在所有的进程空间中直接映射了一个so,就叫vdso,全称virtual dynamic share object,直接来看下:

root@kali:~# cat /proc/self/maps ... ... ... 7fd137db5000-7fd137db6000 rw-p 00000000 00:00 0 7fffd2eee000-7fffd2f0f000 rw-p 00000000 00:00 0 [stack] 7fffd2faa000-7fffd2fad000 r--p 00000000 00:00 0 [vvar] 7fffd2fad000-7fffd2faf000 r-xp 00000000 00:00 0 [vdso]

最下面的那个section,就是我们的vdso了,权限是r-xp,可读可执行但不可写,我们可以直接把他dump出来看看:

gdb-peda$ dumpmem vdso.so 0x00007ffff7ffa000 0x00007ffff7ffc000 Dumped 8192 bytes to 'vdso.so' gdb-peda$ quit root@kali:/tmp# file vdso.so vdso.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=86abd7ee88b80b2b343abd6fde3a2354970d5bac, stripped root@kali:/tmp#

这是一个标准的so文件,来看看他的导出函数:

root@kali:/tmp# objdump -T vdso.so vdso.so: 文件格式 elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000a30 w DF .text 0000000000000305 LINUX_2.6 clock_gettime 0000000000000d40 g DF .text 00000000000001c1 LINUX_2.6 __vdso_gettimeofday 0000000000000d40 w DF .text 00000000000001c1 LINUX_2.6 gettimeofday 0000000000000f10 g DF .text 0000000000000015 LINUX_2.6 __vdso_time 0000000000000f10 w DF .text 0000000000000015 LINUX_2.6 time 0000000000000a30 g DF .text 0000000000000305 LINUX_2.6 __vdso_clock_gettime 0000000000000000 g DO *ABS* 0000000000000000 LINUX_2.6 LINUX_2.6 0000000000000f30 g DF .text 000000000000002a LINUX_2.6 __vdso_getcpu 0000000000000f30 w DF .text 000000000000002a LINUX_2.6 getcpu

是一些常用的系统调用函数。

0x02 vDSO

在内核提权中的应用

首先明确一点,vDSO在用户态的权限是R/X,在内核态的权限是R/W,这导致了如下两种思路:

假如我们能控制RIP,就通过ROP执行内核函数set_memory_rw()来完成对用户态vdso段属性的更改,然后在用户态对vdso段的gettimeofday()函数代码进行覆盖为我们的shellcode,当root权限的进程调用gettimeofday()函数的时候就完成了对shellcode的执行。

假如我们实现的是任意地址写,就通过内核态的任意地址写来更改vdso段中gettimeofday()函数的内容,改为我们的shellcode,同样当root权限的进程调用gettimeofday()函数的时候就完成了对shellcode的执行。

理想很丰满,现实很骨感,为了实现这两个思路,需要解决如下几个问题:

1、如果要使用set_memory_rw()来完成对用户态vdso段属性的更改,需要知道vDSO段的用户态地址

2、如果要通过内核态的任意地址写来更改vdso段中gettimeofday()函数的内容,需要知道vDSO段的内核态地址

3、内核态的shellcode如何编写?

我们来一一解决这些问题:

1. vDSO在用户态的地址在高版本的glibc中可以直接使用getauxval(AT_SYSINFO_EHDR)来获取:

root@kali:/tmp# cat vdsoaddr.c #include <stdio.h> #include <sys/auxv.h> int main() { unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); if (!sysinfo_ehdr) { printf("AT_SYSINFO_EHDR is not present!\n"); return 0; } printf("%lx\n", sysinfo_ehdr); sleep(3000); } root@kali:/tmp# ./vdsoaddr 7ffc5117b000

root@kali:/tmp# ps aux | grep vdsoaddr root 10639 0.0 0.0 4172 656 pts/0 S+ 16:07 0:00 ./vdsoaddr root 10656 0.0 0.0 12928 948 pts/1 S+ 16:07 0:00 grep vdsoaddr root@kali:/tmp# cat /proc/10639/maps ... ... ... 7f5567e16000-7f5567e17000 rw-p 00000000 00:00 0 7ffc51122000-7ffc51143000 rw-p 00000000 00:00 0 [stack] 7ffc51178000-7ffc5117b000 r--p 00000000 00:00 0 [vvar] 7ffc5117b000-7ffc5117d000 r-xp 00000000 00:00 0 [vdso]

可以看到获取到了vdso映射的开始地址。

2、vDSO段的内核态地址

通过暴力搜索vdso的ELF开头来确定vdso在内核中的映射位置,这需要一个内核任意读。

3、shellcode的编写

shellcode编写需要注意两个方面:一个是只对uid=0的用户进行反弹,另外一个是对于正常的gettimeofday()函数仍旧需要进行返回,所以我们就开启一个子进程进行socket反弹shell,反弹到127.0.0.1的监听端口上,一个现成的shellcode可以在这里看到:https://gist.github.com/itsZN/1ab36391d1849f15b785

0x03

大功告成

研究员Mr.zhang

终于大功告成了!搞定了这些问题,基本上就可以完成通过对vDSO的利用来绕过SMEP/PXN这样的防护了,有一个简单的练习题读者可以进行练习:

https://poppopret.org/2015/11/16/csaw-ctf-2015-kernel-exploitation-challenge/

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 安恒信息 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档