Dane oryginału

Copyright © 2019 by Alex Matrosov, Eugene Rodionov, and Sergey Bratus. Title of English-language original: Rootkits and bootkits: Reversing Modern Malware and Next Generation Threats, ISBN 978-0-2620-3925-3, published by No Starch Press. Polish-language edition copyright © 2020 by Polish Scientific Publishers PWN Wydawnictwo Naukowe PWN. All rights reserved.

Przekład Marek Włodarz na zlecenie WITKOM Witold Sikorski

Projekt okładki i stron tytułowych Joanna Andryjowicz na podstawie oryginału

Wydawcy Edyta Kawala, Joanna Banasiak-Lach

Redaktor prowadzący Jolanta Kowalczuk

Redaktor Izabela Mika

Koordynator produkcji Anna Bączkowska

Skład wersji elektronicznej na zlecenie Wydawnictwa Naukowego PWN

Aneta Pudzisz/Woblink

Zastrzeżonych nazw firm i produktów użyto w książce wyłącznie w celu identyfikacji.

Copyright © for the Polish edition by Wydawnictwo Naukowe PWN SA

Warszawa 2020

ISBN 978-83-01-21540-8

eBook został przygotowany na podstawie wydania papierowego z 2020 r., (Wydanie I)

Wydawnictwo Naukowe PWN SA

02-460 Warszawa, ul. Gottlieba Daimlera 2

tel. 22 69 54 321, faks 22 69 54 288

infolinia 801 33 33 88

e-mail: pwn@pwn.com.pl; reklama@pwn.pl

www.pwn.pl

Dla naszych rodzin i tych,

którzy przyczynili się do powstania tej książki

O autorach

Alex Matrosov jest głównym, ofensywnym badaczem bezpieczeństwa w firmie NVIDIA. Ma ponad dwadzieścia lat doświadczenia w dziedzinie inżynierii odwrotnej, zaawansowanych technik analizy złośliwego oprogramowania, bezpieczeństwa oprogramowania wbudowanego i technik nadużywania. Przed dołączeniem do NVIDIA Alex pełnił funkcję głównego badacza bezpieczeństwa w Intel Security Center of Excellence (SeCoE), spędził ponad sześć lat w zespole Intel Advanced Threat Research i zajmował stanowisko starszego badacza bezpieczeństwa w ESET. Alex jest autorem i współautorem licznych artykułów badawczych oraz prelegentem na konferencjach branżowych, w tym na REcon, ZeroNights, Black Hat, DEFCON i wielu innych. Otrzymał od Hex-Rays nagrodę za swoją wtyczkę HexRaysCodeXplorer, od roku 2013 wspieraną przez zespół w REhint.

Eugene Rodionov, dr, pełni funkcję badacza bezpieczeństwa w firmie Intel i zajmuje się zabezpieczeniami BIOS dla platform klienckich. Wcześniej Rodionov prowadził wewnętrzne projekty badawcze i wykonywał pogłębione analizy zaawansowanych zagrożeń w ESET. Do jego obszaru zainteresowań należą zabezpieczenia oprogramowania wbudowanego, programowanie w trybie jądra, technologie antyrootkitowe i inżynieria odwrotna. Rodionov występował na wielu konferencjach branżowych takich jak Black Hat, REcon, ZeroNights i CARO. Jest też współautorem licznych artykułów naukowych.

Sergey Bratus jest profesorem nadzwyczajnym na wydziale informatyki Dartmouth College. Poprzednio pracował w BBN Technologies nad badaniami przetwarzania języka naturalnego. Bratus interesuje się wszelkimi aspektami zabezpieczeń systemów Unix, a w szczególności zabezpieczeniami jądra Linux oraz wykrywaniem i odwrotną inżynierią złośliwego oprogramowania dla systemu Linux.

O recenzencie technicznym

Rodrigo Rubira Branco (BSDaemon) pracuje jako Chief Security Researcher w Intel Corporation, gdzie kieruje zespołem STORM (Strategic Offensive Research and Mitigations). Rodrigo ujawnił dziesiątki podatności w wielu ważnych technologiach i publikował innowacyjne badania na temat eksploitacji, inżynierii odwrotnej i analiz złośliwego oprogramowania. Jest członkiem RISE Security Group i jednym z organizatorów Hackers to Hackers Conference (H2HC), najstarszej konferencji poświęconej badaniom bezpieczeństwa w Ameryce Łacińskiej.

Spis treści

PRZEDMOWA Rodriga Rubia Branco

PODZIĘKOWANIA

SKRÓTY

WPROWADZENIE

Dlaczego warto przeczytać tę książkę?

Co znajdziemy w tej książce?

Część 1: Rootkity

Część 2: Bootkity

Część 3: Obrona i techniki śledcze

Jak czytać tę książkę

CZĘŚĆ I: ROOTKITY

1. CZYM JEST ROOTKIT: STUDIUM PRZYPADKU TDL3

Historia dystrybucji TDL3 w świecie

Procedura infekcji

Kontrola przepływu danych

Bring Your Own Linker

Jak działają hooki trybu jądra w TDL3

Ukryty system plików

Podsumowanie: TDL3 spotyka swoją Nemesis

2. ROOTKIT FESTI: NAJBARDZIEJ ZAAWANSOWANY BOT SPAMOWY I DDOS

Przypadek botnetu Festi

Analiza sterownika rootkita

Informacje konfiguracyjne Festi do komunikacji z C&C

Zorientowana obiektowo platforma Festi

Zarządzanie wtyczkami

Wbudowane wtyczki

Techniki obrony przed uruchomieniem w maszynie wirtualnej

Techniki antydebuggerowe

Metoda ukrywania złośliwego sterownika na dysku

Metoda ochrony klucza rejestru Festi

Sieciowy protokół komunikacyjny Festi

Faza inicjowania

Faza robocza

Omijanie oprogramowania antywirusowego i oprogramowania do analizy śledczej

Algorytm generowania domeny na wypadek awarii C&C

Złośliwa funkcjonalność

Moduł Spam

Mechanizm DDoS

Wtyczka proxy Festi

Podsumowanie

3. OBSERWOWANIE INFEKCJI ROOTKITAMI

Metody przechwytywania

Przechwytywanie zdarzeń systemowych

Przechwytywanie wywołań systemowych

Przechwytywanie operacji plikowych

Przechwytywanie dyspozytora obiektów

Przywracanie jądra systemu

Wielki rootkitowy wyścig zbrojeń: uwaga nostalgiczna

Podsumowanie

CZĘŚĆ II: BOOTKITY

4. EWOLUCJA BOOTKITU

Pierwsze bootkity

Programy infekujące sektor rozruchowy

Elk Cloner i Load Runner

Wirus Brain

Ewolucja bootkitów

Koniec ery BSI

Zasada podpisywania kodu trybu jądra

Pojawienie się Secure Boot

Nowoczesne bootkity

Podsumowanie

5. PODSTAWY PROCESU ROZRUCHU SYSTEMU OPERACYJNEGO

Ogólny przegląd procesu rozruchu systemu Windows

Starszy proces rozruchowy

Proces rozruchu Windows

BIOS i środowisko przeduruchomieniowe

Master Boot Record

Volume Boot Record i Initial Program Loader

Moduł bootmgr oraz Boot Configuration Data

Podsumowanie

6. ZABEZPIECZENIA PROCESU ROZRUCHU

Moduł Early Launch Anti-Malware

Procedury wywołań zwrotnych API

Jak bootkity omijają ELAM?

Zasada podpisywania kodu trybu jądra

Sterowniki trybu jądra podlegające testom integralności

Lokalizacja podpisów sterowników

Słabość integralności starszego kodu

Moduł ci.dll

Zmiany w mechanizmach ochronnych Windows 8

Technologia Secure Boot

Zabezpieczenia oparte na wirtualizacji w Windows 10

Second Level Address Translation

Virtual Secure Mode i Device Guard

Ograniczenia Device Guard dotyczace tworzenia sterowników

Podsumowanie

7. TECHNIKI INFEKCJI BOOTKITÓW

Techniki infekcji MBR

Modyfikowanie kodu MBR: technika infekcji TDL4

Modyfikowanie tablicy partycji MBR

Techniki infekcji VBR/IPL

Modyfikacje IPL: Rovnix

Infekcja VBR: Gapz

Podsumowanie

8. STATYCZNA ANALIZA BOOTKITU PRZY UŻYCIU IDA PRO

Analizowanie MBR zainfekowanego przez bootkit

Ładowanie i deszyfrowanie MBR

Analizowanie usługi dyskowej BIOS

Analiza tablicy partycji zainfekowanego MBR

Techniki analizy VBR

Analizowanie IPL

Inne komponenty bootkitów

Zaawansowane wykorzystanie IDA Pro: tworzymy niestandardowy loader MBR

Poznajemy loader.hpp

Implementowanie accept_file

Implementowanie load_file

Tworzenie struktury tablicy partycji

Podsumowanie

Ćwiczenia

9. DYNAMICZNA ANALIZA BOOTKITU: EMULACJA I WIRTUALIZACJA

Emulacja przy użyciu Bochs

Instalowanie Bochs

Tworzenie środowiska Bochs

Infekowanie obrazu dysku

Korzystanie z wewnętrznego debugera Bochs

Łączenie Bochs z IDA

Wirtualizacja przy użyciu VMware Workstation

Konfigurowanie VMware Workstation

