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
.
Next, select VirtIO for Windows 11 (VirtIO w11
) and proceed with the installation.
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! 👋