Capturing and Tampering TPM Communication in Windows Virtual Machines

We have released a library that supports capturing and tampering with TPM communication. In this article, we will guide you through setting up the environment and the steps to capture and tamper with the communication between a Windows virtual machine and a virtual TPM.

This is a translated article. The original Japanese article is here.

Preparation

You will need one PC. Having a TPM is not strictly necessary, but it can add a bit more fun to the process. The overall flow will involve installing Linux (Ubuntu) first, and then installing Windows on a virtual machine running on Linux. Therefore, you’ll need a machine with specifications that can support the installation of Windows 11.

Once your PC is ready, follow these steps:

  • Enable virtualization features in BIOS (UEFI)
  • Install Ubuntu 24.04
    • Any Linux distribution that supports running virtual machine will work (Arch Linux is also a great option!)
    • For this article, we will base the procedure on Ubuntu 24.04 commands, packages, and paths.
  • Obtain a Windows 11 installer
    • The more features, the more enjoyable the experience will be
    • In this article, we will install Windows 11 Pro.

Installing Packages

After installing the necessary packages, add the currently logged-in user to a few groups to make various operations easier.

sudo apt update
sudo apt install qemu-system-x86 virt-viewer ovmf swtpm swtpm-tools tpm2-tools golang libfuse-dev wireshark
sudo gpasswd -a "$USER" kvm
sudo gpasswd -a "$USER" tss
sudo gpasswd -a "$USER" wireshark

Re-login

To apply the group changes, log out and then log back in. Launch Wireshark and check if you can capture traffic on the loopback interface (lo). If it doesn’t work properly, a system reboot might help.

Verifying SWTPM Operation

Run the following command and confirm that information related to the TPM is displayed. After confirming, you can stop swtpm by pressing Ctrl+C.

mkdir "$HOME"/swtpm
swtpm socket --tpmstate dir="$HOME"/swtpm --tpm2 --ctrl type=unixio,path="$HOME"/swtpm/swtpm.sock.ctrl --server type=unixio,path="$HOME"/swtpm/swtpm.sock --flags not-need-init,startup-clear
tpm2_getcap --tcti=swtpm:path="$HOME"/swtpm/swtpm.sock properties-fixed

Preparing QEMU

Run the following commands to prepare for the installation of Windows 11 on QEMU. In this article, we will store various files directly in the home directory, but feel free to modify the paths as needed to suit your preferences.

wget -O "$HOME"/virtio-win.iso https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso
qemu-img create -f qcow2 "$HOME"/win11.qcow2 64G
cp /usr/share/OVMF/OVMF_VARS_4M.ms.fd "$HOME"

Starting QEMU

Each time you shut down QEMU with Windows, SWTPM also stops. To keep it running continuously, execute the following infinite loop:

while true; do swtpm socket --tpmstate dir="$HOME"/swtpm --tpm2 --ctrl type=unixio,path="$HOME"/swtpm/swtpm.sock.ctrl; done

Next, specify SWTPM as the TPM device for QEMU and start QEMU. We assume that the Windows 11 installer is named win11.iso and located directly in your home directory. If you want Windows to have internet access, remove the -nic none option from the QEMU command.

qemu-system-x86_64 \
  -machine q35,accel=kvm \
  -m 4096 \
  -cpu host \
  -smp 2,sockets=1,dies=1,cores=2,threads=1 \
  -display spice-app \
  -nic none \
  -drive file="$HOME"/win11.qcow2,if=virtio,format=qcow2,discard=unmap \
  -drive file="$HOME"/win11.iso,index=0,media=cdrom \
  -drive file="$HOME"/virtio-win.iso,index=1,media=cdrom \
  -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE_4M.secboot.fd,readonly=on \
  -drive if=pflash,format=raw,file="$HOME"/OVMF_VARS_4M.ms.fd \
  -chardev socket,id=chrtpm,path="$HOME"/swtpm/swtpm.sock.ctrl \
  -tpmdev emulator,id=tpm0,chardev=chrtpm \
  -device tpm-tis,tpmdev=tpm0

Installing Windows

If you're prompted to select an edition, choose Windows 11 Pro.

When you reach the step to select the storage for installation, click on Load driver.

Load driver

Next, select VirtIO for Windows 11 (VirtIO w11) and proceed with the installation.

VirtIO for Windows 11

During the initial setup after installation, you might be prompted for internet access or to sign in with a Microsoft account. You can either follow the prompts or look up methods to create a local account (the bypass methods often change). While I can only speculate about the reasons behind this, personally, I prefer to avoid unnecessary network access during such testing, so I hope Microsoft would allow a bit more flexibility in this regard.. 🙇

Once the installation is complete, shut down Windows and stop SWTPM by pressing Ctrl+C. It might also be a good idea to take a snapshot of the current state.

qemu-img snapshot -c init "$HOME"/win11.qcow2

