April 23rd, 2021 – Alisa Esage
This year I participated in the iconic Pwn2Own competition targeting Parallels Desktop in the Virtualization category (and if you haven't seen the livestream of my 0day exploit attempt, it's right here in the record, around 5 hours mark into the day, enjoy). While my Pwn2Own exploit is under embargo of responsible disclosure, I wanted to share a little fun "not-a-bug" proof-of-concept for Parallels Desktop.
While searching for security issues for Pwn2Own, I noticed an odd design pecularity with my research target: Parallels Desktop shares the user's home directory on the host operating system (MacOS) as a Parallels Shared Folder to the Guest OS *by default*, as soon as Parallels Tools are installed, which is also kind of default, unless you choose to opt out and tolerate virtualization usability issues. For anyone with a bit of knowledge about Unix-based operating systems (of which MacOS is an instance), and familiar with standard security expectations for hypervisors1, such a design decision would raise an instant "WTF?!". That said, it's not my job to judge any software vendor's design decisions, let's see how it works.
On all Unix-based operating systems of which MacOS is an instance, a write access to the user's home folder is essentially a "game over" from the attacker's perspective. While classic operating systems have long accepted the fact and routinely ensure privilege separation where it's due, hypervisors have to factor in their Host OS design specifics in new and unprecedented ways.
The first attack vector here would be an essential script which is most commonly known as the "bash profile":
When bash is invoked as an interactive login shell, or as a non-interac tive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior. -- MacOS Big Sur man pages for 'bash'
Obviously, on Linux this provides the login shell, but what about MacOS? Nothing special here: the registered interactive shell binary is executed each time when you launch the Terminal app (or some other process does it for you invisibly). As seen in the quoted man extracts from MacOS Big Sur, interactive shells behavior on Mac is fully compliant with Unix standards with respect to profile readings.
We also know that MacOS has switched from bash to zsh as a default interactive shell some time ago, which unsurprizingly, conforms to the same fashion:
Commands are then read from $ZDOTDIR/.zshenv. If the shell is a login shell, commands are read from /etc/zprofile and then $ZDOTDIR/.zprofile. Then, if the shell is interactive, commands are read from /etc/zshrc and then $ZDOTDIR/.zshrc. Finally, if the shell is a login shell, /etc/zlogin and $ZDOTDIR/.zlogin are read. -- MacOS Big Sur man pages for 'zsh'
Let's put it together: drop a malicious binary in the shared Home folder, and call it from .zprofile or whatever else interactive shell profile file. The binary will be executed on the host OS each time when the Terminal is launched. This constitutes a user-interacted RCE *plus* persistence and, in the virtualization context, a complete guest-to-host virtual machine escape. Don't forget about the .dot filename pattern to hide your malice from ls.
Does it have to be user-interacted? Not necessarily. Transcending from the classics and defaults of Unix-based OS, Macs have a directory named LaunchAgents under user's home, which is essentially a startup folder. User's apps can register themselves to run on startup (or more specifically, upon the user's login) by dropping a specially formatted configuration file here, named a ".plist". More details in the Apple's documentation.
It is important to note that the attacker's options for user's home folder are not exhausted by interactive shell profiles and LaunchAgents. One other thing that I noticed some software processes (such as Google Chrome's ksfetch updater binary) can run directly from ~/Library/Caches, that also may be hijacked for a fully automated arbitrary code execution. The general principle here is that a write access to the user's home folder is essentially an equivalent of executing a binary under the user's permissions in a potentially uncountable number of ways.
This demonstrates a full guest-to-host VM escape with persistence on Parallels Desktop 16.5.0 (both M1 and Intel), Ubuntu 20.04 guest OS with Parallels Tools installed:
cp mybinary /media/psf/Home/.hello chmod +x /media/psf/Home/.hello echo "~/.hello" >> /media/psf/Home/.zprofile
Proof-of-concept code with a sample "malicious payload" is also mirrored on my github. Note that it only includes a prebuilt payload for M1, which you need to rebuild if you want to test it on an Intel Mac.
As of today, a hypervisor is commonly assumed to enforce at least some basic security boundary and privilege separation between a virtual machine and the host OS. If a particular hypervisor product or deployment includes design points that break this assumption, a user must be explicitly warned at the moment of starting a VM, without the need to dig out for some special hidden options or documentation notices.
On the user's side, it is important to be aware of at least the most trivial ways how your system can be compromised. The easiest attack vectors are typically exploited by the most destructive types of malware.
1 and is not entirely adjusted to the security realities of modern software