vsyscall滑动绕过
vsyscall 介绍
vsyscall
和 vdso
被设计用来加速系统调用的处理
vsyscall
的工作原则其实十分简单:Linux 内核在用户空间映射一个包含一些变量及一些系统调用的实现的内存页。
vsyscallt 特点:
vsyscall页面在每个进程中是静态分配了相同的地址;
分配的内存较小;
只允许4个系统调用;
vdso 特点:
提供和vsyscall相同的功能,同时解决了其局限。
vDSO是动态分配的,地址是随机的;
可以提供超过4个系统调用;
vDSO是glibc库提供的功能;
vsyscall 地址特性
vsyscall分配的地址固定不变,不受 aslr 和 pie 影响,固定在:
1 | ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls |
系统 aslr 打开,程序保护全开
vsyscall提供的系统调用
导出 vsyscall
GDB 运行程序,打断后导出内存数据:
1 | dump memory ./vsyscall 0xffffffffff600000 0xffffffffff601000 |
导出 bin 文件用 ida64 打开即可:
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
保护全开:
存在一个栈溢出,可以覆盖 v6 控制调用的函数:
一开始准备将 v6 覆盖到 system(‘cat flag’) ,但是程序会在写入完成后加上一些东西,无法通过覆盖低字节绕过 pie ,也没有办法泄露出 pie 基地址。
只能想办法将 v7 覆盖成非零值通过 if 判断。
将 v6 覆盖成 vsyscall 的系统调用,该区域的四个系统调用不受 pie 和 alsr 的影响而随机。使用系统调用 sys_time(0xc9) ,可以视为 ret
v7 可以不需要额外写入非零值,因为程序输入会在 payload 后面加上额外东西
1 | from pwn import * |
2020_DASCTF 8月赛 magic_number
保护全开,栈溢出漏洞,有后门
利用 vsyscall 滑动将 rip 往后滑动到后门地址,后门地址是利用栈上遗留的数据,通过 partly write 覆盖写出来的
1 | from pwn import * |
2020_DamCTF ghostbusters
可以调用任意地址的函数,返回值实际上是放在 v7
通过调用 vsyscall 的 sys_time 爆破返回值为 121 时 getshell
1 | from pwn import * |