Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

Attacking Firecracker: AWS' microVM Monitor Written in Rust- 949

Valentina Palmiotti - Grapl SecurityPosted 3 Years Ago
  • Firecracker is an open source Virtual Machine Monitor (VMM) by AWS written in Rust. The purpose of this project is to allow for multi-tenant services to run on one machine. Firecracker is built on top of the KVM, built by the Linux project. Being able to break out of Firecracker would allow for cross-tenant access to data, a major problem.
  • The KVM is a type 1 hypervisor, meaning that it runs on bare metal (unlike Hyper-V). The KVM is made up of two modules: one for providing the virtualization infrastructure and the other for processor specific models to take a slice of the CPU. Each VM runs as a regular Linux process on the host, with a low level API for interacting with it at /dev/kvm.
  • Firecracker is a VMM that uses the Linux Kernel’s KVM virtualization infrastructure to provide Linux and OSv microVMs on Linux hosts. Storage is done via a block device and there are several virtualized services like this as well. The API that the vulnerability was found in is the vsock, which is used for communicating between a virtual machine and the host. AWS designed this in such a way to reduce VMM attack surface and put most of the stuff on the client side.
  • virtio-vsock is a guest/host communication device that allows applications on the guest and host to communicate via socket. In QEMU, this is implemented in a kernel module. For FireCracker, it is implemented in user space, but the device model is over MMIO to the VMM directly.
  • When a VM is created, RAM is allocated using MMAP into the MemoryRegion structure. This has a guest_base (physical address on the guest and MemoryMapping, which is a pointer to the memory of the Firecracker process this belongs to. The drivers running in the guest’s kernel communicate with Firecracker through shared buffers.
  • The guest creates buffers with a descriptor table and signals that the buffer is ready to be consumed. Each index of the table contains a table with an address and a length field for I/O to be performed. Since this is user provided input, it should be treated as malicious/untrusted. However, the validation of the data simply checks that an integer overflow hasn't occurred. So, what's the problem?
  • An address may NOT exist within an allocated memory region or overlap with a different region. Memory corruption is upon us! How do we exploit this though? Using the VsockPacket, it is possible to read or write out of bounds as long as the buffer starts in a valid region and ends in a valid region. So, we can use the space between two regions using the unsafe Rust code.
  • To exploit this vulnerability, an attacker needs code execution within the context of the kernel to hit the virtio-vsock driver. What's in that gap space? Nothing too interesting. The author eventually gave up on exploitation, simply because the overflow didn't allow for the overwriting of anything helpful. A buffer overflow into the stack was possible, but there were guard pages setup.
  • Since this bug was fixed, a few extra mitigations were put in place that are interesting. First, there are guard pages between all Memory Regions. This prevents this type of attack from happening in the future. Second, the there context is restricted via a jailer program and per thread secccomp filters. Hardening and exploit mitigations from the beginning make memory corruption vulnerabilities extremely hard to take to full code execution. Overall, good post on security design!