Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book

Czym w praktyce jest technika DLL side-loading, stosowana przez niektóre szkodliwe oprogramowanie?

13 lutego 2023, 17:13 | Teksty | komentarzy 5

Złośliwe oprogramowanie (ang. malware) chętnie wykorzystuje cechy charakterystyczne bibliotek dołączanych dynamicznie (.dll). Podstawową cechą charakterystyczną bibliotek .dll jest to, że potrzebują procesu, który wykona zawarty w nich kod. Stąd wszelkie nadużycia w postaci wstrzykiwania złośliwych bibliotek .dll do procesów zaufanych programów. Np. przypadek z roku 2020 o załadowaniu złośliwej biblioteki do procesu programu antywirusowego Defender w systemie Windows.

Jeśli system Windows lub zainstalowana aplikacja sprawdza jedynie nazwę biblioteki .dll do załadowania bez weryfikacji sumy kontrolnej czy podpisu cyfrowego, to istnieje możliwość podmiany takiej biblioteki .dll na złośliwą.

Niniejszy tekst przedstawia przykład załadowania złośliwej biblioteki .dll do zaufanego i podpisanego cyfrowo programu. Technika ta jest oznaczona w MITRE ATT&CK identyfikatorem T1574.

Biblioteki dynamiczne w systemie Windows

Oprogramowanie komputerowe często składa się z odrębnych modułów. Bardziej zaawansowane aplikacje nie są monolitem w postaci jednego pliku. Dzięki temu w przypadku aktualizacji programu do nowej wersji nie zmienia się całości tylko podmienia poszczególne komponenty na nowsze.

Czytelnicy, którzy mają jakiekolwiek doświadczenie w budowaniu aplikacji dla systemu Windows (rysunek 1) zapewne kojarzą dwa rodzaje bibliotek takie jak:

  • statyczna (rozszerzenie .lib) wbudowywana w plik programu,
  • dołączana dynamicznie (rozszerzenie .dll) często dystrybuowana obok plików programu (nie wymaga ponownej kompilacji całego oprogramowania)

Biblioteki .dll pozwalają zatem na współdzielenie tego samego kodu i aktualizacje poszczególnych funkcjonalności bez ponownej kompilacji całego programu.

Rysunek 1. Rodzaje aplikacji dla pulpitu Windows w Visual C++

Z myślą o początkujących Czytelnikach warto dodać, że biblioteki .dll nie uruchomimy tak jak zwykłego programu np. poprzez podwójne kliknięcie (rysunek 2).

Rysunek 2. Biblioteki .dll nie uruchamia się tak jak pliku wykonywalnego .exe

Dzieje się tak, ponieważ biblioteka .dll musi zostać uruchomiona w kontekście jakiegoś procesu. Jednym ze sposobów uruchomienia wybranej funkcji z biblioteki .dll może być wywołanie narzędzia rundll32.exe podając mu jako argument nazwę biblioteki oraz po przecinku nazwę funkcji do wywołania (rysunek 3).

Rysunek 3. W celu wywołania określonej funkcji z biblioteki .dll można użyć narzędzia rundll32.exe

Przykład podatnej aplikacji

Pierwszą fazą przygotowania ataku jest odnalezienie aplikacji, która może być podatna na DLL Side-loading (T1574.002).

Można to wykonać poprzez analizę statyczną lub dynamiczną badając funkcje ładujące biblioteki .dll takie jak np. LoadLibrary. Innym prostszym sposobem może być sprawdzenie czy eksperymentalne usunięcie biblioteki .dll znajdującej się w katalogach programu będzie wyświetlało komunikat o jej braku. Najbardziej wartościowe dla atakujących będą podatne pliki systemu Windows, gdyż często znajdują się one na white list programów antywirusowych i innych narzędzi obronnych. Poza plikami systemu Windows atakujący mogą użyć też inne budzące zaufanie aplikacje np. podpisane cyfrowo oprogramowanie typu third party. Przykładowa aplikacja na którą trafiłem całkiem przypadkowo okazała się być podatna na DLL side-loading. Jest to przeglądarka arkuszy programu Excel (rysunek 4).

Program: Free Excel Viewer 2.2.0.4

Link: https://www.pdfexcelconverter.com/down/freeexcelviewer.exe [dostęp: 2023-02-05]

Nazwa pliku instalatora: freeexcelviewer.exe

Suma kontrolna SHA-256:

e004aa1d768d28263dc3961185dd8f65194e33a21e797594b2f69014a57f51bc

Raport skanowania antywirusowego: https://www.virustotal.com/gui/file/e004aa1d768d28263dc3961185dd8f65194e33a21e797594b2f69014a57f51bc

Rysunek 4. Przykładowa podatna aplikacja freeexcelviewer.exe jest podpisana cyfrowo i nieszkodliwa

Znaleziona i użyta jako przykład dla tego artykułu aplikacja freeexcelviewer.exe posiada certyfikat DigiCert EV Code Signing CA (rysunek 5).

Rysunek 5. Przykładowa podatna aplikacja to freeexcelviewer.exe

