Journey to Freedom: Escaping from VirtualBox

Corentin Bayet (Security Researcher · Reverse Tactics), Bruno Pujos (CEO / Security Researcher · Reverse Tactics)

OffensiveCon 2025 · Day 2 · Main · Briefings

Overview

Corentin Bayet and Bruno Pujos of Reverse Tactics present the VirtualBox guest-to-host escape they executed at Pwn2Own Vancouver 2024, earning $90,000. The exploit chains an uninitialized memory read in the PGMPhysRead function (a variant of a 2023 Synacktiv bug) to leak stack and heap pointers and defeat ASLR, then uses a stack buffer overflow in the virtio network card's VirtQueue descriptor parsing to gain code execution in the VirtualBox host process via CFG-aware ROP. ---

Watch on YouTube

Visual summary for Journey to Freedom: Escaping from VirtualBox by Corentin Bayet, Bruno Pujos
Visual summary for Journey to Freedom: Escaping from VirtualBox by Corentin Bayet, Bruno Pujos

Key moments

  1. 4:35 MMIO/PMIO attack surface in VirtualBox: PGMPhysRead calls device handlers with arbitrary buffer sizes
  2. 5:59 State-of-the-art analysis reveals 2023 Synacktiv PGMPhysRead uninit-read pattern to hunt for variants
  3. 9:29 BusLogic MMIO handler returns success without writing buffer, leaking entire XHCI thread stack frame
  4. 9:46 Uninitialized host stack read yields stack and heap pointers defeating ASLR from guest
  5. 13:34 Virtio VirtQueueBuf always stack-allocated in VirtualBox builds despite ifdef suggesting heap path
  6. 14:16 Virtio VirtQueue descriptor count insufficiently validated, producing guest-controlled stack buffer overflow
  7. 18:57 CFG bypassed by constructing ROP chain exclusively from CFG-bitmap-valid function entry points
  8. 24:32 Pwn2Own exploit: 100% stable Python/Chipsec chain earns $90,000 for VirtualBox guest-to-host escape

Journey to Freedom: Escaping from VirtualBox

Speakers: Corentin Bayet (Reverse Tactics), Bruno Pujos (Reverse Tactics)

Conference: OffensiveCon 2025 — May 16–17, 2025, Berlin

YouTube: https://www.youtube.com/watch?v=i-3zUmdXpNI

Reading time: ~10 minutes

TL;DR

Corentin Bayet and Bruno Pujos of Reverse Tactics present the VirtualBox guest-to-host escape they executed at Pwn2Own Vancouver 2024, earning $90,000. The exploit chains an uninitialized memory read in the PGMPhysRead function (a variant of a 2023 Synacktiv bug) to leak stack and heap pointers and defeat ASLR, then uses a stack buffer overflow in the virtio network card's VirtQueue descriptor parsing to gain code execution in the VirtualBox host process via CFG-aware ROP.

Introduction

Oracle's VirtualBox occupies an unusual position in the hypervisor security landscape: it is open-source, widely deployed, and maintained without a dedicated security team. For competitive exploit research at events like Pwn2Own, that combination makes it both accessible — the source code is public — and fragile: security investment tracks revenue, and VirtualBox generates little for Oracle. Corentin Bayet and Bruno Pujos of the French security firm Reverse Tactics targeted VirtualBox at Pwn2Own Vancouver 2024, ultimately delivering a 100% stable, Python-based exploit chain that escaped from a Linux guest to the Windows host process and then escalated to SYSTEM via a separate Windows LPE.

The talk covers the guest-to-host escape component in detail, walking through the attack surface selection methodology, the information leak, and the stack buffer overflow — including the exploit tooling choices and CFG bypass strategy.

Research Methodology: State of the Art Before the Dive

Bayet structures his approach to hypervisor research around an explicit "state of the art" phase before any code review. The goal is to build a working model of the codebase's historically vulnerable patterns — the classes of bugs that have appeared before — so that code review can be guided toward likely clusters rather than conducted exhaustively across millions of lines.