Packet Capture

The setup is now complete. This is where the real work begins.

First, switch SWTPM to use TCP communication and start it.

while true; do swtpm socket --tpmstate dir="$HOME"/swtpm --tpm2 --server port=2321 --ctrl type=tcp,port=2322; done

Next, launch the sample program from TPMProxy, qemu_swtpm_forward. This program intercepts communication on the UNIX domain socket instead of SWTPM, receives file descriptors, and forwards the communication to SWTPM.

go run github.com/CyberDefenseInstitute/tpmproxy/example/qemu_swtpm_forward@latest

Wireshark, it's your time to shine!

wireshark -k -i lo -f 'tcp portrange 2321-2322' -Y 'tpm'

Now, start QEMU Windows, specifying that TPM communication should be directed towards /tmp/qemu_swtpm_fwd.sock and... watch the magic happen!

qemu-system-x86_64 \
  -machine q35,accel=kvm \
  -m 4096 \
  -cpu host \
  -smp 2,sockets=1,dies=1,cores=2,threads=1 \
  -display spice-app \
  -nic none \
  -drive file="$HOME"/win11.qcow2,if=virtio,format=qcow2,discard=unmap \
  -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE_4M.secboot.fd,readonly=on \
  -drive if=pflash,format=raw,file="$HOME"/OVMF_VARS_4M.ms.fd \
  -chardev socket,id=chrtpm,path=/tmp/qemu_swtpm_fwd.sock \
  -tpmdev emulator,id=tpm0,chardev=chrtpm \
  -device tpm-tis,tpmdev=tpm0

🎉

There is another sample program similar to qemu_swtpm_forward called qemu_swtpm_dissect. This sample doesn't rely solely on Wireshark for packet analysis; it also attempts to analyze the packets using Go-TPM. I will introduce this in more detail at another time.

Packet Tampering

Not only can you capture the communication, but tampering with the packets is also possible.

First, shut down the Windows virtual machine where you were capturing packets. qemu_swtpm_forward should have exited automatically, but if it's still running, stop it with Ctrl+C. You can leave SWTPM and Wireshark running as they are.

Now, launch the Proof of Concept program, qemu_swtpm_tamper, which simply changes the TPM manufacturer to XYZ.

go run github.com/CyberDefenseInstitute/tpmproxy/example/qemu_swtpm_tamper@latest

Then, run QEMU Windows again with the same command as before and watch what happens...

qemu-system-x86_64 \
  -machine q35,accel=kvm \
  -m 4096 \
  -cpu host \
  -smp 2,sockets=1,dies=1,cores=2,threads=1 \
  -display spice-app \
  -nic none \
  -drive file="$HOME"/win11.qcow2,if=virtio,format=qcow2,discard=unmap \
  -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE_4M.secboot.fd,readonly=on \
  -drive if=pflash,format=raw,file="$HOME"/OVMF_VARS_4M.ms.fd \
  -chardev socket,id=chrtpm,path=/tmp/qemu_swtpm_fwd.sock \
  -tpmdev emulator,id=tpm0,chardev=chrtpm \
  -device tpm-tis,tpmdev=tpm0

💪

Conclusion & Next Time Preview

In this article, we walked through the steps to use sample programs from the TPMProxy library, which supports capturing and tampering with TPM communication. I hope this gave you a sense of the possibilities for what can be done.

With Windows 11 requiring TPM 2.0 devices, the use of TPM for application development is expected to grow. However, countermeasures against wiretapping and tampering of TPM communication are still not widely implemented. While TPM communication can be encrypted, there is very little information available on the topic. Upon closer examination of the limited available information, we found that due to small mistakes, sensitive information is sometimes transmitted in plain text or not encrypted at all. Capturing the actual communication makes this immediately clear, but even TPM experts might struggle to easily observe TPM communication. It seems that reviewing this communication is not a standard practice.

In light of this, we developed and released TPMProxy to address these issues.

This article primarily focused on the setup, and some may have gotten the impression that you can only observe communication using an emulator. While capturing communication on real hardware requires tools like a logic analyzer, it is still possible (though I've never seen tampering in practice, it is theoretically possible). This is why we occasionally see articles claiming successful decryption of BitLocker-encrypted drives by extracting keys from TPM communication (some of these articles even falsely attribute this to TPM vulnerabilities).

In the next article, we will explore the process of decrypting a BitLocker-encrypted drive using TPMProxy.

At Cyber Defense Institute, we are conducting research and development on PIV Gateway™, a zero-trust system using TPM remote attestation technology as a root of trust. PIV Gateway™ supports encryption of TPM communication parameters. We hope to explain what TPM communication parameter encryption entails and discuss the challenges of its practical application.

Until next time, enjoy your TPM adventures! 👋

© 2016 - 2024 DARK MATTER / Built with Hugo / Theme Stack designed by Jimmy