Tego typu podpis ma zagwarantować, że oprogramowanie pochodzi od znanego wydawcy oraz nie zostało zmodyfikowane (rysunek 6). Certyfikat ma ważność do lutego 2024 roku (rysunek 7).

Rysunek 6. Certyfikat podatnej aplikacji ma zapewnić, że program pochodzi od sprawdzonego wydawcy i nie został zmodyfikowany

Rysunek 7. Podatna aplikacja freeexcelviewer.exe w dzień eksperymentu ma ważny certyfikat

Z myślą o początkujących Czytelnikach warto dodać, że jakakolwiek zmiana w kodzie podpisanego cyfrowo programu (rysunek 8) spowoduje, że certyfikat zostanie utracony (rysunek 9).

Rysunek 8. Najmniejsza zmiana w kodzie podpisanego programu i tracimy certyfikat (dekompilacja pliku *.exe w narzędziu dnSpy)

Rysunek 9. Program po zmodyfikowaniu nie ma już ważnego podpisu cyfrowego – nie tędy droga

Po otwarciu folderu z podatną aplikacją możemy zauważyć, że znajduje się tam kilka bibliotek .dll. Przykładową biblioteką w której umieścimy ładunek będzie unvell.ReoGrid.dll (rysunek 10). Jest to moduł do obsługi arkuszy kalkulacyjnych z repozytorium w witrynie GitHub pod adresem: https://github.com/unvell/ReoGrid

Rysunek 10. Biblioteka .dll w której umieszczony będzie ładunek

Za pomocą Process Explorer możemy zweryfikować (rysunek 11), że biblioteka unvell.ReoGrid.dll jest wczytywana do pamięci programu freeexcelviewer.exe.

Rysunek 11. Weryfikacja wczytywanych modułów .NET (bibliotek .dll) przez program freeexcelviewer.exe za pomocą narzędzia Process Explorer

Czas wybrać miejsce w kodzie biblioteki, gdzie umieścimy ładunek. Niech miejscem umieszczenia ładunku będzie okno ustawień drukowania podatnej aplikacji (rysunek 12), czyli metoda o nazwie PrintSettings (konstruktor klasy PrintSettings).

Rysunek 12. Ładunek zostanie wykonany po otworzeniu okna drukowania w podatnym programie freeexcelviewer.exe

W międzyczasie przygotowano niegroźny kod ładunku w języku C# dla celów demonstracyjnych (rysunek 13), który zwyczajnie pobiera ładunek tekstowy z witryny internetowej. W sytuacji realnej, poza laboratorium, cyberprzestępca w ten sposób mógłby w sposób automatyczny pobrać ciąg złośliwych instrukcji na komputer ofiary.

Rysunek 13. Przygotowany kod ładunku na potrzeby tego artykułu będzie nieszkodliwy, a jego zadaniem będzie pobranie wiadomości tekstowej z witryny pełniącej rolę Command&Control (cyberprzestępczego centrum dowodzenia)

Kolejny krok to skopiowanie kodu ładunku do schowka poprzez wybranie w narzędziu dnSpy: Edit IL Instructions > Copy (rysunek 14).

Rysunek 14. Kopiujemy do schowka systemowego kod ładunku w C#.NET

W schowku systemowym mamy ładunek w postaci kodu w języku IL (ang. Intermediate Language). Ten język pośredni nazywany jest Asemblerem platformy .NET, czyli językiem niskopoziomowym. Otwieramy (Edit IL Instructions) okno edycji kodu konstruktora PrintSettings() okna drukowania w bibliotece unvell.ReoGrid.dll (rysunek 15), aby wkleić tam kod ładunku (Paste After Selection).

Rysunek 15. Wyświetlamy kod konstruktora PrintSettings() jako listing Asemblera IL (nazywanego też CIL lub MSIL – jest to Asembler platformy .NET)

Na rysunku 16 możemy teraz zobaczyć, że na końcu kodu konstruktora klasy PrintSettings znajduje się kod ładunku.

Rysunek 16. Wklejamy kod ładunku na końcu kodu konstruktora PageSettings()

Czas zapisać zmodyfikowaną bibliotekę .dll poprzez wybranie z górnego menu File > Save Module (rysunek 17).

Rysunek 17. Zapisujemy zmodyfikowaną bibliotekę .dll do katalogu z podatnym programem freeexcelviewer.exe

Edycja kodu w pliku biblioteki .dll spowodowała zmianę daty i czasu ostatniej modyfikacji (rysunek 18).

Rysunek 18. Umieszczenie ładunku w bibliotece .dll spowodowało zmianę daty ostatniej modyfikacji

Atakujący w celu zmniejszenia szansy wykrycia złośliwego ładunku przez analityków, oprogramowanie antywirusowe czy inne programy obronne mogą przywrócić poprzedni czas i datę ostatniej modyfikacji pliku biblioteki (rysunek 19). Datę i czas ostatniej modyfikacji pliku możemy skorygować przykładowo takim kodem w C#.NET:

Listing 1. Korygowanie czasu i daty modyfikacji pliku biblioteki.