For VirtualBox, this analysis surfaced a 2023 uninitialized memory read found by "Major Tom Sek," a former Synacktiv colleague who used it at Pwn2Own 2023. That bug was in PGMPhysRead, a ubiquitous function responsible for copying guest physical memory into a host-side buffer. The function iterates page-by-page (because guest physical memory is not contiguous in host address space), and for each page, checks whether the guest physical address (GPA) falls within an MMIO-mapped region. If it does, it calls the registered MMIO read handler. If the handler fails, the function attempts to early-exit and zeroes the buffer — but the memset uses CB (the current page size) instead of CB_Read (the total buffer size), leaving all subsequent pages uninitialized.

The original Synacktiv exploit triggered this via the XHCI USB 3.0 controller's MMIO read handler, which correctly fills the buffer, then read the leaked uninitialized data by finding code that reads from the guest and writes the result back in a way accessible to the attacker. The patch applied after 2023 was minimal: changing CB to CB_Read in that one error path.

▶ Watch: PGMPhysRead bug and the 2023 Synacktiv variant (6:01)

Vulnerability 1: Uninitialized Memory Read via BusLogic MMIO Handler

Bayet recognized that the patch addressed only the specific error path — the underlying structural problem remained: PGMPhysRead calls device-specific MMIO handlers and trusts them to fully initialize the provided buffer. Any handler that returns success without writing to the full buffer will leave uninitialized host stack data in the output.

Auditing the full set of registered MMIO handlers for the PGMPHYS_DO_GC_PHYS_READ flag (which marks handlers callable with arbitrary buffer sizes, not just the typical 1, 2, or 4 bytes) revealed a candidate: the BusLogic SCSI controller's MMIO read handler. BusLogic is an emulated hard disk interface. Its MMIO read handler does essentially nothing — it returns VINF_SUCCESS without writing any data to the buffer. Because the handler succeeds, PGMPhysRead's early-exit/memset branch is never taken, and the caller receives a buffer populated entirely with uninitialized host stack data.

The exploit trigger is straightforward: send a guest-controlled GPA that maps to the BusLogic MMIO range to any VirtualBox device that calls PGMPhysRead and then makes the result accessible. The XHCI controller's descriptor-processing path reads guest memory via PGMPhysRead and then copies the result back to the guest — providing exactly the read-back path needed. The result is an arbitrary read of uninitialized host stack memory: the XHCI thread's stack frame, containing stack pointers (defeating ASLR for the stack), text segment pointers (providing base addresses for ROP gadget computation), and arbitrary host data that can be used as a staging area.

▶ Watch: BusLogic MMIO handler variant and ASLR defeat (10:00)

Attack Surface Expansion: Virtio and the VirtQueue Overflow

With ASLR defeated and known addresses for the XHCI thread stack, Bayet needed a code execution primitive. The Virtio device implementation became the target for this stage. Virtio is a paravirtualized device specification originally developed for QEMU/KVM and adopted by VirtualBox for its virtual disk and virtual network card implementations. VirtualBox's Virtio code exposes a VirtQueue mechanism through which the guest sends descriptors pointing to guest memory buffers for the host to process.

Reviewing the VirtQueue parsing code revealed a suspicious conditional compilation pattern: a VirtQueueBuf structure was allocated on the stack under one #ifdef branch and on the heap under another — and in the actual build configuration used by VirtualBox, the structure was always stack-allocated. The code that parsed incoming descriptor lists from the guest into this stack-allocated VirtQueueBuf performed insufficient bounds validation on the number of descriptors, allowing an attacker-controlled guest to write beyond the end of the stack buffer.

The resulting stack buffer overflow is directly reachable from the Virtio network card's descriptor processing path. The guest supplies a descriptor ring entry pointing to controlled data; VirtualBox's virtioNetR3 device handler processes it, copies descriptor content into the stack-local VirtQueueBuf without adequate length checks, and the overflow corrupts the return address and any saved frame pointers on the XHCI worker thread's stack.

▶ Watch: Virtio device code review and VirtQueueBuf overflow (14:00)

Exploit Strategy: Chipsec, Python, and CFG-Aware ROP

The exploit was written entirely in Python using Chipsec — a hardware security testing framework with pre-built Windows and Linux kernel drivers that expose privileged operations (physical memory read/write, MMIO access, in/out instruction execution, hypercall invocation) to userland. Chipsec's Python API provides an OS-agnostic interface that allows writing a single exploit script that operates identically from Windows or Linux guest environments. The final deliverable was compiled with PyInstaller into a standalone executable — no Python runtime or dependencies required on the target guest.

