Rzuciłem okiem ostatnio na pewne narzędzie, które służyło do "zabezpieczania" środowiska pracy użytkownika. Nie wdając się w szczegóły procesy uruchomione w tym środowisku miały pewne dodatkowe ograniczenia, na przykład odnośnie uruchamiania innych procesów (lista dozwolonych), zapisywania danych, kopiowania plików. Gdy widzę takie rozwiązanie zawsze przede wszystkim zastanawiam się nad tym, jak je można obejść. Do tego dobrze jest wiedzieć (przynajmniej w przybliżeniu) jak to coś działa. Nie miałem na to zbyt wiele czasu, ale szybkie zbadanie sprawy przy pomocy Process Monitor pokazało, że "chronione" procesy ładują dodatkowe biblioteki. Moja pierwsza hipoteza zakłada więc API Hooking. Tylko jak łatwo ją potwierdzić?
Wykrywanie API hooking
Założenia
Zakładam, że dysponuję zrzutem pamięci systemu. Zrzut pamięci jest utworzony na przykład przy pomocy narzędzia windd (nie mylić z tym windd!). Zrzut ten może być w formacie Microsoft Crash Dump lub być po prostu kopią zawartości pamięci fizycznej. Zaletą pierwszego formatu jest to, że można załadować go do Debugging Tools For Windows, format surowy jest preferowany w przypadku narzędzi takich jak Volatility czy Memoryze.
W tym wypadku interesuje mnie usermode, czyli głównie:
- IAT (Import Address Table),
- EAT (Export Address Table),
- Hot patching,
Dodatkowym ograniczeniem jest fakt, iż w tym temacie nie jestem zbyt dobry, dlatego szukam rozwiązań łatwych.
Generowanie danych testowych
W tym eksperymencie wolę wiedzieć co powinienem znaleźć. Innymi słowy chcę kontrolować na czym i jakiego typu hook jest założony. Nie potrzebuję bardzo skomplikowanych przykładów, dlatego do wygenerowania danych testowych (czyli testowych zrzutów pamięci) w zupełności wystarczy przykładowy program zawarty w HookLib.
EAT, hot patching i WinDbg
Metoda wykrywania modyfikacji EAT oraz modyfikacji kodu programów i bibliotek znajdujących się w pamięci jest stosunkowo prosta. Oczywiście pod warunkiem, że poza zrzutem pamięci dysponujemy odpowiednim "oryginalnym" plikiem. Porównanie załadowanego obrazu z plikiem może pokazać ewentualne różnice.
Na początek przykład bez założonego hooka:
0:001> !for_each_module !chkimg -p c:\virtualpc @#ModuleName 0 errors : HookLibTest 0 errors : uxtheme 0 errors : MSCTF 0 errors : msctfime 0 errors : IMM32 0 errors : OLEAUT32 0 errors : ole32 0 errors : msvcrt 0 errors : ADVAPI32 0 errors : RPCRT4 0 errors : GDI32 0 errors : Secur32 0 errors : kernel32 0 errors : ntdll 0 errors : USER32
Jak widać zarówno sam plik programu, jak i ładowane przez niego biblioteki nie zostały zmienione w pamięci.
Sytuacja zmienia się, gdy zostanie założony hook:
0:001> !for_each_module !chkimg -p c:\virtualpc @#ModuleName 0 errors : HookLibTest 0 errors : uxtheme 0 errors : MSCTF 0 errors : msctfime 0 errors : IMM32 0 errors : OLEAUT32 0 errors : ole32 0 errors : msvcrt 0 errors : ADVAPI32 0 errors : RPCRT4 0 errors : GDI32 0 errors : Secur32 0 errors : kernel32 0 errors : ntdll 7 errors : USER32 (7e4507e5-7e4507eb)
0:001> !for_each_module !chkimg -p c:\virtualpc @#ModuleName 0 errors : HookLibTest 0 errors : uxtheme 0 errors : MSCTF 0 errors : msctfime 0 errors : IMM32 0 errors : OLEAUT32 0 errors : ole32 0 errors : msvcrt 0 errors : ADVAPI32 0 errors : RPCRT4 0 errors : GDI32 0 errors : Secur32 0 errors : kernel32 0 errors : ntdll 4 errors : USER32 (7e414098-7e41409b)
W tych dwóch przypadkach widać, że modyfikowany jest obraz biblioteki USER32. Można uzyskać dokładniejsze dane o modyfikacjach:
0:001> !chkimg user32 4 errors : user32 (7e414098-7e41409b) 0:001> ln 7e414098 (7e413900) USER32!$$VProc_ImageExportDirectory+0x798 | (7e4184ae) USER32!NtUserCallOneParam
W tym wypadku widać, że zmiany (obszar, który uległ zmianie pokazuje polecenie !chkimg) znajduje się prawdopodobnie w EAT (ln pokazuje najbliższe względem podanego adresu symbole).
W drugim przypadku zmiany wglądają nieco inaczej:
0:001> !chkimg user32 7 errors : user32 (7e4507e5-7e4507eb) 0:001> ln 7e4507e5 (7e4507df) USER32!GdiConvertMetaFilePict+0x6 | (7e4507ea) USER32!MessageBoxA
W zmienionym zakresie obecnie znajduje się taki kod:
0:001> u 7e4507e5 7e4507eb USER32!GdiConvertMetaFilePict+0x6: 7e4507e5 e91608fb81 jmp HookLibTest+0x1000 (00401000) USER32!MessageBoxA: 7e4507ea ebf9 jmp USER32!GdiConvertMetaFilePict+0x6 (7e4507e5)
Przed zmianą (albo inaczej - po naprawieniu), kod ten wyglądał tak:
0:001> !chkimg -f user32 Warning: Any detected errors will be fixed to what we expect! 7 errors (fixed): user32 (7e4507e5-7e4507eb) 0:001> u 7e4507e5 7e4507eb USER32!GdiConvertMetaFilePict+0x6: 7e4507e5 90 nop 7e4507e6 90 nop 7e4507e7 90 nop 7e4507e8 90 nop 7e4507e9 90 nop USER32!MessageBoxA: 7e4507ea 8bff mov edi,edi
Jak widać na powyższych przykładach !chkimg jest dość skutecznym sposobem wykrywania modyfikacji EAT lub modyfikacji kodu (hot patching).
IAT i !chkimg
Niestety, tej samej techniki nie można zastosować do wyszukiwania modyfikacji IAT, z opisu !chkimg:
Addresses that are occupied by the Import Address Table (IAT) are not checked.
Dlaczego? Wynika to z tego, czym właściwie jest Import Address Table (patrz: Understanding the Import Address Table). Można przyjąć w uproszczeniu, że to co znajduje się w IAT w pamięci jest konstruowane dynamicznie, więc porównywanie pamięci z obrazem pliku jest bezcelowe.
Jak wykryć modyfikację IAT
Z tego co wiem, sprawa jest dość prosta, choć pracochłonna. Należy zweryfikować, czy adresy w IAT wskazują na "prawidłowe" adresy. Czyli przypadkowo czy adres pokazujący na funkcję MessageBoxA (bo ta jest wykorzystana w przykładach) pokazuje rzeczywiście na adres, pod którym ta funkcja jest dostępna w bibliotece USER32. Problem w tym, że nie bardzo widzę prosty sposób na wyświetlenie IAT w WinDbg, ale mogę się mylić.
To, że coś nie jest proste, nie znaczy, że się nie da tego zrobić: Import Table Functions. Wykorzystując podane tam skrypty można zobaczyć coś takiego:
(...) 00408014 7e43b144 USER32!DialogBoxParamA 00408018 7e424a4e USER32!EndDialog 0040801c 7e42436e USER32!GetDlgItem 00408020 7e4507ea USER32!MessageBoxA 00408024 7e42f3c2 USER32!SendMessageA 00408028 7e43c2e7 USER32!SendDlgItemMessageA 0040802c 7e45085c USER32!MessageBoxExA (...)
(...) 00408014 7e43b144 USER32!DialogBoxParamA 00408018 7e424a4e USER32!EndDialog 0040801c 7e42436e USER32!GetDlgItem 00408020 00401000 HookLibTest+0x1000 00408024 7e42f3c2 USER32!SendMessageA 00408028 7e43c2e7 USER32!SendDlgItemMessageA 0040802c 7e45085c USER32!MessageBoxExA (...)
Pierwszy zrzut to przypadek "czysty". Jak widać import wskazuje na USER32!MessageBoxA. W drugim przypadku import ten jest podmieniony i wskazuje na miejsce w obrębie HookLibTest.
Wykorzystany skrypt trzeba trochę zmodyfikować by móc go wykorzystać do nieco wygodniejszego wykrywania takich modyfikacji. Powinien przynajmniej wypisywać informację gdzie powinien dany element wskazywać, a jeszcze lepiej, gdyby wypisywał tylko te przypadki, w których teoria (to, gdzie powinien wskazywać) nie pokrywa się z praktyką (to, gdzie wskazuje).
Co dalej?
Co dalej? To dość oczywiste. Muszę tylko zrzucić pamięć w odpowiednim momencie, a później sprawdzić czy moja hipoteza jest słuszna. Jestem prawie pewien, że tak. Podobne rozwiązanie stosowane jest w Google Chrome jako część sandboxa (patrz: Sandbox w Google Chrome). Warto też zastanowić się jak (nie)skuteczne jest tego typu rozwiązanie, przy czym najpierw dobrze jest ustalić przed czym tak naprawdę ma ono chronić.
Przy okazji w wolnej chwili sprawdzę, czy z wykrywaniem tego typu hooków (głównie IAT i EAT) jest w stanie poradzić sobie wspomniane już Memoryze. Jeśli chodzi o Volatility to warto tu wspomnieć o Volatility Analyst Pack (patrz: New and Updated Volatility Plug-ins Part II), który teoretycznie robi dokładnie to, czego szukam. Teoretycznie, bo jeszcze nie udało mi się z powodzeniem uruchomić tych pluginów...
Drobne uzupełnienie do wpisu Wykrywanie API hooking, a konkretnie do możliwości wykorzystania narzędzia Volatility w tym celu. Wspominałem, że istnieje plugin służący do wykrywania API Hooking, ale nie udało mi się go (jeszcze) użyć. Poświęciłem temu tema
Przesłany: Mar 17, 07:21
Jeśli po mojej prezentacji na dzisiejszym spotkaniu OWASP kogoś zainteresował temat ogólnie pojętego forensic, być może zainteresują go również starsze wpisy dotyczące tego tematu. Nazbierało się tego trochę, więc małe przypomnienie części z poruszanych t
Przesłany: Jun 10, 20:54