Łączenie VMware GDB z IDA

Microsoft Hyper-V i Oracle VirtualBox

Podsumowanie

Ćwiczenia

10. EWOLUCJA TECHNIK INFEKOWANIA MBR I VBR: OLMASCO

Dropper

Zasoby droppera

Telemetria celem przyszłego rozwoju

Triki zapobiegające debugowaniu i emulacji

Funkcjonalność bootkitu

Technika infekcji bootkitem

Proces rozruchu zainfekowanego systemu

Funkcjonalność rootkitu

Zahaczanie obiektu urządzenia dysku twardego i wstrzyknięcie payloadu

Obsługa ukrytego systemu plików

Implementowanie Transport Driver Interface w celu przekierowania łączności sieciowej

Podsumowanie

11. BOOTKITY IPL: ROVIX I CARBERP

Ewolucja bootkitu Rovnix

Architektura bootkitu

Infekowanie systemu

Proces rozruchowy po infekcji i IPL

Implementowanie polimorficznego deszyfratora

Rozszyfrowywanie programu ładującego Rovnix przy użyciu VMware i IDA Pro

Przejmowanie kontroli przez łatanie rozruchowego programu Windows

Ładowanie złośliwego sterownika trybu jądra

Funkcjonalność sterownika trybu jądra

Wstrzykiwanie modułu payloadu

Mechanizmy ukrywania i samoobrony

Ukryty system plików

Formatowanie partycji jako Virtual FAT

Szyfrowanie ukrytego systemu plików

Uzyskiwanie dostępu do ukrytego systemu plików

Ukryty kanał łączności

Historia przypadku: połączenie z trojanem Carberp

Rozwój Carberp

Ulepszenia droppera

Wyciek kodu źródłowego

Podsumowanie

12. GAPZ: ZAAWANSOWANA INFEKCJA VBR

Dropper Gapz

Algorytm droppera

Analiza droppera

Omijanie HIPS

Infekowanie systemu bootkitem Gapz

Przypomnienie informacji o bloku parametrów BIOS-u

Infekowanie VBR

Ładowanie złośliwego sterownika trybu jądra

Funkcjonalność rootkitu Gapz

Ukryty magazyn

Samoobrona przed oprogramowaniem antywirusowym

Wstrzyknięcie payloadu

Interfejs komunikacyjny payloadu

Niestandardowy stos protokołu sieciowego

Podsumowanie

13. ROZWÓJ RANSOMWARE MBR

Krótka historia ransomware

Ransomware z funkcjonalnością bootkitu

Modus operandi ransomware

Analiza ransomware Petya

Uzyskiwanie uprawnień administratora

Infekowanie dysku twardego (krok 1)

Szyfrowanie przy użyciu danych konfiguracyjnych złośliwego programu ładującego

Prowokowanie awarii systemu

Szyfrowanie MFT (krok 2)

Podsumowanie: końcowe przemyślenia na temat Petya

Analiza ransomware Satana

Dropper Satana

Infekowanie MBR

Informacje debugowania droppera

Złośliwy MBR Satana

Podsumowanie: końcowe przemyślenia na temat Satana

Podsumowanie

14. ROZRUCH UEFI A PROCES ROZRUCHOWY MBR/VBR

Unified Extensible Firmware Interface

Różnice między starszym procesem rozruchowym BIOS a UEFI

Przepływ procesu rozruchu

Partycjonowanie dysku: MBR kontra GPT

Inne różnice

Specyficzne cechy tablicy partycji GUID

Jak działa oprogramowanie wbudowane UEFI

Specyfikacja UEFI

Wewnątrz loadera systemu operacyjnego

Windows Boot Loader

Zalety UEFI z punktu widzenia bezpieczeństwa

Podsumowanie

15. WSPÓŁCZESNE BOOTKITY UEFI

Przegląd historycznych zagrożeń BIOS-u

WinCIH, pierwszy złośliwy program atakujący BIOS

Mebromi

Przegląd innych zagrożeń i środków zaradczych

All Hardware Has Firmware

Podatności UEFI

(Nie)skuteczność bitów ochrony pamięci

Sprawdzanie bitów ochrony

Sposoby infekowania BIOS-u

Modyfikowanie niepodpisanego Option ROM UEFI

Dodanie lub zmodyfikowanie sterownika DXE

Istota iniekcji rootkitu

Rootkity UEFI wykorzystywane w atakach

Rootkit Vector-EDK od Hacking Team

Podsumowanie

16. PODATNOŚCI OPROGRAMOWANIA UKŁADOWEGO UEFI

Co sprawia, że oprogramowanie wbudowane jest podatne?

Klasyfikowanie podatności UEFI

Podatności „po przejęciu”

Podatności umożliwiające przejęcie łańcucha zaopatrzenia

Neutralizowanie podatności łańcucha dostaw

Historia zabezpieczeń oprogramowania układowego UEFI

Jak działają zabezpieczenia BIOS-u

Zabezpieczenia pamięci flash SPI i ich podatności

Ryzyko związane z nieuwierzytelnioną aktualizacją BIOS-u

Ochrona BIOS-u przy użyciu Secure Boot

Intel Boot Guard

Technologia Intel Boot Guard

Podatności w Boot Guard

Podatności w modułach SMM

Istota SMM

Nadużywanie programów obsługi SMI

Podatności w skrypcie rozruchu S3

Istota S3 Boot Script

Wyszukiwanie słabości w skrypcie rozruchu S3

Wykorzystanie podatności skryptu rozruchu S3

Naprawianie podatności skryptu rozruchu S3

Podatności w Intel Management Engine

Historia podatności ME

Ataki na kod ME

Studium przypadku: ataki na Intel AMT i BMC

Podsumowanie

CZĘŚĆ III: OBRONA I TECHNIKI ANALIZY

17. JAK DZIAŁA UEFI SECURE BOOT

Czym jest Secure Boot?

Szczegóły implementacji UEFI Secure Boot

Sekwencja rozruchu

Uwierzytelnianie plików wykonywalnych za pomocą podpisów cyfrowych

Baza danych db

Baza danych dbx

Uwierzytelnienie oparte na czasie

Klucze Secure Boot

UEFI Secure Boot: pełny obraz

Zasady Secure Boot

Ochrona przed bootkitami przy użyciu Secure Boot

Atakowanie Secure Boot

Łatanie oprogramowania PI w celu wyłączenia Secure Boot

Modyfikowanie zmiennych UEFI w celu obejścia testów zabezpieczeń

Ochrona Secure Boot za pomocą weryfikowanego lub mierzonego rozruchu

Weryfikowany rozruch

Mierzony rozruch

Intel BootGuard

Odszukiwanie ACM

Poznawanie FIT

Konfigurowanie Intel BootGuard

ARM Trusted Boot Board

ARM Trust Zone

Programy ładujące w architekturze ARM

Przebieg Trusted Boot

Weryfikowany rozruch kontra rootkity oprogramowania układowego

Podsumowanie

18. SPOSOBY ANALIZOWANIA UKRYTYCH SYSTEMÓW PLIKÓW

Przegląd ukrytych systemów plików

Odczytywanie danych bootkitu z ukrytego systemu plików

Odczytywanie danych z systemu w stanie offline

Odczytywanie danych w działającym systemie

Zahaczanie sterownika miniportu urządzenia pamięci masowej

Analizowanie obrazu ukrytego systemu plików

Narzędzie HiddenFsReader

Podsumowanie

19. ŚLEDZTWA BIOS/UEFI: PODEJŚCIA DO ZDOBYWANIA OPROGRAMOWANIA UKŁADOWEGO I ANALIZ

Ograniczenia naszych technik badania

Dlaczego badanie oprogramowania układowego jest ważne

Atakowanie łańcucha dostaw

Przełamanie zabezpieczeń BIOS-u przez podatność oprogramowania układowego

Pozyskiwanie oprogramowania układowego

Podejście programowe do uzyskiwania oprogramowania układowego

Lokalizowanie rejestrów obszaru konfiguracji PCI

Obliczanie adresów rejestru konfiguracji SPI

Korzystanie z rejestrów SPI

Czytanie danych z pamięci flash SPI

Uwzględnianie niedoskonałości podejścia programowego

Sprzętowe podejście do uzyskiwania oprogramowania układowego

Przegląd analizy przypadku Lenovo ThinkPad T540p

Lokalizowanie układu pamięci flash SPI

Odczytywanie pamięci flash SPI przy użyciu modułu FT2232

Analizowanie obrazu oprogramowania układowego przy użyciu UEFITool

Poznawanie regionów pamięci flash SPI

Przeglądanie regionów pamięci flash SPI przy użyciu UEFITool

Analizowanie regionu BIOS-u

Analizowanie obrazu oprogramowania układowego przy użyciu Chipsec

Poznawanie architektury Chipsec

Analizowanie oprogramowania układowego przy użyciu Chipsec Util

Podsumowanie

PRZYPISY

PRZEDMOWA

Jest niezaprzeczalnym faktem, że wykorzystanie złośliwego oprogramowania jest rosnącym zagrożeniem dla bezpieczeństwa komputerów. Ze wszystkich stron obserwujemy alarmujące statystyki świadczące o powiększaniu się finansowych skutków złośliwego oprogramowania, o jego złożoności oraz o samej liczbie złośliwych próbek. Więcej niż kiedykolwiek wcześniej badaczy zabezpieczeń, zarówno w przemyśle, jak i środowisku naukowym, studiuje złośliwe oprogramowanie i publikuje wyniki badań w rozmaitych miejscach, od blogów i konferencji branżowych po spotkania naukowe i książki dedykowane tej tematyce. Publikacje te obejmują wszelkie rodzaje tematów: inżynierię odwrotną, najlepsze praktyki, metodologię i najlepsze zestawy narzędzi.

