diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 1f2516b4232..5f45ed2c2f4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -937,6 +937,7 @@ - [WWW2Exec - \_\_printf_arginfo_table](binary-exploitation/arbitrary-write-2-exec/aw2exec-__printf_arginfo_table.md) - [Virtualbox Slirp Nat Packet Heap Exploitation](binary-exploitation/libc-heap/virtualbox-slirp-nat-packet-heap-exploitation.md) - [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.md) + - [QEMU/KVM VM Escape Chains](binary-exploitation/qemu-kvm-vm-escape-chains.md) - [Adreno A7xx Sds Rb Priv Bypass Gpu Smmu Kernel Rw](binary-exploitation/linux-kernel-exploitation/adreno-a7xx-sds-rb-priv-bypass-gpu-smmu-kernel-rw.md) - [Af Unix Msg Oob Uaf Skb Primitives](binary-exploitation/linux-kernel-exploitation/af-unix-msg-oob-uaf-skb-primitives.md) - [Arm64 Static Linear Map Kaslr Bypass](binary-exploitation/linux-kernel-exploitation/arm64-static-linear-map-kaslr-bypass.md) diff --git a/src/binary-exploitation/common-exploiting-problems.md b/src/binary-exploitation/common-exploiting-problems.md index ef245997f3d..957a8ca7569 100644 --- a/src/binary-exploitation/common-exploiting-problems.md +++ b/src/binary-exploitation/common-exploiting-problems.md @@ -309,6 +309,10 @@ This pattern is useful whenever the initial primitive can reach writable policy ## Related pages +{{#ref}} +qemu-kvm-vm-escape-chains.md +{{#endref}} + {{#ref}} common-exploiting-problems-unsafe-relocation-fixups.md {{#endref}} diff --git a/src/binary-exploitation/qemu-kvm-vm-escape-chains.md b/src/binary-exploitation/qemu-kvm-vm-escape-chains.md new file mode 100644 index 00000000000..3337ab258a2 --- /dev/null +++ b/src/binary-exploitation/qemu-kvm-vm-escape-chains.md @@ -0,0 +1,116 @@ +# QEMU/KVM VM Escape Chains + +{{#include ../banners/hacktricks-training.md}} + +A QEMU/KVM guest can reach several independently privileged parsers: KVM's host-kernel MMU, QEMU device models, firmware/SMM state, and in-process libraries such as libslirp. A useful escape methodology is therefore to inventory every enabled boundary and combine weak primitives across components instead of looking only for one guest-to-host RCE.[[1]](#references) + +## Map the guest-controlled host attack surface + +Review the exact QEMU command line and test what the guest can reach. Default devices, display rendering, user-mode networking, management sockets, shared filesystems, and host services reachable through the user-network gateway all add host-side code paths. QEMU's user backend exposes the host at the second address of its virtual subnet (normally `10.0.2.2`), while `restrict=on` blocks non-explicit guest access to the host and outside networks.[[1]](#references)[[6]](#references) + +```bash +# Host: recover the effective QEMU configuration +tr '\0' ' ' < /proc/$(pgrep -n qemu-system)/cmdline; echo +lsof -Pan -p "$(pgrep -n qemu-system)" -i + +# Guest: test the default slirp host address and a commonly exposed service +ip route +curl --noproxy '*' --connect-timeout 2 http://10.0.2.2:631/ +``` + +Classify each reachable component by the primitive it may provide:[[1]](#references) + +| Surface | Guest-controlled input | Useful primitive | +| --- | --- | --- | +| KVM shadow MMU | Page-table changes, invalidations and vTLB state | Host-physical alias or kernel corruption | +| QEMU memory/device model | MMIO, port I/O, ROM aliases, queue lifecycle | Heap corruption, protected-memory exposure | +| libslirp | IPv4/IPv6 fragments, ICMP/TCP/UDP state | In-process read/write or heap grooming | +| Display backend | Mode registers and rendering transitions | QEMU heap overflow | +| Host-loopback services | Requests that appear local to the service | Credential reuse or privileged file operations | + +## Stale KVM shadow translations to host-physical write + +KVM shadow paging maintains host-side SPTEs and role metadata for guest translations. In the disclosed chain, an attacker changed a guest entry from a level-2 mapping to a 4 KiB mapping while an unsynchronized shadow page remained reusable. The old `paging64_invlpg()` path then reused the stale level-2 role, preserving a writable 2 MiB translation into host physical memory. The upstream change removed `FNAME(invlpg)` and routes invalidation through `FNAME(sync_spte)` so unsynchronized SPTEs are synchronized or zapped consistently.[[1]](#references)[[2]](#references) + +The exploitation pattern is:[[1]](#references) + +1. Build shadow state for a large guest mapping and make the corresponding shadow page unsynchronized. +2. Replace the guest page-table entry with a 4 KiB mapping without losing the reusable shadow page. +3. Invalidate the guest address so vulnerable code walks the shadow state with the obsolete large-page role. +4. Reuse the surviving translation as a writable host-physical window and locate pages belonging to the QEMU process. + +A broad physical write is not automatically reliable code execution: it still needs a stable target in QEMU's heap or mapped data. This is where a second guest-controlled allocator surface can act as an address-discovery oracle.[[1]](#references) + +## libslirp packet objects as heap landmarks + +Mixed IPv4 fragments can deliberately disagree about Internet Header Length (IHL). In the reported libslirp bug, reassembly accounting used inconsistent header sizes and later ICMP reflection copied beyond the logical reassembled packet. Repeating the sequence left thousands of recognizable, live `NetPacket` objects in QEMU's heap.[[1]](#references) + +Use those objects to convert an imprecise host-memory primitive into control flow:[[1]](#references) + +1. Spray packets whose live host objects contain distinctive lengths, flags and payload bytes. +2. Scan the readable or writable host window for several correctly spaced copies; multiple matches reduce false positives. +3. Identify a live object containing a callback and preserve the fields needed by normal processing. +4. Replace only the callback and required context pointer, then trigger the ordinary completion/send path. + +This technique is useful beyond libslirp: any guest-driven subsystem that creates many long-lived, callback-bearing host objects can serve as a landmark spray for a separate physical-memory or heap write.[[1]](#references) + +### Combine CVEs with ordinary correctness fixes + +Do not limit patch review to security advisories. A known libslirp vulnerability was combined with an older non-CVE fix to obtain arbitrary host-process read/write. That fix replaced incompatible `ipq`/`ipasfrag` aliasing in `ip_reass()` with a union-backed type because compiler strict-aliasing assumptions could otherwise leave fragment-queue state inconsistent.[[1]](#references)[[3]](#references) + +When auditing a deployed version, diff every upstream change touching the vulnerable parser's length, lifetime and ownership invariants. A fix described as a compiler, crash, assertion, or data-consistency correction may supply the missing leak, write, or state-confusion primitive for an already known bug.[[1]](#references)[[3]](#references) + +## Protected-memory alias as an SMM bridge + +Emulated memory aliases must be validated against protected physical ranges. The chain used a guest-controlled VAPIC ROM alias that QEMU allowed to overlap locked SMRAM. The alias exposed SMM code/state to the guest and enabled attacker-controlled SMM execution; the subsequent KVM translation bugs carried that influence into a writable host-physical mapping.[[1]](#references) + +This creates a reusable audit rule: for every guest-selectable `MemoryRegion` alias, verify both `alias_base + size` overflow handling and intersection with SMRAM or other locked/reserved ranges after address-space updates. Locking the underlying range is insufficient if a second emulated mapping can still reference it.[[1]](#references) + +## Other guest-to-QEMU primitives + +### Display geometry unit mismatch + +QEMU once reused `last_width` for text characters and graphics pixels. A graphics → text → graphics transition could make the dimensions compare equal while retaining a buffer allocated for the old size:[[4]](#references) + +1. Graphics mode with `CR01=0x00` allocated `panning_buf` for 8 pixels: `(8 + 16) * 4 = 96` bytes. +2. Text mode with `CR01=0xff` stored a width of 256 characters without resizing that buffer. +3. Graphics mode with `CR01=0x1f` produced 256 pixels; the stale equality skipped reallocation and `vga_draw_line4()` wrote 1,024 bytes, a 960-byte overflow per scanline. + +The upstream fix reallocates `panning_buf` unconditionally in `vga_draw_graphic()`. On the reported target, `-display none` left no display listener to reach the renderer, demonstrating that removing a backend can eliminate an otherwise valid corruption primitive.[[1]](#references)[[4]](#references) + +### Queue reset and packet-length state divergence + +Reset paths deserve the same lifetime review as normal completion. One reported QEMU device reset left requests alive; later completion underflowed the queue's `inuse` counter and reentered completion handlers. This produced denial of service and bounded state corruption, but not an unbounded write by itself.[[1]](#references) + +A separate libslirp IPv6 path retained bytes beyond the declared payload length and later allowed them to influence a host-side stream. Treat every declared-length/trailing-data disagreement as a possible cross-protocol injection primitive, but confirm that a suitable host service is reachable and that the extra bytes are consumed predictably.[[1]](#references) + +## Host-loopback CUPS certificate to root file overwrite + +User-mode networking can invalidate a service's assumption that loopback traffic originates on the host. In the disclosed environment, guest access to CUPS exposed a reusable root `Local` certificate. The guest could authenticate, configure a `file://` printer, and make print data overwrite a host file with the CUPS scheduler's root privileges.[[1]](#references) + +The upstream CUPS correction shows both required trust failures: it restricts `Local` certificate authentication and local-printer creation to `AF_LOCAL` Unix-domain sockets rather than TCP loopback, and removes ordinary file output while retaining the explicit `/dev/null` case. AppArmor blocked the sensitive target paths in the experiment, so the primitive's practical reach still depends on the scheduler's mandatory-access-control profile.[[1]](#references)[[5]](#references) + +## Reducing exploit-chain reachability + +Prefer an explicit minimal QEMU configuration and add devices one at a time. `-nodefaults` suppresses default devices, `-display none` removes graphical output, `-nic none` disables the default network device, and user networking can use `restrict=on` when only explicit forwarding is required.[[1]](#references)[[6]](#references) + +```bash +# Starting point; add only the storage/console devices the workload needs +qemu-system-x86_64 -nodefaults -display none -nic none ... + +# If libslirp is required, prevent implicit host/outside reachability +-netdev user,id=n0,restrict=on,ipv6=off +``` + +Patch auditing must also include upstream correctness commits, not only CVE feeds: the KVM invalidation change and libslirp strict-aliasing correction were exploitable building blocks despite not initially being treated as security fixes. Separately restrict the QEMU process, management sockets and host services so one successful primitive does not immediately inherit broad host access.[[1]](#references)[[2]](#references)[[3]](#references) + +## References + +- [1] [Trail of Bits - VMs Won't Contain Cyber-Capable Agents](https://blog.trailofbits.com/2026/08/26/vms-wont-contain-cyber-capable-agents/) +- [2] [Linux - KVM: x86/mmu: use sync_spte to update vTLB](https://github.com/torvalds/linux/commit/9fd4a4e3a3d9fc0306525d95bf3eca693d311406) +- [3] [libslirp - Enforce strict aliasing in IP reassembly](https://gitlab.freedesktop.org/slirp/libslirp/-/commit/26be815b86e8d49add8c9a8b320239b9594ff03d) +- [4] [QEMU - Fix panning_buf OOB after text/graphics switch](https://gitlab.com/qemu-project/qemu/-/commit/95687639e647ec917226e6d3a6713a2b373e1ffe) +- [5] [CUPS - Restrict local certificates and file output](https://github.com/OpenPrinting/cups/commit/e052dc44da9d12adfbebc51de4975fbadb2ce356) +- [6] [QEMU system invocation - display and user-network options](https://qemu.readthedocs.io/en/master/system/invocation.html) + +{{#include ../banners/hacktricks-training.md}}