Escaping VirtualBox 6.1: Part 1
secret.club
secret.club
First it shows how the top CTFs can showcase the state of the art in terms of exploitation. It's hard for anyone to argue that the CTF scene does not reflect the "real world" when it is producing solid work like unpublished virtual machine escapes. And even better, the work is shared in high quality writeups.
Secondly, this plus other vulnerabilities found in VirtualBox emphasises that off-the-shelf hypervisors cannot be considered to create a security boundary. Every serious nationstate possess weaponised exploits to break out of VirtualBox, VMware etc. KVM and Xen have a smaller attack surface and are known to have a better isolation model, but I'm sure there are still plenty of exploits given enough resources. Perhaps this is obvious to some, but some people really do think that VirtualBox VMs act like a sandbox, which is only true if your adversary is rather unsophisticated.
For a writeup from the same CTF, but focussing on networking and cryptography instead involving an exploit in a Chinese anti-censorship proxy tunnel, please see https://blog.cryptohack.org/cracking-chinese-proxy-realworld...
KVM - the low-level kernel-level hypervisor - has a tiny attack surface and has been audited exhaustively. It's unlikely to have critical bugs in it.
When people talk about "KVM vulnerabilities", they're usually talking about vulnerabilities in QEMU, which implements the actual device emulation. QEMU has all of the attack surface, deals with low-level data shuffling, and is written in C. Even worse, most stock QEMU-KVM deployments simply run qemu as root with no extra sandboxing or MAC like SELinux/sVirt. It's very likely that a bunch of 0days exist for those environments.
This is why many cloud providers use KVM-the-kernel-module, but an in-house replacement for QEMU.
Fortunately, there's a growing ecosystem of QEMU replacements written in Rust:
- https://github.com/cloud-hypervisor/cloud-hypervisor
- https://github.com/firecracker-microvm/firecracker
- https://chromium.googlesource.com/chromiumos/platform/crosvm... (the Chrome OS VM runtime which Firecracker was forked from)
Google's gVisor - the sandbox that App Engine and Cloud Run uses - uses KVM as well: https://gvisor.dev/docs/
With an emulation layer written in a language like Rust, the trust boundary is much better.
As for VirtualBox in particular - that one should not be considered a trust boundary. Nobody is seriously using it in production, and it's regularly featured in CTF competitions as a fun exploitation target.
> most stock QEMU-KVM deployments simply run qemu as root with no extra sandboxing or MAC like SELinux/sVirt.
This is not true. OpenStack uses Libvirt for example, so on Red Hat/CentOS systems it will be hardened with SELinux by default. The same is true for virt-manager, which runs as either an unprivileged "qemu" user or as the user that invokes it.
Not all the code in QEMU is of identical quality, but the subset that is used by cloud providers is very mature and is also tested in Google's open source fuzzing cluster. Thanks to a student from Boston University who came up with some pretty cool techniques, we can cover devices effectively without having to teach the fuzzer about each device's registers.
> many cloud providers use KVM-the-kernel-module, but an in-house replacement for QEMU.
Two of them--certainly they are the big ones, Amazon and Google, but pretty much everybody else is using QEMU. For what it's worth, Amazon is also using QEMU on their old Xen-based instance types.
Firecracker is the only open source virtual machine monitor that cloud providers use in production apart from QEMU, as far as I know. It's a very interesting project and the people behind it have also started rust-vmm, a library of Rust crates for virtual machine monitors and device emulation backends. Several QEMU developers also contribute to rust-vmm, focusing especially on the abstractions needed to avoid unsafe code in virtual machine monitors. There was already an instance last year of problematic unsafe code in Firecracker that wouldn't have been there had it used rust-vmm's vm-memory crate, and in fact Firecracker has since switched to vm-memory. So there is plenty of collaboration between the authors of various VMMs.
Can I ask who this was and is there any more info on their work? Seems important and worth naming them :)
Which are typically closed source, which is quite a shame.
A lot of the extensive security precautions for qemu are intended for a hosting provider threat model where multiple random tenant customers may be using VMs on the same hypervisor bare metal, in which case you absolutely don't want them to be able to escape the vm or read each others' memory.
Nation states are one thing.
Will it protect the average user, against common security risks ?
But every security bug starts as a zero day. But yet some bugs become common malware, yet I others are not.
Why?
And is virtualization somehow special in that regard?
https://en.wikipedia.org/wiki/Wargame_%28hacking%29?wprov=sf... (mentioned in 2nd paragraph)
I love Real World CTF. In 2018 I participated in the finals round held in Zhengzhou, and there was a problem that involved Java and the RMI protocol. We ended up exploiting two zero-days in Java, reported them to Oracle and got a CVE: CVE-2019-2684. That was very exciting to me - to discover and exploit a bug in real software in less than 48 hours :)
Kudos to the VirtualBox hackers for doing that on such a high-profile bit of software - amazing work!
Do the organizers know about the security vulnerability?
Where do they get the vulnerabilities from?
Edit: Curious, are there common guest escapes that exploit something other than virtual devices?
As bugs in memory-unsafe PL code have high probability to be exploitable, giving control to the attacker, the game is set.
Presumably it might be a good idea to do a better job isolating the virtual devices. Might be nice to use a memory safe language/runtime also.
They have this variable declaration in the beginning: static const short port_base = 0x434;
However they use "port" variable when making calls: __outbyte(port+3, 0);