Jak widać zatem, od dawna toczy się wiele dyskusji na temat analizy złośliwego oprogramowania i automatyzowania narzędzi, każdy zaś dzień przynosi kolejne. Można się zatem zastanawiać: Po co jeszcze jedna książka na ten temat? Co wnosi ta książka, czego nie znajdziemy w innych?

Po pierwsze i przede wszystkim, choć książka ta dotyczy inżynierii wstecznej zaawansowanego – przez co rozumiem innowacyjnego – złośliwego oprogramowania, zawiera całą podstawową wiedzę o tym, dlaczego dany kod złośliwego oprogramowania w ogóle powstał. Książka wyjaśnia wewnętrzne działanie różnych komponentów, których to dotyczy – od rozruchu platformy, przez ładowanie systemu operacyjnego, aż po różne komponenty jądra oraz operacje warstwy aplikacji, które wpływają z powrotem na jądro.

Sam wielokrotnie odkrywałem, że objaśnianie podstawowych zagadnień jest czymś innym niż same podstawy – choć wymaga sięgnięcia w dół do fundamentów, do podstawowych elementów budulcowych techniki komputerowej. I z tej perspektywy książka ta jest o czymś więcej niż tylko o złośliwym oprogramowaniu. Wyjaśnia, jak działają komputery, jak nowoczesny stos oprogramowania wykorzystuje zarówno podstawowe możliwości maszyny, jak i interfejsy użytkownika. Gdy raz to pojmiemy, zaczniemy automagicznie rozumieć, jak i dlaczego coś się psuje oraz jak i dlaczego może zostać nadużyte.

Kto mógłby lepiej przedstawić takie wskazówki niż autorzy z potwierdzonymi osiągnięciami w dziedzinie ujawniania – w wielu sytuacjach – prawdziwie zaawansowanego złośliwego kodu, który za każdym razem przesuwał dalej granice możliwości w tej dziedzinie? Dodajmy do tego celowy i mozolny wysiłek w dążeniu do połączenia tego doświadczenia z podstawami działania komputerów i tworzenia szerszego obrazu, takiego jak sposoby analizowania i zrozumienia różnych problemów o podobnych cechach koncepcyjnych, a stanie się oczywiste, dlaczego książka ta powinna się znaleźć na początku listy obowiązkowych lektur.

Jeśli zawartość i wybrana metodologia aż nadto usprawiedliwiają potrzebę powstania takiej książki, kolejnym pytaniem mogłoby być, dlaczego nikt wcześniej nie podjął się jej napisania. Obserwowałem (i miałem zaszczyt aktywnie uczestniczyć, a także – mam nadzieję – wnieść coś od siebie) ewolucję tej książki, co zajęło kilka lat stałych wysiłków, mimo że autorzy mieli już całość surowych materiałów. Przez to doświadczenie oczywiste stało się dla mnie, dlaczego nikt inny nie próbował tego wcześniej: nie tylko jest to trudne, lecz także wymaga odpowiedniego połączenia umiejętności (które, biorąc pod uwagę wcześniejsze doświadczenia autorów, oczywiście posiadają), właściwego wsparcia ze strony redaktorów (które zapewniło wydawnictwo No Starch Press, cierpliwie przeprowadzając przez proces redakcyjny i akceptując nieuniknione opóźnienia w trakcie projektu z powodu zmieniających się realiów ofensywnej pracy związanej z zabezpieczeniami), a także entuzjazmu pierwszych czytelników (którzy mieli kluczowy wpływ na doprowadzenie tej pracy do linii mety).

Znacząca część tej książki koncentruje się na budowaniu zrozumieniu tego, jak w nowoczesnym komputerze osiągane jest zaufanie (lub jego brak) i jak mogą zostać wykorzystane (nadużyte) różne warstwy i przejścia między nimi, aby unieważnić założenia poczynione przez kolejną warstwę. W unikatowy sposób zwraca to uwagę na dwa główne problemy związane z implementowaniem zabezpieczeń; dotyczą one: kompozycji (wiele warstw, gdzie poprawne funkcjonowanie każdej zależy od właściwego zachowania innej lub innych) oraz założeń (ponieważ warstwy muszą z natury zakładać, że poprzednia zachowuje się poprawnie). Autorzy dodatkowo dzielą się swoją wiedzą na temat narzędzi i podejść stosowanych w unikatowo trudnych analizach komponentów wczesnego rozruchu i głębszych warstw systemu operacyjnego. Samo to przekrojowe podejście warte było napisania książki, przez co powstała niejako książka wewnątrz książki. Jako czytelnik uwielbiam takie podejście „dwa w jednym”, które niewielu tylko autorów oferuje swoim czytelnikom.

Moje przekonania o naturze wiedzy jest takie, że jeśli naprawdę coś znamy, możemy to zhakować. Użycie inżynierii odwrotnej do zrozumienia kodu, który hakuje zwyczajne zachowanie systemu, to wspaniały techniczny wyczyn, który często odsłania wiele wiedzy. Możliwość uczenia się od profesjonalistów o wielkim dorobku w wykonywaniu tej ewolucji – wykorzystanie ich umiejętności, metod, zaleceń i ogólnej wiedzy specjalistycznej – przy podążaniu własną ścieżką jest unikatową okazją. Nie przeocz jej! Idź w działaniach dalej; użyj materiałów pomocniczych; ćwicz; zaangażuj społeczność, przyjaciół, a nawet wykładowców (którzy, mam nadzieję, dostrzegą wartość, jaką ta książka wnosi do nauczania). To nie jest tylko książka do czytania – to książka warta przestudiowania.

Rodrigo Rubira Branco

(BSDaemon)

PODZIĘKOWANIA

Chcielibyśmy podziękować wszystkim czytelnikom, którzy zakupili wczesne wersje tej książki. Ich ciągłe wsparcie było bardzo motywujące do dalszej pracy; bez tego książka zapewne nigdy nie zostałaby ukończona. Dziękujemy wam wszystkim za cierpliwe oczekiwanie na to ostateczne wydanie!

Chcielibyśmy też podziękować ludziom, którzy wspierali nas we wczesnej fazie powstawania książki: to David Harley, Juraj Malcho i Jacub Debski.

Pracowników No Starch Press, którzy pomagali nam w ciągu pięciu lat pracy nad tą książką, jest zbyt wielu, aby ich wszystkich wymienić, zatem chcielibyśmy szczególnie podkreślić wkład Billa Pollocka (za jego cierpliwość i skupienie się na jakości) oraz Liz Chadwick i Laurel Chun (bez ich pomocy książka byłaby bardzo odmienna).

Doceniamy ogromnie wszystkie opinie, które otrzymaliśmy od takich osób, jak Alexandre Gazet, Bruce Dang, Nikolaj Schlej, Zeno Kovah, Alex Tereshkin i wszyscy inni czytelnicy wczesnych wersji, którzy przesłali nam swoje komentarze. Dziękujemy z wskazanie znalezionych przez was literówek i błędów oraz za sugestie i zachęty.

Ogromne podziękowania należą się Rodrigo Rubira Branco (BSDaemon) za jego nadzwyczajną pomoc, recenzję techniczną i przedmowę do tej książki.

Chcielibyśmy też podziękować Ilfakowi Gulfanovowi oraz zespołowi Hex-Rays za ich pomoc i świetne narzędzia, których użyliśmy przy analizach zagrożeń omawianych w tej książce.

Chciałbym podziękować mojej żonie, Swietłanie, za jej wsparcie, a zwłaszcza za cierpliwość, gdy spędzałem większość czasu na swoich badaniach.

Alex Matrosov

Chciałbym przekazać wielkie „dziękuję” mojej rodzinie: mojej żonie, Eugenii, oraz moim chłopcom, Olegowi i Leonowi, za pomoc, inspirację i zrozumienie.

Eugene Rodionov

Jestem wdzięczny wielu ludziom za możliwość wniesienia skromnego wkładu do tej książki: autorom i redaktorom z Phrack i Uninformed, badaczom z Phenoelit i THC, organizatorom i uczestnikom Recon, PH-Neutral, Toorcon, Troopers, Day-Con, Shmoocon, Rubi-Con, Berlinsides, H2HC, Sec-T, DEFCON i wielu innym. Specjalne podziękowania kieruję do Williama Polka, który pokazał mi, że hakerskie podejście wykracza poza komputery, i bez którego pomocy nie byłbym fizycznie w stanie pracować ani podróżować od lat. I oczywiście nic z tego nie mogłoby się zdarzyć bez miłości, cierpliwości i pomocy mojej żony, Anny.

Sergey Bratus

SKRÓTY[*]

AES Advanced Encryption Standard

ACM Authenticated Code Module

ACPI Advanced Configuration and Power Interface

AMT Active Management Technology

APC asynchronous procedure call – asynchroniczne wywołanie procedury

APIC Advanced Programmable Interrupt Controller

ARM Advanced RISC Machine

ATA Advanced Technology Attachment

BCD Boot Configuration Data