Windows builds of VirtualBox are compiled with Control Flow Guard (CFG), Microsoft's forward-edge control flow integrity mechanism. CFG validates indirect call targets against a bitmap of legitimately callable function addresses; a stack buffer overflow that simply overwrites a return address to an arbitrary ROP gadget will be blocked. Bayet's bypass used the leaked text segment pointers from the information leak stage to compute the base address of the VirtualBox binary and its loaded DLLs, then searched for ROP gadgets exclusively within CFG-valid call targets — functions whose addresses appear in the CFG bitmap. Because VirtualBox.exe and its component DLLs are large binaries, the CFG-valid gadget set is sufficiently rich to construct a full shellcode-staging ROP chain.

The ROP chain achieved code execution in the VirtualBox host process (VBoxSVC.exe context), landing in the Windows user session with the privileges of the VirtualBox process itself. The full escape was 100% stable across repeated runs — a requirement for competition success and a testament to the precision of the ASLR defeat via the information leak.

Notable Quotes

"Oracle maintains VirtualBox. I'm quite sure they don't make any profit on this product, so they have no team hundred percent dedicated on VirtualBox security."

— Corentin Bayet, ▶ 2:00

"A good journey always starts with a good state of the art. It's a very important step you cannot neglect — because it will save you a lot of time later. The most important thing is to extract the vulnerable patterns, the kind of bugs you can find in the codebase that you might re-find."

— Corentin Bayet, ▶ 6:01

"I found quickly a variant of the same bug from 2023. I don't even have to find an exploit technique because I can just reuse what Major Tom Sek used. I just need to find a specific MMIO read handler that does not fully initialize the buffer and returns a success."

— Corentin Bayet, ▶ 10:00

Key Takeaways

  • Vulnerable pattern analysis pays dividends: Studying the 2023 PGMPhysRead uninitialized-read bug closely enough to understand its root cause — MMIO handler non-initialization — allowed Bayet to find a structurally identical variant in a different handler (BusLogic) in days, without the overhead of a full codebase audit.
  • MMIO handler completeness is an implicit contract that VirtualBox violates: PGMPhysRead assumes all registered MMIO read handlers will fully populate the provided buffer; the BusLogic handler's no-op implementation violates this contract and exposes the host's XHCI thread stack to guest-controlled reads.
  • Virtio's VirtQueue stack allocation pattern is exploitable: VirtualBox's Virtio implementation stack-allocates the VirtQueueBuf descriptor structure and insufficiently validates descriptor counts from the guest, producing a stack buffer overflow reachable from an untrusted guest via the virtio-net descriptor ring.
  • CFG on Windows is bypassable via CFG-valid gadget selection: When a ROP chain is constructed exclusively from gadget addresses that appear in the CFG bitmap (i.e., legitimately callable function entry points), the forward-edge CFI provided by CFG does not prevent exploitation — the leaked text segment pointers from the info leak stage make this construction feasible.
  • Chipsec + PyInstaller provides a portable, self-contained hypervisor exploit toolkit: Python-based exploit development using Chipsec's privileged hardware access API, compiled to a standalone executable with PyInstaller, eliminates runtime dependency problems and produces competition-ready exploit tooling that operates identically on Windows and Linux guests.

Reviews

Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT

A clean, honest account of a Pwn2Own $90K VirtualBox escape: variant bug discovery via pattern-matching from prior research, uninitialized stack read via BusLogic MMIO handler non-initialization to defeat ASLR, Virtio VirtQueue stack overflow to gain code execution, CFG-valid gadget selection to bypass Control Flow Guard. No novel primitives invented here — but the methodology is disciplined, the chain is complete, 100% stable, and the CFG-valid ROP approach deserves attention.

Heather Calloway (CISO) — PASS

VirtualBox guest-to-host escape via uninitialized read in BusLogic MMIO variant analysis, leading to ASLR defeat and a CFG-aware ROP chain achieving host code execution. Pwn2Own Vancouver 2024, $90K.

→ Top-rated talks at OffensiveCon 2025

All talks from OffensiveCon 2025