NFsec Logo

Polecenie ldd i niezaufane pliki binarne

29/07/2023 w Bezpieczeństwo Możliwość komentowania Polecenie ldd i niezaufane pliki binarne została wyłączona

N

iewiele osób zdaje sobie sprawę z faktu, że polecenie ldd służące do wyświetlania bibliotek współdzielonych wymaganych przez dany program nie jest plikiem binarnym tylko skryptem w języku bash:

agresor@darkstar:~$ whereis ldd
ldd: /usr/bin/ldd /usr/share/man/man1/ldd.1.gz
agresor@darkstar:~$ file /usr/bin/ldd
/usr/bin/ldd: Bourne-Again shell script, ASCII text executable

W dodatku, jeśli przeczytamy stronę manualną tego polecenia natchniemy się na taki zapis:

Należy pamiętać, że w pewnych okolicznościach (np. gdy program określa interpreter ELF inny niż ld-linux.so), niektóre wersje ldd mogą próbować uzyskać informacje o zależnościach, próbując bezpośrednio wykonać program, co może doprowadzić do wykonania dowolnego kodu zdefiniowanego w interpreterze programu ELF, a być może do wykonania samego programu (w wersjach glibc 2.27, implementacja upstream ldd na przykład to robiła, chociaż większość dystrybucji dostarczała zmodyfikowaną wersję, która tego nie robiła).

Dlatego nigdy nie należy używać ldd na niezaufanym pliku wykonywalnym, ponieważ może to spowodować wykonanie dowolnego kodu.

Zapis ten znajduje swoją historię w CVE-2009-5064, czyli luce w sposobie, w jaki narzędzie ldd identyfikowało biblioteki dołączane dynamicznie. Jeśli osoba atakująca mogłaby nakłonić użytkownika do uruchomienia ldd na złośliwym pliku binarnym, mogłoby to spowodować wykonanie dowolnego kodu z uprawnieniami użytkownika uruchamiającego ldd. Przykłady takich aplikacji mogą zostać stworzone np. za pomocą osobnej biblioteki C do tworzenia wbudowanych systemów Linux. Wystarczy zlinkować szkodliwy kod z nowym programem ładującym, z którego usuniemy / zakomentujemy wykrywanie zmiennej LD_TRACE_LOADED_OBJECTS:

/*
   if (_dl_getenv("LD_TRACE_LOADED_OBJECTS", envp) != NULL) {
           trace_loaded_objects++;
   }
*/

Spowoduje to, że szkodliwy program zostanie uruchomiony przez program ładujący nawet, jeśli narzędzie systemowe ustawi taką zmienną. Teraz w samym programie należy wykrywać w/w zmienną, aby uzależnić od niej wersję uruchomionego kodu:

#include <stdio.h>
#include <stdlib.h>

int main()
{
   /* wykrycie uruchomienia ldd */
   if (getenv("LD_TRACE_LOADED_OBJECTS") != 0) {
      printf("szkodliwy kod\n");
      printf("\tlibc.so.6 => /lib/libc.so.6 (0x4001d000)\n");
      printf("\t/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)\n");
      return 0;
   }

   printf("normalny kod\n");
   return 0;
}

Jak widzimy nie do końca jest bezpieczne uruchamianie ldd na niezaufanych plikach binarnych. Skrypt ldd używa dynamicznego linkera do załadowania pliku binarnego i jego zależności do pamięci, a następnie polega na samym dynamicznym konsolidatorze, aby wyświetlić szczegóły w konsoli. Z tego powodu proces ten może być nadużywany w inny sposób niż zgodnie z przeznaczeniem np. do wstrzyknięcia kodu, jak było to w przypadku CVE-2019-1010023. W jaki więc sposób sprawdzać zależności? Oczywiście nieznane pliki binarne powinny być sprawdzane na specjalnie przygotowanym do tego środowisku. Po drugie możemy skorzystać bezpośrednio z linkera systemowego:

agresor@darkstar:~$ /lib64/ld-linux-x86-64.so.2 --verify /bin/ls \
                    && echo 'Plik obsługiwany!' || echo 'Plik nieobsługiwany!'

Jeśli plik jest obsługiwany, możemy go sprawdzić za pomocą składni:

agresor@darkstar:~$ LD_TRACE_LOADED_OBJECTS=1 /lib64/ld-linux-x86-64.so.2 /bin/ls
	linux-vdso.so.1 (0x00007ffe3b1dd000)
	libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f4b1111f000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4b10ef7000)
	libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f4b10e60000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f4b11177000)