string path = @"C:\Isolated\FreeExcelViewer\unvell.ReoGrid.dll";
var dateTime = new DateTime(2019, 07, 22, 10, 43, 0, 0, DateTimeKind.Local);
File.SetCreationTime(path, dateTime);
File.SetLastWriteTime(path, dateTime);

Rysunek 19. Biblioteka z ładunkiem oraz czysta kopia (.bak) mają teraz taką samą datę modyfikacji

Teraz, gdy uruchomimy podatny program freeexcelviewer.exe, to załadowana zostanie zmodyfikowana biblioteka unvell.ReoGrid.dll. Pamiętamy, że kod ładunku umieściliśmy w konstruktorze klasy PrintSettings. Otwórzmy zatem okno ustawień drukowania (rysunek 20).

Rysunek 20. Uruchamiamy podatny program oraz otwieramy okno drukowania, gdyż tam jest kod ładunku

Po otwarciu okna ustawień drukowania możemy zauważyć, że dołączony przez nas kod został uruchomiony i pomyślnie pobrał tekstowy ładunek stworzony dla celów demonstracyjnych tego artykułu (rysunek 21).

Rysunek 21. Kod ładunku został uruchomiony

Wskazówka: Jeśli żądanie metody GET wykonywane przez klasę HttpClient w kodzie ładunku zwraca błąd: Could not create SSL/TLS secure channel, to na początku kodu ładunku można dodać:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

Podsumowanie

Niniejszy eksperyment w sposób klarowny zaprezentował jakim zagrożeniem jest niezabezpieczenie w programie mechanizmu ładowania bibliotek .dll. Podatność DLL Side-loading w przykładowym programie freeexcelviewer.exe pozwoliła nam osiągnąć nieautoryzowane wykonanie kodu umieszczonego w bibliotece .dll w kontekście procesu zaufanego programu z podpisem cyfrowym (rysunek 22).

Rysunek 22. Niczemu niewinny program freeexcelviewer.exe poprzez załadowanie zmodyfikowanej biblioteki .dll wykonał kod ładunku (ang. payload)

Zalecenia bezpieczeństwa

Twórcy oprogramowania powinni weryfikować biblioteki ładowane przez ich aplikacje np. za pomocą sprawdzania sumy kontrolnej (funkcji skrótu, ang. hash).

Administratorzy systemów powinni zwracać uwagę na podpisane cyfrowo programy, które ładują niepodpisane biblioteki .dll (rysunek 22). Monitorować ruch sieciowy pochodzący z takich procesów. Skanować procesy w poszukiwaniu złośliwych ładunków. Warto też sprawdzić datę i czas kompilacji podejrzanej biblioteki (ang. compiler timestamp).

Rysunek 22. Narzędzia z pakietu Sysinternals do monitorowania procesów w systemie Windows

Administratorzy i użytkownicy komputerów powinni aktualizować używane oprogramowanie, gdyż nowsze wersje aplikacji mogą zawierać poprawkę na podatność DLL Side-loading oraz inne błędy.

Należy jednak pamiętać, że istnieje też duże prawdopodobieństwo nieumyślnego pobrania złośliwej wersji oprogramowania. Wiele tego typu przypadków opisywaliśmy w ostatnim czasie:

Warto też zapoznać się rekomendacjami bezpieczeństwa opisanymi w następującym dokumencie:

Dynamic-Link Library Security – Win32 apps | Microsoft Learn

https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-security

Autor tekstu: Dawid Farbaniec

Wykaz literatury

Hijack Execution Flow: DLL Side-Loading | https://attack.mitre.org/techniques/T1574/002/

DLL Side-loading & Hijacking — Using Threat Intelligence to Weaponize R&D |

https://www.mandiant.com/resources/blog/abusing-dll-misconfigurations

Dynamic-Link Library Security | https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-security

THREAT ANALYSIS REPORT: DLL Side-Loading Widely (Ab)Used | https://www.cybereason.com/blog/threat-analysis-report-dll-side-loading-widely-abused

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. thrull

    Hy hy, w zamierzchłych czasach nie umiałem odpalić sniffera na windowsie kiedy próbowałem zhaczyć protokół jednego z najbardziej popularnych ówczas komunikatorów (kto zgadnie który?). Zrobiłem proxy dllkę wsock32.dll która ładnie mi całą komunikację wyraportowała. I powstał klient na linuksa (a nawet dwa). Wystarczyło ją wgrać do katalogu z programem – wg. Microsoftu nadal powinno zadziałać – LoadLibrary poszuka dllki z lokalnym katalogu aplikacji (a potem wg. kolejności ustalonej przez system). Do reverse cały cały czas dobre narzędzie. Nie tylko do złych rzeczy :-)

    Odpowiedz
  2. Lep

    O takie artykuły nic nie robiłem! ;)

    Odpowiedz
  3. Timi

    Świetny artykuł! Oby więcej takich :)

    Odpowiedz
  4. Zbigniew

    Oby więcej artykułów w tej konwencji. Super robota

    Odpowiedz
  5. Popieram słowa poprzedników: świetny artykuł i czekam na więcej :-)

    Odpowiedz

Odpowiedz