Hacktricks-skills ret2vdso-exploitation
How to perform Ret2vDSO (Return-to-vDSO) attacks in binary exploitation challenges. Use this skill whenever the user mentions vDSO, vdso, virtual dynamic shared object, kernel gadgets, AT_SYSINFO_EHDR, or needs to exploit gadgets in the kernel-mapped vDSO region. Also trigger when working with binary exploitation challenges where standard ROP gadgets aren't available but vDSO gadgets might be, or when ASLR bypass via vDSO is mentioned. This skill helps dump vDSO regions, locate gadgets, and build exploitation chains using vDSO addresses.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/binary-exploitation/rop-return-oriented-programing/ret2vdso/SKILL.MDRet2vDSO Exploitation
A skill for performing Return-to-vDSO attacks in binary exploitation challenges.
What is vDSO?
The vDSO (virtual Dynamic Shared Object) is a small ELF DSO mapped by the kernel to provide fast user-space implementations of some kernel helpers. It's mapped at a fixed or semi-fixed address and contains gadgets that can be used for ROP attacks.
When to Use This Skill
- Binary exploitation challenges where standard ROP gadgets are insufficient
- When you need to dump and analyze the vDSO region
- When ASLR bypass via vDSO is possible (CONFIG_COMPAT_VDSO)
- When you have access to
or can leak vDSO addresses/proc/<pid>/auxv - ARM64 SROP exploitation via vDSO
Core Methodology
Step 1: Locate the vDSO Base Address
The vDSO base address is passed in the auxiliary vector as
AT_SYSINFO_EHDR. You can recover it by:
-
Reading
(if accessible):/proc/<pid>/auxvcat /proc/<pid>/auxv -
Using
in a helper process:getauxval#include <sys/auxv.h> #include <stdio.h> int main() { void *vdso = (void*)getauxval(AT_SYSINFO_EHDR); printf("vDSO base: %p\n", vdso); return 0; } -
From memory maps (look for
):[vdso]cat /proc/<pid>/maps | grep vdso
Step 2: Dump the vDSO Region
Once you have the base address, dump the vDSO from the process memory:
# Find the vDSO address range cat /proc/<pid>/maps | grep vdso # Example output: f7ffc000-f7ffe000 r-xp 00000000 00:00 0 [vdso] # Calculate size and dump BASE=0xf7ffc000 SIZE=$((0xf7ffe000 - 0xf7ffc000)) dd if=/proc/<pid>/mem of=vdso bs=1 skip=$BASE count=$SIZE # Or use the helper script python scripts/dump_vdso.py <pid>
Step 3: Analyze the vDSO for Gadgets
# Check file type file vdso # Find gadgets using ROPgadget ROPgadget --binary vdso | grep -E 'pop|ret|mov|add|sub|xor' # Look for specific syscall gadgets ROPgadget --binary vdso | grep 'int 0x80' # x86 syscall ROPgadget --binary vdso | grep 'syscall' # x86_64 syscall ROPgadget --binary vdso | grep 'svc' # ARM64 syscall # Or use the helper script python scripts/find_vdso_gadgets.py vdso
Step 4: Identify Exported Symbols
The vDSO exports specific symbols depending on architecture:
x86 32-bit:
__kernel_vsyscall__kernel_sigreturn__kernel_rt_sigreturn
x86_64:
__vdso_clock_gettime__vdso_gettimeofday__vdso_time
ARM64:
__kernel_rt_sigreturn__kernel_vsyscall
Use
readelf or objdump to find symbol offsets:
readelf -Ws vdso | grep -E 'FUNC|__kernel|__vdso' objdump -d vdso | grep -A5 '<__kernel'
Step 5: Build the Exploitation Chain
Once you have gadgets, calculate their absolute addresses:
vdso_base = 0xf7ffc000 # From auxv or memory leak # Example gadgets (offsets from readelf/ROPgadget) gadgets = { 'pop_edx_pop_ecx_ret': vdso_base + 0x57a, 'mov_dword_ptr_edx_ecx': vdso_base + 0xcca, 'pop_ebx_pop_esi_pop_ebp': vdso_base + 0x15cd, } # Build ROP chain rop_chain = [ gadgets['pop_edx_pop_ecx_ret'], target_address, value_to_write, gadgets['mov_dword_ptr_edx_ecx'], # ... rest of chain ]
Architecture-Specific Notes
x86/x86_64
- vDSO typically contains syscall-related gadgets
- Look for
(x86) orint 0x80
(x86_64) instructionssyscall - Common gadgets involve
instructions for register setuppop
ARM64
- vDSO gadgets are more limited on ARM64
- Primary use case: SROP (Sigreturn-Oriented Programming)
- Look for
for SROP chains__kernel_rt_sigreturn - Check for gadgets that can control
(link register)x30
ASLR Bypass Considerations
Important: If the kernel is compiled with
CONFIG_COMPAT_VDSO, the vDSO address may not be randomized, allowing ASLR bypass:
- 32-bit processes on 64-bit kernels often have fixed vDSO addresses
- Check kernel config:
grep CONFIG_COMPAT_VDSO /boot/config-$(uname -r) - If fixed, you can use hardcoded vDSO addresses in your exploit
Common Pitfalls
-
Symbol versioning: vDSO uses symbol versioning. Match the expected version when resolving symbols.
-
Address randomization: On modern kernels, vDSO may still be ASLR'd. Always verify the address at runtime.
-
Architecture mismatch: Ensure you're analyzing the correct architecture's vDSO (32-bit vs 64-bit).
-
Permissions: You need appropriate permissions to read
and/proc/<pid>/mem
./proc/<pid>/auxv
Example Workflow
# 1. Find target process ps aux | grep target_binary # 2. Get vDSO address from maps cat /proc/<pid>/maps | grep vdso # f7ffc000-f7ffe000 r-xp 00000000 00:00 0 [vdso] # 3. Dump vDSO python scripts/dump_vdso.py <pid> # 4. Find useful gadgets python scripts/find_vdso_gadgets.py vdso | grep -E 'pop|syscall|ret' # 5. Build exploit using discovered gadgets # (use your preferred exploit framework or custom code)
References
- Linux vDSO man page
- Kernel vDSO documentation
- vDSO ASLR bypass vulnerability
- HTB Maze of Mist writeup
Scripts
This skill includes helper scripts:
- Dump vDSO from a running processscripts/dump_vdso.py
- Find and list gadgets in a vDSO dumpscripts/find_vdso_gadgets.py
Run them with
--help for usage information.