The XZ Backdoor issue triggered by one untrusted maintainer

A malicious backdoor was introduced into XZ Utils via a compromised/trusted maintainer account (JiaT75) and shipped in a tarball (5.6.0/5.6.1) by modifying the Automake build scripts (build-to-host.m4) and embedding an obfuscated two-stage payload. The backdoor installs as liblzma, hooks RSA-related symbols via an IFUNC resolver to verify attacker-supplied signatures in sshd and execute arbitrary commands. #XZUtils #CVE-2024-3094

Keypoints

  • Supply-chain compromise: a maintainer account (JiaT75) released XZ Utils versions 5.6.0/5.6.1 containing a backdoor embedded in a modified build-to-host.m4 and test files.
  • Build-process infection: attacker added build-to-host.m4 to .gitignore and used Automake/autoconf macros to execute obfuscated scripts during ./configure and the tests build.
  • Two-stage obfuscated payload: Stage 1 extracts a compressed bash script from test data; Stage 2 verifies environment, decrypts payload via a custom RC4-like PRNG/addition scheme, then decompresses and runs the final payload.
  • IFUNC/GOT hooking: malicious code modifies the Global Offset Table during ifunc resolution to hook RSA_public_decrypt (with fallbacks to EVP_PKEY_set1_RSA and RSA_get0_key) so sshd will validate attacker-supplied signatures and run commands.
  • Activation vector: because libsystemd pulls liblzma into many downstream sshd builds, the malicious liblzma can load into sshd (/usr/sbin/sshd) and remain dormant unless presented with the crafted signed payload.
  • Mitigation/detection: downgrade to 5.4.x (or later safe releases), restart/inspect sshd, apply the documented kill-switch environment variable, and use published detectors (JFrog, Elastic, Andres Freund scripts, etc.).

MITRE Techniques

  • [T1593.003] Code Repositories – Attacker used the project repository and contributor trust to introduce malicious changes: [‘Version 5.6.0 published with malicious build-to-host.m4’]
  • [T1585.002] Email Accounts – Attacker altered project contact/ownership vectors to route trust and communication: [‘Changed bug report email address from his own account to XZ official account ([email protected]) — The above email address redirects emails to himself’]
  • [T1195.001] Compromise Software Dependencies and Development Tools – Malicious build artifact (tarball) contained an ignored m4 script that executes during build, propagating upstream: [‘the attacker changed part of the build-to-host.m4 script and used it as the first stage to load malware.’]
  • [T1059.004] Unix Shell – The payload extracts and executes bash scripts during the build and runtime stages: [‘the bash script extracted … decompress the replaced data into lzma … and run the bash script corresponding to Stage 2.’]
  • [T1140] Deobfuscate/Decode Files or Information – The backdoor uses layered obfuscation and custom decryption (tr transformations, custom PRNG and addition-based decryption) before executing payloads: [‘Use the AWK command to decrypt using the numbers obtained using the PRNG algorithm of RC4 … The decrypted data is then decompressed.’]
  • [T1573.001] Symmetric Cryptography – Encrypted payloads and command data are protected with symmetric ciphers (ChaCha20 keyed from hard-coded ED448 public key fragment) before signature verification: [‘The ED448 public key is hard-coded into the malware, and it attempts to decrypt data by using the first 32 bytes of the public key as the decryption key for the Chacha20 algorithm.’]
  • [T1078] Valid Accounts – Attacker operated via a trusted maintainer identity (or compromised maintainer account) to push malicious code: [‘a user named JiaT75 released a tarball containing backdoor code … To insert this backdoor, the attacker served as a trusted Maintainer of XZ Utils for at least two years.’]

Indicators of Compromise

  • [Email] maintainer/contact – jiat0218[@]gmail.com
  • [File name] malicious build/artifact – build-to-host.m4, tests/files/bad-3-corrupt_lzma2.xz
  • [Tarball / Versions] released malicious versions – 5.6.0, 5.6.1
  • [File hash] malicious tarballs / artifacts – 81e0fd62752bdab11fa992af9d9545af, 307958b78b392e58a2c88e620a121708, and 12 more hashes
  • [Repository / Domain] upstream sources referenced – https://github.com/tukaani-project/xz, https://git.tukaani.org/?p=xz.git

The attack chain begins with a trusted-contributor compromise (JiaT75) and a modified Automake/autoconf macro (build-to-host.m4) added to .gitignore so the altered script was not inspected in the repository. During ./configure and the Automake test build, that m4 macro uses sed/tr transformations on embedded test files (bad-3-corrupt_lzma2.xz, good-large_compressed.lzma) to reconstruct and xz-decompress an initial bash script (Stage 1). Stage 1 extracts a payload fragment by repeatedly reading fixed-size blocks, applying character substitutions, and then decompressing to run a secondary (Stage 2) script.

Stage 2 performs environment checks (build type, architecture, packaging context) and reconstructs the remaining encrypted payload data by merging pieces read earlier. It then applies a custom RC4-like PRNG (S[i] = ((7*i)+5)%256), consumes PRNG output (4,096 bytes in 5.6.0; 8,196 bytes in 5.6.1), and decrypts the payload by addition (not XOR). The decrypted blob is decompressed to reveal the final native payload and scripts.

The native payload modifies runtime linking by exploiting IFUNC resolution to overwrite GOT entries for RSA_public_decrypt (with fallbacks to EVP_PKEY_set1_RSA and RSA_get0_key), redirecting those calls to malicious code. Because many downstream sshd builds load liblzma via libsystemd, the infected liblzma can load into /usr/sbin/sshd; the backdoor then uses a hard-coded ED448 public key (first 32 bytes → ChaCha20 key) to decrypt command data and verify a signature before executing attacker-supplied commands, leaving minimal logs. Disable/mitigation options include downgrading to 5.4.x (or updating to patched releases), restarting sshd, applying the documented kill-switch environment variable, and using published detection tools (JFrog, Elastic, Andres Freund scripts, XZ scanners).

Read more: https://medium.com/s2wblog/the-xz-backdoor-issue-triggered-by-one-untrusted-maintainer-2d5e5c1273d0