No i proszę. Otrzymujemy dokładnie taki sam wynik, jaki wytworzyłby skrypt ldd (minus różnice w adresach pamięci pod którymi zostały załadowane biblioteki, ale to ze względu na ASLR).

Więcej informacji: ldd(1) and untrusted binaries, Compromising analysis tools, ldd can execute an app unexpectedly, The GNU C Library version 2.27 is now available

Wykrywanie zatrutych plików binarnych w Linuksie

09/01/2022 w Bezpieczeństwo 1 komentarz.

Z

atruwanie plików binarnych w Linuksie jest procesem, w którym atakujący podmienia często używane (dystrybucyjnie pre-instalowane) programy i narzędzia swoimi wersjami, które spełniają te same funkcje, ale dodatkowo wykonują złośliwe akcje. Może to być zastąpienie pliku nowym, zaprojektowanym tak, aby zachowywał się jak stare polecenie lub zmanipulowanie istniejącego (np. dopisanie na końcu instrukcji), aby bezpośrednio uruchamiało złośliwy kod. Próbkę tego procesu mogliśmy zobaczyć w ściągawce z informatyki śledczej w wykrywaniu włamań za pomocą linii poleceń Linuksa. Dzisiaj ją nieco rozwiniemy.
[ czytaj całość… ]

Wykrywanie szkodliwego oprogramowania stworzonego przez memfd_create()

20/02/2021 w Bezpieczeństwo Możliwość komentowania Wykrywanie szkodliwego oprogramowania stworzonego przez memfd_create() została wyłączona

Z

memfd_create() spotkaliśmy się przy okazji omawiania obchodzenia flagi montowania noexec. Nie jest to jedyny przypadek, gdzie pomysł bezplikowej metody jest stosowany. Złośliwe oprogramowanie również stosuje bezplikową technikę do wstrzykiwania się w ramach działającego systemu Linux, aby nie pozostawić żadnych śladów na dysku. Przypomnijmy szybko, co robi wywołanie memfd_create(): pozwala na utworzenie pliku, który rezyduje w części pamięci RAM. Strona manualna opisuje to jako:
[ czytaj całość… ]

Odzyskiwanie skasowanej binarki z aktywnego procesu szkodliwego oprogramowania

17/06/2020 w Bezpieczeństwo Możliwość komentowania Odzyskiwanie skasowanej binarki z aktywnego procesu szkodliwego oprogramowania została wyłączona

S

zkodliwe oprogramowanie na systemach Linux bardzo często usuwa swoje pliki binarne po uruchomieniu. Ma to na celu oszukanie skanerów oraz systemów kontroli integralności, które bazują na analizie plików. Dla przykładu takiego zachowania posłużymy się kopią polecenia sleep:

cd /tmp
cp /bin/sleep x
./x 3600 &
rm x

Możemy teraz sprawdzić, czy rzeczywiście plik już nie istnieje:

root@darkstar:~# ls -al /tmp/x
ls: cannot access /tmp/x: No such file or directory

Spójrzmy teraz na listę procesów:

root      1437  0.0  0.0   6176   780 pts/1    S    21:11   0:00 ./x 3600

Idąc tropem PID możemy sprawdzić informacje w /proc

root@darkstar:/tmp# ls -al /proc/1437/exe
lrwxrwxrwx 1 root root 0 Jun 17 21:15 /proc/1437/exe -> '/tmp/x (deleted)'

System pokazuje nam skasowany obiekt w podanej ścieżce, ale system plików Linuksa tak naprawdę nie usunie tego pliku, dopóki uruchomiony proces ma go w stanie otwartym. Plik tam jest, ale po prostu nie jest nam pokazywany. Link symboliczny /proc/1437/exe z łatwością jest nam w stanie dostarczyć plik binarny, który uruchomił dany proces. Po prostu możemy go skopiować w dowolne miejsce, aby poddać go dalszej analizie:

root@darkstar:/tmp# cp /proc/1437/exe /tmp/y
root@darkstar:/tmp# sha1sum /tmp/y
bebcce23072c4d831ce8e2822a0858d6aa813067  /tmp/y
root@darkstar:/tmp# sha1sum /bin/sleep
bebcce23072c4d831ce8e2822a0858d6aa813067  /bin/sleep

Więcej informacji: How To Recover A Deleted Binary From Active Linux Malware