BDS Boot Device Selection

BIOS Basic Input/Output System

BMC Baseboard Management Controller

BPB BIOS Parameter Block

BPM boot policy manifest – manifest zasady rozruchu

BSI boot sector infector – infektor sektora rozruchowego

BSoD Blue Screen of Death – „niebieski ekran śmierci”

C&C command and control – serwer zarządzający złośliwego oprogramowania

CBC cipher block chaining – wiązanie bloków zaszyfrowanych

CDO control device object – obiekt urządzenia sterującego

CHS Cylinder Head Sector

CLR Common Language Runtime

COFF Common Object File Format

COM Component Object Model

CSM Compatibility Support Module

DBR DOS Boot Record

DDoS distributed denial of service – rozproszona odmowa usługi

DGA domain name generation algorithm, algorytm generowania nazwy domenowej

DKOM Direct Kernel Object Manipulation

DLL dynamic-link library – biblioteka łączona dynamicznie

DMA direct memory access – bezpośredni dostęp do pamięci

DRAM dynamic random access memory – dynamiczna pamięć o swobodnym dostępie

DRM digital rights management – zarządzanie prawami cyfrowymi

DXE Driver Execution Environment

EC Embedded Controller

ECB Electronic Code Book

ECC Elliptic Curve Cryptography

EDK EFI Development Kit

EDR Endpoint Detection and Response

EFI Extensible Firmware Interface

ELAM Early Launch Anti-Malware

ELF Executable and Linkable Format/Extensible Linking Format

EPT Extended Page Tables

FEK file encryption key – klucz szyfrowania pliku

FFS firmware filesystem – system plików oprogramowania układowego

FIT Firmware Interface Table

FPF field-programmable fuse – programowalna macierz bramek

GDB GNU Debugger

GDT Global Descriptor Table

GPT GUID Partition Table

GUID global unique identifier – globalnie unikatowy identyfikator

HAL hardware abstraction layer – warstwa abstrakcji sprzętu

HBA host-based architecture – architektura oparta na hoście

HECI Host-Embedded Controller Interface

HIPS Host Intrusion Prevention System

HSFC hardware sequencing flash control – kontrola sekwencjonowania sprzętowego pamięci flash

HSFS hardware sequencing flash status – status sekwencjonowania sprzętowego pamięci flash

HVCI Hypervisor-Enforced Code Integrity

IBB initial boot block – wstępny blok rozruchowy

IDT Interrupt Descriptor Table

IOCTL Input/Output Control

IPL Initial Program Loader

IRP input/output request packet – pakiet żądania wejścia/wyjścia

ISH Integrated Sensor Hub

IV initialization value – wartość inicjująca

IVT Interrupt Vector Table

KEK key exchange key – klucz wymiany kluczy

KM key manifest – manifest klucza

KPP Kernel Patch Protection

LBA logical block address – adres bloku logicznego

LPE local privilege escalation – lokalna eskalacja uprawnień

MBR Master Boot Record

ME Management Engine

MFT Master File Table

MIPS millions of instructions per second – miliony instrukcji na sekundę

MSR model-specific register – rejestr specyficzny dla modelu

NDIS Network Driver Interface Specification

NVRAM nonvolatile random access memory – nieulotna pamięć o swobodnym dostępie

NX no-execute – nie wykonanuj

OEM original equipment manufacturer – oryginalny wytwórca sprzętu

OSI Open Systems Interconnection

PCH Platform Controller Hub

PCR Platform Configuration Register

PDO physical device object – obiekt urządzenia fizycznego

PE Portable Executable

PEI Pre-EFI Initialization

PI platform initialization – inicjowanie platformy

PIC Position-Independent Code

PK platform key – klucz platformy

PKI public key infrastructure – infrastruktura klucza publicznego

PMU Power Management Unit

PnP Plug and Play

PoC proof of concept – dowód koncepcji, prototyp

POST Power-On Self-Test

PPI Pay-Per-Install

RCBA Root Complex Base Address

RCRB Root Complex Register Block

ROP return-oriented programming – programowanie zwrotne

RVI Rapid Virtualization Indexing

SGX Software Guard Extensions

SLAT Second Level Address Translation

SMC System Management Controller

SMI System Management Interrupt

SMM System Management Mode

SMRAM system management random access memory – pamięć o swobodnym dostępie zarządzania systemem

SPC Software Publisher Certificate

SPI Serial Peripheral Interface

SPIBAR SPI Base Address Register

SSDT System Service Descriptor Table

TBB Trusted Boot Board

TDI Transport Driver Interface

TE Terse Executable

TPM Trusted Platform Module

TSA Time Stamping Authority

UAC User Account Control – kontrola konta użytkownika

UEFI Unified Extensible Firmware Interface

UID unique identifier – unikatowy identyfikator

VBR Volume Boot Record

VBS virtualization-based security – zabezpieczenia oparte na wirtualizacji

VDO volume device object – obiekt urządzenia woluminu

VFAT Virtual File Allocation Table

VFS Virtual File System

VM virtual machine – maszyna wirtualna

VMM virtual machine manager – menedżer maszyn wirtualnych

VSM Virtual Secure Mode

WDK Windows Driver Kit

WHQL Windows Hardware Quality Labs

WMI Windows Management Instrumentation

[*] Nazwy własne podawane są w oryginalnym brzmieniu. Dla akronimów pochodzących od terminów potocznych podane jest rozwinięcie oryginału wraz z tłumaczeniem na język polski (przyp. tłum.).

WPROWADZENIE

Pomysł napisania tej książki powstał, gdy po opublikowaniu wielu artykułów i postów na blogach o rootkitach i bootkitach zdaliśmy sobie sprawę, że temat ten nie uzyskuje nawet ułamka uwagi, na którą zasługuje. Czuliśmy, że jest to szersze zagadnienie i pragnęliśmy książki, która pozwoli

nadać sens temu wszystkiemu – takiej, która uogólniłaby tę mieszankę sprytnych sztuczek, spostrzeżeń na temat architektur systemów operacyjnych i wzorców projektowych używanych w innowacjach napastników i obrońców. Rozglądaliśmy się za taką książką i nie znaleźliśmy żadnej, zatem zdecydowaliśmy się ją napisać – taką, jaką sami chcieliśmy przeczytać.

Zajęło nam to cztery i pół roku, dłużej niż planowaliśmy i, niestety, dużo dłużej, niż moglibyśmy oczekiwać, że nasi oczekiwani czytelnicy i pomocnicy wczesnych wydań zechcą z nami pozostać. Jeśli jesteś jedną z tych osób, które nas wspierały od początku i jednak czytasz tę książkę, jesteśmy zawstydzeni twoim nieustającym poświęceniem!

W tym czasie obserwowaliśmy wspólną ewolucję ataków i obrony przed nimi. W szczególności widzieliśmy, jak nowe mechanizmy ochrony Microsoft Windows sprawiły, że wiele głównych gałęzi rozwoju rootkitów i bootkitów stało się ślepymi uliczkami. Historię tę można znaleźć na stronach tej książki.

Widzieliśmy też pojawienie się nowych klas złośliwego oprogramowania, biorącego na cel BIOS i oprogramowanie chipsetu, poza zasięgiem bieżącego oprogramowania obronnego w Windows. Wyjaśnimy w książce, jak ta wspólna ewolucja się rozwijała i dokąd naszym zdaniem zaprowadzą nas jej kolejne kroki.

Innym tematem tej książki jest rozwój technik inżynierii odwrotnej, nakierowanej na wczesne fazy procesu rozruchu systemu operacyjnego. Tradycyjnie, im wcześniej w długim łańcuchu procesu rozruchowego komputera wchodzi do gry jakiś fragment oprogramowania, tym mniej jest on widoczny. Ten brak możliwości obserwacji przez długi czas był mylony z bezpieczeństwem. Jednak w miarę naszych badań nad bootkitami i implantami BIOS-u, które wywracały do góry nogami technologie systemu niskiego poziomu, takie jak Secure Boot, dostrzegamy, że podejście security by obscurity sprawdza się tu nie lepiej niż w innych obszarach informatyki. Po krótkim czasie (który w czasach Internetu może się tylko skrócić jeszcze bardziej) podejście to staje się bardziej korzystne dla napastników niż dla obrońców. Ta koncepcja nie została dostatecznie omówiona w innych książkach na ten temat, zatem próbujemy wypełnić tę lukę.

Dlaczego warto przeczytać tę książkę?

Książkę pisaliśmy dla bardzo szerokiego kręgu badaczy bezpieczeństwa informatycznego, zainteresowanych tym, jak zaawansowane, trwałe zagrożenia (ataki APT) omijają zabezpieczenia poziomu systemu operacyjnego. Skupiliśmy się na tym, jak te zaawansowane zagrożenia można wykrywać i skutecznie je analizować. Każda część książki odzwierciedla nową fazę ewolucyjnego rozwoju zaawansowanych zagrożeń, od ich pojawienia się jako zawężonych dowodów koncepcji po ich późniejsze rozpowszechnienie wśród uczestników zagrożeń, aż po finalne włączenie do podstępnego arsenału ukierunkowanych ataków.

Chcielibyśmy jednak dotrzeć do szerszego grona odbiorców niż tylko analitycy złośliwego oprogramowania. W szczególności mamy nadzieję, że książka okaże się równie użyteczna dla twórców systemów wbudowanych i specjalistów zabezpieczeń chmurowych, biorąc pod uwagę, że zagrożenie rootkitami i innymi implantami może być ogromne dla ich ekosystemów.

Co znajdziemy w tej książce?

Rozpoczynamy od eksploracji rootkitów w części 1, w której przedstawiamy wewnętrzne mechanizmy jądra systemu Windows, które historycznie były miejscem działania rootkitów. Następnie w części 2 przenosimy uwagę w stronę procesu rozruchu systemu operacyjnego i bootkitów, które powstały po tym, gdy w systemie Windows zaczęto wzmacniać tryb jądra. Rozbieramy na części proces rozruchu z punktu widzenia napastnika, zwracając szczególną uwagę na nowe schematy oprogramowania układowego UEFI i na ich podatności. Na koniec, w części 3, skupiamy się na badaniach śledczych, zarówno dotyczących klasycznych ataków rootkitów systemu operacyjnego, jak i nowszych ataków bootkitów na BIOS i oprogramowanie układowe.

Część 1: Rootkity

W tej części koncentrujemy się na klasycznych rootkitach poziomu systemu operacyjnego w czasie ich największej świetności. Te historyczne przykłady rootkitów zapewniają wartościowy wgląd w to, jak napastnicy widzą wewnętrzne mechanizmy systemu operacyjnego i jak znajdują sposoby solidnego wbudowania do nich swoich implantów, wykorzystując własne struktury systemu.

Rozdział 1: Czym jest rootkit: studium przypadku TDL3

Poznawanie tego, jak działają rootkity, rozpoczynamy od opowieści o jednym z najbardziej interesujących rootkitów swoich czasów, opartej na naszych własnych spotkaniach z jego różnymi wariantami i naszych analizach tych zagrożeń.

Rozdział 2: Rootkit Festi: najbardziej zaawansowany bot spamu i DDoS

W tym rozdziale analizujemy pamiętny rootkit Festi, który wykorzystywał najbardziej zaawansowane techniki utajniania dostępne w jego czasach do rozsyłania spamu i ataków DDoS. Techniki te obejmowały utworzenie własnego stosu TCP/IP na poziomie jądra.

Rozdział 3: Obserwowanie infekcji rootkitami

Rozdział ten prowadzi nas w głąb jądra systemu operacyjnego, pokazując triki używane przez napastników w celu przejęcia kontroli nad głębszymi warstwami jądra, takie jak przechwytywanie zdarzeń i wywołań systemowych.

Część 2: Bootkity

Druga część przenosi naszą uwagę na ewolucję bootkitów, warunki, które napędzały tę ewolucję, oraz techniki inżynierii wstecznej takich zagrożeń. Zobaczymy tu, jak bootkity rozwinęły się w celu implantowania się wewnątrz BIOS-u i wykorzystywania podatności oprogramowania układowego UEFI.

Rozdział 4: Ewolucja bootkitów

Ten rozdział to głębokie zanurzenie w siły (ko)ewolucyjne, które powołały bootkity do istnienia i kierowały ich rozwojem. Przyjrzymy się niektórym z pierwszych odkrytych bootkitów, takich jak owiany złą sławą Elk Cloner.

Rozdział 5: Podstawy procesu rozruchu systemu operacyjnego

Omówimy tu wewnętrzne mechanizmy procesu rozruchowego Windows i jak się one zmieniały z upływem czasu. Zagłębimy się w takie szczegóły, jak Master Boot Record, tablice partycji, dane konfiguracyjne i moduł bootmgr.

Rozdział 6: Zabezpieczenia procesu rozruchu

Rozdział ten to wycieczka z przewodnikiem po technologiach ochrony systemu rozruchu Windows, takich jak moduły Early Launch Anti-Malware (ELAM), zasady podpisywania trybu jądra (Kernel-Mode Code Signing Policy) i ich słabości oraz nowsze techniki zabezpieczeń oparte na wirtualizacji.

Rozdział 7: Techniki infekcji bootkitów

W tym rozdziale rozłożymy na czynniki metody infekowania sektorów rozruchowych i przyjrzymy się ich ewolucji z upływem czasu. Jako przykładów użyjemy kilku dobrze znanych bootkitów: TDL4, Gapz oraz Rovnix.

Rozdział 8: Statyczna analiza bootkitu przy użyciu IDA Pro

Ten rozdział dotyczy metod i narzędzi analizy statycznej do badania infekcji bootkitami. Poprowadzimy w nim czytelnika przez analizę, używając bootkitu TDL4 jako przykładu, a także udostępniamy materiały do wykorzystania we własnych analizach, włącznie z obrazem dysku do pobrania.

Rozdział 9: Dynamiczna analiza bootkitu: emulacja i wirtualizacja

W tym miejscu przeniesiemy uwagę na metody analizy dynamicznej przy użyciu emulatora Bochs oraz wbudowanego w VMware debuggera GDB. Ponownie poprowadzimy czytelnika przez kolejne kroki dynamicznej analizy bootkitów MBR i VBR.

Rozdział 10: Ewolucja technik infekowania MBR i VBR: Olmasco

Prześledzimy tu ewolucję technik ukrywania się wykorzystywanych w celu przeniesienia bootkitów na niższe poziomy procesu rozruchu. Jako przykładu użyjemy Olmasco, zbadamy jego techniki infekcji i utrwalania, funkcjonalności złośliwego oprogramowania i wstrzykiwania payloadu.

Rozdział 11: Bootkity IPL: Rovnix i Carberp

W tym rozdziale zajrzymy pod maskę dwóch spośród najbardziej złożonych bootkitów, Rovnix i Carberp, wymierzonych w bankowość elektroniczną. Były to pierwsze bootkity atakujące IPL i unikające ówczesnego oprogramowania ochronnego. Do ich analizy wykorzystamy VMware oraz IDA Pro.

Rozdział 12: Gapz: zaawansowana infekcja VBR

Przedstawiamy tu szczytowe osiągnięcie ewolucji ukrywania się bootkitów: tajemniczy rootkit Gapz, który wykorzystywał najbardziej zaawansowane techniki swoich czasów do atakowania VBR.

Rozdział 13: Rozwój ransomware MBR

W tym rozdziale zobaczymy, jak bootkity znalazły sobie miejsce w zagrożeniach typu ransomware.

Rozdział 14: Rozruch UEFI a proces rozruchowy MBR/VBR

W tym miejscu poznamy proces rozruchu rozwiązań UEFI BIOS – informacje kluczowe dla wykrywania najnowszej ewolucji złośliwego oprogramowania.

Rozdział 15: Współczesne bootkity UEFI

Ten rozdział dotyczy naszych autorskich badań nad różnymi implantami BIOS-u, zarówno dowody koncepcji, jak i ich rozmieszczenie w środowisku naturalnym. Omówimy metody infekowania i utrwalania obecności w BIOS UEFI oraz przyjrzymy się przykładom złośliwego oprogramowania UEFI odkrytego w takim środowisku naturalnym jak Computrace.

Rozdział 16: Podatności oprogramowania układowego UEFI

W tym miejscu przedstawimy pogłębiony przegląd różnych klas podatności nowoczesnych układów BIOS-u, które umożliwiają wprowadzenie implantów. Jest to pogłębione studium podatności i eksploitów UEFI, włącznie ze studium przypadku.

Część 3: Obrona i techniki śledcze

Końcowa część książki dotyczy analiz śledczych bootkitów, rootkitów i innych zagrożeń dla BIOS-u.

Rozdział 17: Jak działa UEFI Secure Boot

Rozdział ten stanowi pogłębioną analizę działania technologii Secure Boot i jej ewolucji, podatności i skuteczności.

Rozdział 18: Podejścia do analizowania ukrytych systemów plików

Tu przedstawimy przegląd ukrytych systemów plików wykorzystywanych przez złośliwe oprogramowanie i metod ich wykrywania. Przeanalizujemy obraz ukrytego systemu plików, przedstawiając opracowane przez nas narzędzie HiddenFsReader.

Rozdział 19: Badania BIOS/UEFI: podejścia do zdobywania oprogramowania układowego i analizy

W tym końcowym rozdziale omówimy podejścia do wykrywania najbardziej zaawansowanych i wyrafinowanych zagrożeń. Przyjrzymy się podejściom sprzętowym i programowym oraz wykorzystaniu różnych narzędzi open source, takich jak UEFITool i Chipsec.

Jak czytać tę książkę

Wszystkie próbki zagrożeń omawianych w tej książce oraz inne materiały pomocnicze można znaleźć na stronie internetowej tej książki, https://nostarch.com/rootkits/. Witryna ta również wskazuje narzędzia używane w analizach bootkitów, takie jak kod źródłowy wtyczki IDA Pro, której używaliśmy w naszych autorskich badaniach.

CZĘŚĆ I

ROOTKITY

1

CZYM JEST ROOTKIT: STUDIUM PRZYPADKU TDL3

W tym rozdziale wprowadzimy pojęcie rootkita, wykorzystując rodzinę TDL3 jako przykład. Ten rootkit systemu Windows jest dobrym przykładem zaawansowanych technik przechwytywania kontroli i przepływu danych, wykorzystujących niższe warstwy architektury systemu operacyjnego. Przyjrzymy się temu, jak TDL3 infekuje system i jak pokonuje określone interfejsy i mechanizmy OS, aby przetrwać i pozostać niewykrytym.

TDL3 wykorzystuje mechanizm infekcji, który bezpośrednio ładuje jego kod do jądra Windows, przez co stał się nieskuteczny po wprowadzeniu przez Microsoft środków zapewniania integralności jądra w 64-bitowych systemach Windows. Niemniej techniki używane przez TDL3 w celu wstrzyknięcia kodu do jądra nadal są wartościowe jako przykład tego, jak można niezawodnie i skutecznie przejąć wykonywanie kodu jądra, gdy uda się ominąć tego rodzaju mechanizmy zabezpieczające. Podobnie jak w przypadku wielu innych rootkitów, hooki wykorzystywane przez TDL3 opierają się na kluczowych wzorcach samej architektury jądra. W pewnym sensie hooki rootkita mogą być lepszym przewodnikiem po rzeczywistej strukturze jądra niż oficjalna dokumentacja, a na pewno stanowią najlepsze wskazówki dla zrozumienia nieudokumentowanych struktur i algorytmów systemu.

W rzeczy samej, TDL3 został zastąpiony przez TDL4, który dzieli znaczącą część funkcjonalności ukrywania się i ochrony przed śledzeniem z TDL3, ale zwrócił się do technik bootkitu w celu ominięcia mechanizmu podpisywania kodu trybu jądra (Kernel-Mode Code Signing) w 64-bitowych systemach Windows (techniki te opiszemy w rozdziale 7).

W tym rozdziale zwrócimy uwagę na konkretne interfejsy i mechanizmy OS, które wykorzystuje TDL3. Wyjaśnimy, jak TDL3 i podobne mu rootkity są projektowane i jak działają, po czym w drugiej części książki przeanalizujemy metody i narzędzia, którymi można je wykrywać, obserwować i analizować.

Historia dystrybucji TDL3 w świecie

Po raz pierwszy wykryty w roku 2010[1] rootkit TDL3 był jednym z najbardziej wyrafinowanych przykładów złośliwego oprogramowania opracowanego do tego czasu. Jego mechanizmy ukrywania się stanowiły wyzwanie dla całej branży antywirusowej (podobnie jak jego bootkitowy następca, TDL4, który stał się pierwszym szeroko rozpowszechnionym bootkitem dla platformy x64).

UWAGA

Ta rodzina złośliwego oprogramowania znana jest również pod nazwami TDSS, Olmarik lub Alureon. Taka obfitość nazw tej samej rodziny nie jest niczym szczególnym, gdyż dostawcy antywirusów mają skłonność do stosowania różnych nazw w swoich raportach. Typowe jest również, że zespoły badawcze przypisują różne nazwy różnym modułom wspólnego ataku, szczególnie na wczesnych etapach analizy.

TDL3 był dystrybuowany przy użyciu modelu biznesowego Pay-Per-Install (PPI) za pośrednictwem powiązanych ze sobą grup DogmaMillions i GangstaBucks (obie zostały później wyłączone). Schemat PPI, popularny wśród grup cyberprzestępców, jest podobny do schematów używanych powszechnie do rozpowszechniania pasków narzędziowych dla przeglądarek. Dystrybutorzy pasków śledzą ich wykorzystanie przez tworzenie specjalnych kompilacji z osadzonym unikatowym identyfikatorem (UID) dla każdego pakietu lub paczki dostępnej do pobrania przez różne kanały dystrybucyjne. Pozwala to twórcom na obliczenie liczby instalacji (liczby użytkowników) powiązanych z UID, a tym samym ustalenie przychodu wygenerowanego przez każdy kanał dystrybucyjny. Analogiczna informacja dystrybucyjna została osadzona w pliku wykonywalnym rootkita TDL3, a specjalne serwery obliczały liczbę instalacji związanych z konkretnym dystrybutorem – i jego obciążających.

Współpracownicy grup cyberprzestępczych otrzymywali unikatowy login i hasło, które identyfikowały liczbę instalacji dla każdego zasobu. Każdy udziałowiec miał również osobistego menedżera, z którym można było się skonsultować w razie dowolnych problemów technicznych.

Aby zredukować ryzyko wykrycia przez oprogramowanie antywirusowe, udziałowcy często przepakowywali rozpowszechniane oprogramowanie i używali zaawansowanych technik obronnych w celu wykrycia stosowania debuggerów i maszyn wirtualnych, aby zmylić analizy wykonywane przez badaczy złośliwych programów[2]. Zabronione było również wykorzystywanie przez partnerów takich zasobów jak VirusTotal w celu sprawdzenia, czy ich aktualne wersje mogą być wykryte przez oprogramowanie antywirusowe i za takie postępowanie groziły nawet kary finansowe. Wynikało to stąd, że próbki wysyłane do VirusTotal mogły przyciągnąć uwagę, a w konskwencji analizę laboratoriów badawczych bezpieczeństwa, co w konsekwencji skróciłoby czas użyteczności złośliwego oprogramowania. Jeśli dystrybutorzy malware chcieli się upewnić co do niewykrywalności produktu, mogli odwoływać się do usług uruchamianych przez twórcę oprogramowania, analogicznych do VirusTotal, ale mogących zagwarantować, że dostarczone próbki będą trzymane z dala od dostawców oprogramowania zabezpieczającego.

Procedura infekcji

Po pobraniu infektora TDL3 do systemu użytkownika z jednego z kanałów dystrybucyjnych rozpoczyna się proces infekcji. Aby móc przetrwać ponowne uruchomienie systemu, TDL3 infekuje jeden ze sterowników rozruchowych, niezbędnych do załadowania systemu operacyjnego, wstrzykując złośliwy kod do binarnego pliku tego sterownika. Te sterowniki są ładowane wraz z obrazem jądra we wczesnej fazie procesu inicjowania systemu. W rezultacie przy uruchamianiu zainfekowanej maszyny zmodyfikowany sterownik jest ładowany i złośliwy kod przejmuje kontrolę na procesem uruchamiania.

Tym samym procedura infekcji, gdy zostanie uruchomiona w przestrzeni adresowej trybu jądra, przeszukuje listę sterowników rozruchowych, które wspierają kluczowe komponenty systemu operacyjnego, i losowo wybiera jeden z nich jako cel infekcji. Każdy wpis na liście jest opisany przez nieudokumentowaną strukturę KLDR_DATA_TABLE_ENTRY, pokazaną w listingu 1.1, do której odsyłacz znajduje się w polu DriverSection struktury DRIVER_OBJECT. Każdy ładowany sterownik trybu jądra ma odpowiadającą mu strukturę DRIVER_OBJECT.

typedef struct _KLDR_DATA_TABLE_ENTRY {

LIST_ENTRY InLoadOrderLinks;

LIST_ENTRY InMemoryOrderLinks;

LIST_ENTRY InInitializationOrderLinks;

PVOID ExceptionTable;

ULONG ExceptionTableSize;

PVOID GpValue;

PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;

PVOID ImageBase;

PVOID EntryPoint;

ULONG SizeOfImage;

UNICODE_STRING FullImageName;

UNICODE_STRING BaseImageName;

ULONG Flags;

USHORT LoadCount;

USHORT Reserved1;

PVOID SectionPointer;

ULONG CheckSum;

PVOID LoadedImports;

PVOID PatchInformation;

} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;

Listing 1.1. Układ struktury KLDR_DATA_TABLE_ENTRY wskazywanej przez pole DriverSection

Po wybraniu docelowego sterownika dropper TDL3 modyfikuje obraz sterownika w pamięci, nadpisując początkowe kilkaset bajtów jego sekcji zasobów .rsrc złośliwym loaderem. Jest on prosty: jedynie ładuje z dysku twardego w trakcie rozruchu resztę potrzebnego mu kodu złośliwego oprogramowania.

Oryginalne, nadpisane bajty z sekcji .rsrc – które nadal są niezbędne sterownikowi, aby mógł poprawnie funkcjonować – przechowywane są w pliku o nazwie rsrc.dat w ukrytym systemie plików utrzymywanym przez złośliwe oprogramowanie. (Zauważmy, że infekcja nie zmienia rozmiaru pliku zainfekowanego sterownika). Po wykonaniu tej modyfikacji TDL3 zmienia wskaźnik entry point w nagłówku Portable Executable (PE) sterownika, aby wskazywał na złośliwy loader. Tym samym adres punktu wejścia sterownika zainfekowanego przez TDL3 wskazuje sekcję zasobów, co nie jest dopuszczalne w normalnych warunkach. Na rysunku 1.1 jest pokazany sterownik rozruchowy przed i po infekcji, widać więc, jak obraz sterownika został zainfekowany, z etykietą Header odwołującą się do nagłówka PE wraz z tabelą sekcji.

Rysunek 1.1. Modyfikacje sterownika rozruchowego trybu jądra w trakcie infekcji systemu

Ten wzorzec infekowania plików wykonywalnych w formacie PE – podstawowym formacie binarnym plików wykonywalnych i bibliotek dynamicznych (DLL) w systemie Windows – jest typowy dla dropperów wirusów, ale nie tak częsty w przypadku rootkitów. Nagłówek PE i tabela sekcji są nieodzowne dla dowolnego pliku PE. Nagłówek PE zawiera krytyczne informacje o lokalizacji kodu i danych, metadanych systemowych, rozmiaru stosu itd., podczas gdy tabela sekcji zawiera informacje o sekcjach pliku wykonywalnego i ich lokalizacji.

Aby dokończyć proces infekcji, złośliwy program nadpisuje wpis katalogu metadanych .NET w nagłówku PE tymi samymi wartościami zawartymi we wpisie zabezpieczeń danych katalogu. Krok ten zapewne miał na celu udaremnienie analizy statycznej zainfekowanych obrazów, gdyż może wywołać błąd podczas parsowania nagłówka PE przez typowe narzędzia analizy złośliwych programów. W rzeczy samej, próby załadowania takich obrazów powodowały awarię IDA Pro w wersji 5.6 – bug ten został już naprawiony. Zgodnie ze specyfikacją PE/COFF udostępnioną przez firmę Microsoft katalog metadanych .NET zawiera dane używane przez Common Language Runtime (CLR) do ładowania i uruchamiania aplikacji .NET. Jednak ten wpis katalogu nie jest istotny dla sterowników rozruchowych trybu jądra, ponieważ wszystkie one są natywnymi plikami binarnymi i nie zawierają żadnego kodu zarządzanego przez system. Z tego powodu ten wpis katalogu nie jest sprawdzany przez program ładujący OS, pozwalając na załadowanie zainfekowanego sterownika, choć jego zawartość jest nieprawidłowa.

Zauważmy, że technika infekcji TDL3 jest ograniczona: działa tylko na platformach 32-bitowych ze względu na zasadę podpisywania kodu trybu jądra stosowaną przez Microsoft, która wymusza obowiązkowe sprawdzenia integralności kodu w systemach 64-bitowych. Ponieważ zawartość sterownika jest modyfikowana podczas infekowania systemu, jego cyfrowy podpis nie jest już poprawny, a tym samym powstrzymuje to OS przed załadowaniem sterownika w systemach 64-bitowych. Twórcy złośliwego oprogramowania odpowiedzieli na to opracowaniem TDL4. Zarówno ten mechanizm, jak i sposób jego obejścia omówimy szczegółowo w rozdziale 6.

Kontrola przepływu danych

Aby wypełnić swoją misję niewykrywalności, rootkity jądra muszą modyfikować przepływ sterowania lub przepływ danych (albo i jedno, i drugie) systemowych wywołań jądra, ilekroć oryginalny przepływ sterowania lub danych systemu operacyjnego mógłby ujawnić obecność dowolnych komponentów złośliwego oprogramowania w stanie spoczynku (np. plików) albo dowolnych spośród jego uruchomionych zadań lub artefaktów (takich jak struktury danych jądra). W tym celu rootkity typowo wstrzykują swój kod w jakieś miejsce na ścieżce wykonania implementacji wywołań systemowych; lokalizacja tych hooków kodu jest jednym z najbardziej edukacyjnych aspektów rootkitów.

Bring Your Own Linker

Tworzenie hooków (zahaczanie) to zasadniczo konsolidowanie. Nowoczesne rootkity przynoszą własne linkery, aby połączyć swój kod z systemem, który to wzorzec projektowy nazwaliśmy Bring Your Own Linker (wykorzystaj własny konsolidator). Aby móc niewidocznie wstawić te „konsolidatory”, TDL3 wykorzystuje kilka typowych zasad projektowania złośliwego oprogramowania.

Po pierwsze, cel musi pozostać działający mimo wstrzykniętego dodatkowego kodu, ponieważ napastnik nic nie zyska, a może wiele stracić, psując atakowane oprogramowanie. Z punktu widzenia inżynierii oprogramowania zahaczanie jest montowaniem oprogramowania i wymaga ostrożnego podejścia. Napastnik musi się upewnić, że system będzie uzyskiwał dostęp do nowego kodu tylko w przewidywalnym stanie, aby kod ten mógł zostać poprawnie wykonany, aby uniknąć dowolnych awarii lub nietypowego zachowania, które przyciągnęłoby uwagę użytkownika. Mogłoby się zdawać, że rozmieszczenie hooków ograniczone jest tylko wyobraźnią autora rootkita, ale w rzeczywistości musi on trzymać się stabilnych granic oprogramowania i interfejsów, które naprawdę dobrze zna. Nie jest więc zaskoczeniem, że hooki zazwyczaj odwołują się do tych samych struktur, które są używane dla natywnej funkcjonalności łączenia dynamicznego, zarówno tej udokumentowanej publicznie, jak i nie. Tabele wywołań zwrotnych, metody i inne wskaźniki funkcji, które łączą warstwy abstrakcji lub moduły oprogramowania są najbezpieczniejszymi miejscami dla hooków; przechwytywanie preambuł funkcji również się dobrze sprawdza.

Po drugie, umiejscowienie hooka nie powinno być zbyt oczywiste. Choć wczesne rootkity wykorzystywały systemową tabelę wywołań jądra najwyższego poziomu, ta technika szybko stała się przestarzała, gdyż tak bardzo rzucała się w oczy. W istocie, gdy została użyta w rootkicie Sony w 2005 roku[3], to położenie już było już uznawane za archaiczne. W miarę jak rootkity stawały się bardziej wyrafinowane, ich hooki przenosiły się w dół stosu, z głównych tabel wywołań systemowych do podsystemów OS przedstawiających jednolite warstwy API dla różniących się implementacji, takich jak Virtual File System (VFS), a następnie jeszcze niżej – do metod i wywołań zwrotnych konkretnych sterowników. TDL3 jest doskonałym przykładem tej migracji.

Jak działają hooki trybu jądra w TDL3

Aby pozostać poniżej horyzontu wykrywania, TDL3 stosował dość zaawansowaną technikę zahaczania, niespotykaną dotychczas w praktyce: przechwytywał żądania odczytu i zapisu wejścia/wyjścia wysyłane do dysku twardego na poziomie sterownika miniportu pamięci masowej (sterownika sprzętowego nośnika pamięci występującego na samym spodzie stosu sterowników pamięci masowej). Sterowniki portów są modułami systemu, które udostępniają interfejs programowania dla sterowników miniportów dostarczanych przez producentów odpowiednich urządzeń pamięciowych. Na rysunku 1.2 jest pokazana architektura stosu sterowników urządzeń pamięci masowej w Microsoft Windows.

Rysunek 1.2. Architektura stosu sterowników urządzeń w Microsoft Windows

Przetwarzanie struktury pakietu żądania wejścia/wyjścia (I/O request packet – IRP) adresowanego do pewnego obiektu zlokalizowanego na urządzeniu pamięci masowej zaczyna się na poziomie sterownika systemu plików. Odpowiedni sterownik systemu plików ustala konkretne urządzenie, na którym przechowywany jest ten obiekt (taki jak partycja dyskowa oraz ekstent, czyli ciągły obszar pamięci zarezerwowany wstępnie dla pliku w systemie) i wysyła inny IRP do klasy obiektu sterownika urządzenia. Ten zaś z kolei tłumaczy żądanie wejścia/wyjścia na odpowiedni obiekt miniportu urządzenia.

Zgodnie z dokumentacją Windows Driver Kit (WDK) sterowniki portów pamięci masowej zapewniają interfejs między niezależnym od sprzętu sterownikiem klasy a sterownikiem miniportu specyficznym dla HBA (host-based architecture – architektury opartej na hoście). Gdy ten interfejs jest dostępny, TDL3 ustawia hooki poziomu jądra na najniższym możliwym poziomie niezależnym od sprzętu w stosie sterowników urządzeń pamięci masowej, tym samym omijając dowolne narzędzia monitorujące lub zabezpieczenia działające na poziomie systemu plików lub sterownika klasy pamięci masowej. Takie hooki można wykryć tylko przy użyciu narzędzia, które zna normalne rozmieszczenie tych tabel dla konkretnego zbioru urządzenia albo znanej dobrej konfiguracji określonego komputera.

Aby zrealizować tę technikę zahaczania, TDL3 najpierw uzyskuje wskaźnik do obiektu sterownika miniportu odpowiedniego obiektu urządzenia. Mówiąc konkretniej, kod zahaczający próbuje otworzyć uchwyt dla \??\PhysicalDriveXX (gdzie XX odpowiada numerowi dysku twardego), ale ten łańcuch jest w rzeczywistości łączem symbolicznym, wskazującym obiekt urządzenia \Device\HardDisk0\DR0, utworzony przez sterownik klasy pamięci masowej. Przechodząc w dół stosu urządzeń od \Device\HardDisk0\DR0 na samym spodzie, znajdziemy obiekt miniportu urządzenia pamięci masowej. Po odnalezieniu obiektu miniportu urządzenia łatwiej jest uzyskać wskaźnik do jego obiektu sterownika, podążając za polem DriverObject w udokumentowanej strukturze DEVICE_OBJECT. W tym momencie złośliwy program ma wszystkie informacje, jakich potrzebuje do podłączenia się do stosu sterowników pamięci masowej.

Następnie TDL3 tworzy nowy, złośliwy obiekt sterownika i nadpisuje pole DriverObject obiektu sterownika miniportu wskaźnikiem do nowo utworzonego pola, co widać na rysunku 1.3. Pozwala mu to przechwytywać żądania odczytu/zapisu leżącego w tle dysku twardego, gdyż adresy wszystkich uchwytów są specyfikowane w powiązanej strukturze obiektu sterownika: jest to tablica MajorFunction w strukturze DRIVER_OBJECT.

Złośliwe główne uchwyty pokazane na rysunku 1.3 przechwytują pakiety IRP_MJ_INTERNAL_CONTROL oraz IRP_MJ_DEVICE_CONTROL przeznaczone dla poniższego kodu Input/Output Control (IOCTL) w celu monitorowania i modyfikowania żądań odczytu/zapisu z dysku twardego, przechowania zainfekowanego sterownika i obrazu ukrytego systemu plików implementowanego przez złośliwe oprogramowanie:

- IOCTL_ATA_PASS_THROUGH_DIRECT

- IOCTL_ATA_PASS_THROUGH

Rysunek 1.3. Zahaczanie obiektu sterownika miniportu pamięci masowej

TDL3 blokuje możliwość odczytywania sektorów dysku twardego zawierającego chronione dane przez narzędzia systemu Windows i ich przypadkowe nadpisanie przez system plików Windows, tym samym chroniąc zarówno niewykrywalność, jak i integralność rootkita. Przy natrafieniu na operację odczytu TDL3 zeruje bufor zwracany po zakończeniu operacji wejścia/wyjścia, a w przypadku żądania zapisu pomija całą operację odczytu. Technika hooków TDL3 pozwala mu na obejście niektórych technik wykrywania modyfikacji jądra; inaczej mówiąc, operacje wykonywane przez TDL3 nie dotykają żadnych często chronionych i monitorowanych obszarów, w tym modułów systemu, System Service Descriptor Table (SSDT), Global Descriptor Table (GDT) ani Interrupt Descriptor Table (IDT). Jego następca, TDL4, przyjmuje to samo podejście w celu ominięcia ochrony przed mechanizmem PatchGuard dostępnym w 64-bitowych systemach operacyjnych Windows, ponieważ dziedziczy znaczącą część funkcjonalności trybu jądra z TDL3, w tym opisane wyżej hooki do sterownika miniportu pamięci masowej.

Ukryty system plików

TDL3 był pierwszą rodziną złośliwego oprogramowania, które przechowywało swoje pliki konfiguracyjne i payload[4] w ukrytym, szyfrowanym obszarze pamięci masowej docelowego systemu, zamiast polegania na usłudze systemu plików oferowanej przez system operacyjny. Obecnie podejście TDL3 zostało przyjęte i dostosowane przez inne zaawansowane zagrożenia, takie jak Rovnix Bootkit, ZeroAccess, Avatar czy Gapz.

Ta technika ukrytej pamięci masowej znacząco utrudnia analizę, gdyż złośliwe dane są przechowywane w zaszyfrowanym kontenerze zlokalizowanym gdzieś na dysku twardym, ale poza obszarem zarezerwowanym przez własny system plików systemu operacyjnego. Jednocześnie złośliwe oprogramowanie jest w stanie uzyskiwać dostęp do ukrytego systemu plików, wykorzystując standardowe API Win32, takie jak CreateFile, ReadFile, WriteFile i CloseHandle. Upraszcza to tworzenie złośliwej zawartości, pozwalając projektantom oprogramowania na korzystanie ze standardowych interfejsów Windows w celu odczytywania i zapisywania zawartości z obszaru pamięci masowej bez konieczności tworzenia i utrzymywania jakiś niestandardowych interfejsów. Takie decyzje projektowe są znaczące, gdyż łącznie z użyciem standardowych interfejsów dla hooków zwiększa to ogólną niezawodność rootkita; z punktu widzenia inżynierii oprogramowania jest to przykład dobrego i właściwego ponownego wykorzystania kodu! Formuła sukcesu wg. CEO firmy Microsoft brzmiała „Developers, developers, developers, developers!” – innymi słowy, traktowanie istniejących umiejętności programistycznych jako cennego kapitału. Analogicznie TDL3 wykorzystuje istniejące umiejętności programowania dla Windows tych deweloperów, którzy przeszli na ciemną stronę, zapewne zarówno w celu ułatwienia tego przejścia, jak i zwiększenia niezawodności złośliwego kodu.

TDL3 umieszcza swój obraz ukrytego systemu plików na dysku twardym w sektorach, których nie zajmuje właściwy system plików systemu operacyjnego. Obraz ten powiększa się od końca dysku w stronę jego początku, co oznacza, że ostatecznie może nadpisać dane systemu plików użytkownika, o ile urośnie dostatecznie. Obraz ten jest podzielony na bloki po 1024 bajty. Pierwszy blok (na samym końcu dysku twardego) zawiera tabelę plików, której wpisy opisują pliki zawarte w systemie plików i obejmują następujące informacje:

- nazwę pliku ograniczoną do 16 znaków, w tym końcowy znak null;

- rozmiar pliku;

- rzeczywiste przesunięcie pliku, które można obliczyć, odejmując od przesunięcia początku systemu plików początkowe przesunięcie pliku pomnożone przez 1024;

- czas utworzenia systemu plików.

Zawartość systemu plików jest szyfrowana niestandardowym (i głównie wybranym ad hoc) algorytmem szyfrowaniem opartym na blokach. Różne wersje rootkita używały różnych algorytmów. Na przykład, pewne modyfikacje wykorzystywały szyfrowanie RC4, jako klucza używając logicznego adresu bloku (logical block address – LBA) pierwszego sektora odpowiadającego każdemu blokowi. Jednak inna modyfikacja szyfrowała dane przy użyciu operacji XOR z ustalonym kluczem: zwiększanym o 0x54 przy każdej operacji XOR, co dawało szyfrowanie wystarczająco słabe, aby można było łatwo zauważyć szczególny wzorzec odpowiadający zaszyfrowanym blokom zawierającym zera.

W trybie użytkownika dostęp do zawartości w ukrytej pamięci masowej następował przez otwarcie uchwytu dla obiektu urządzenia o nazwie \Device\XXXXXXXX\YYYYYYYY, gdzie XXXXXXXX i YYYYYYYY są losowo wygenerowanymi liczbami szesnastkowymi. Zauważmy, że ścieżka kodu zapewniająca dostęp do tej pamięci masowej opiera się na wielu standardowych komponentach Windows – zapewne już zdebugowanych przez firmę Microsoft, a tym samym niezawodnych. Nazwa obiektu urządzenia jest generowana przy każdym rozruchu systemu, a następnie przekazywana jako parametr do modułów payloadu. Rootkit jest odpowiedzialny za obsługę żądań wejścia/wyjścia do tego systemu plików. Na przykład, gdy moduł payload wykonuje operację wejścia/wyjścia względem pliku przechowywanego w ukrytym obszarze pamięci masowej, OS przekazuje to żądanie do rootkita i wykonuje jego funkcje punktu wejściowego, aby obsłużyć żądanie.

W tym wzorcu projektowym TDL3 ilustruje ogólny trend występujący w rootkitach. Zamiast dostarczania całkiem nowego kodu dla wszystkich operacji i obciążania innych deweloperów złośliwego oprogramowania koniecznością nauczenia się specyfiki tego kodu, rootkit jedzie „na barana” na istniejącej i dobrze znanej funkcjonalności Windows – sprawdza się, dopóki te triki i wykorzystywane przez nie interfejsy Windows nie są powszechnie znane. Wraz ze zmianami w masowo stosowanych środkach obronnych wyewoluowały szczególne metody infekcji, ale to podejście się zachowało, jako że jest ono zgodne z powszechnymi zasadami niezawodności kodu, wspólnymi dla projektowania zarówno złośliwego, jak i życzliwego oprogramowania.

Podsumowanie: TDL3 spotyka swoją Nemesis

Jak widzieliśmy, TDL3 jest zaawansowanym rootkitem, który wprowadził szereg technik zapewniających potajemne i trwałe działanie w zainfekowanym systemie. Jego hooki trybu jądra i ukryte systemy plików nie zostały niezauważone przez innych twórców złośliwego oprogramowania, a tym samym pojawiły się później w innych złożonych zagrożeniach. Jedynym ograniczeniem procedury infekcji było to, że mogła ona atakować tylko systemy 32-bitowe.

Gdy TDL3 zaczął się rozpowszechniać, realizował zadanie zaplanowane przez jego twórców, ale wraz ze wzrostem liczby 64-bitowych systemów rósł popyt na możliwość infekowania systemów x64. Aby to osiągnąć, twórcy złośliwego oprogramowania musieli odkryć, jak pokonać zasadę podpisywania kodu trybu jądra w 64-bitowych systemach, aby móc załadować złośliwy kod do przestrzeni adresowej trybu jądra. Jak pokażemy w rozdziale 7, autorzy TDL3 jako sposób ominięcia wymuszenia podpisywania kodu wybrali technikę bootkitu.

PRZYPISY

Rozdział 1

[1] http://static1.esetstatic.com/us/resources/white-papers/TDL3-Analysis.pdf.

[2] Rodrigo Rubira Branco, Gabriel Negreira Barbosa i Pedro Drimel Neto, „Scientific but not academic overview of malware anti-debugging, anti-disassembly and anti-VM technologies” (dokument przedstawiony na konferencji Black Hat USA 2012, 21–26 czerwca, Las Vegas, Nevada), https://media.blackhat.com/bh-us-12/Briefings/Branco/BH_US_12_Branco_Scientific_Academic_WP.pdf.

[3] https://blogs.technet.microsoft.com/markrussinovich/2005/10/31/sony-rootkits-and-digital-rights-management-gone-too-far/.

[4] Payload – kod, który wykonuje rzeczywistą szkodliwą pracę (przyp. tłum.).