the shellcoders handbook. edycja polska

51
Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: [email protected] PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ IDZ DO IDZ DO ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG KATALOG KSI¥¯EK KATALOG KSI¥¯EK TWÓJ KOSZYK TWÓJ KOSZYK CENNIK I INFORMACJE CENNIK I INFORMACJE ZAMÓW INFORMACJE O NOWOCIACH ZAMÓW INFORMACJE O NOWOCIACH ZAMÓW CENNIK ZAMÓW CENNI K CZYTELNIA CZYTELNIA FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE SPIS TRECI SPIS TRECI DODAJ DO KOSZYKA DODAJ DO KOSZYKA KATALOG ONLINE KATALOG ONLINE The Shellcoders Handbook. Edycja polska Usuñ luki w zabezpieczeniach programów i systemów operacyjnych • Poznaj przyczyny powstawania luk • Naucz siê sposobów w³amañ do systemów • Podejmij odpowiednie rodki zapobiegawcze Niemal co tydzieñ dowiadujemy siê o nowych „³atach” usuwaj¹cych luki w zabezpieczeniach systemów operacyjnych i programów. Niestety — czêsto, zanim ³ata zostanie rozpowszechniona i zainstalowana na komputerach, kto wykorzysta „dziurê” w systemie i w³amie siê do niego. Có¿ wiêc zrobiæ, aby zabezpieczyæ swoje dane przez atakiem hakera? Jak znaleæ s³abe punkty zabezpieczeñ i usun¹æ je? W jaki sposób zaimplementowaæ odpowiednie zabezpieczenia w tworzonym przez siebie oprogramowaniu? Ksi¹¿ka „The Shellcoder’s handbook. Edycja polska” zawiera odpowiedzi na wszystkie te pytania. Ksi¹¿ka bêd¹ca efektem pracy zespo³u z³o¿onego ze specjalistów w zakresie bezpieczeñstwa systemów komputerowych, analityków i hakerów przedstawia sposoby wykrywania s³abych punktów oprogramowania tworzonego w jêzyku C i sprawdzenia mo¿liwoci ich wykorzystania. Opisuje luki w istniej¹cych systemach i programach oraz sposoby ich zabezpieczenia. Zawarte w niej wiadomoci pozwol¹ na tworzenie w³asnych systemów wykrywania b³êdów i pomog¹ ustaliæ, czy b³êdy te stanowi¹ potencjalne zagro¿enie. • Podstawowe metody w³amañ do ró¿nych systemów operacyjnych • Techniki przepe³niania stosu, wykorzystywania kodu pow³oki i b³êdów ³añcuchów formatuj¹cych • Kontrola s³abych punktów programów metodami wstrzykiwania kodu i fuzzingu • Kontrola kodu ród³owego programów • Klasy b³êdów • Sposoby ledzenia s³abych punktów • Analiza kodu binarnego • Tworzenie eksploitów • Ataki na systemy zarz¹dzania bazami danych Autorzy: J. Koziol, D. Litchfield, D. Aitel, Ch. Anley, S. Eren, N. Mehta, R. Hassell T³umaczenie: Jaromir Senczyk ISBN: 83-7361-597-0 Tytu³ orygina³u: The Shellcoders Handbook Format: B5, stron: 560 Przyk³ady na ftp: 165 kB

Upload: wydawnictwo-helion

Post on 05-Dec-2014

746 views

Category:

Technology


2 download

DESCRIPTION

Usuń luki w zabezpieczeniach programów i systemów operacyjnych * Poznaj przyczyny powstawania luk* Naucz się sposobów włamań do systemów* Podejmij odpowiednie środki zapobiegawcze Niemal co tydzień dowiadujemy się o nowych "łatach" usuwających luki w zabezpieczeniach systemów operacyjnych i programów. Niestety -- często, zanim łata zostanie rozpowszechniona i zainstalowana na komputerach, ktoś wykorzysta "dziurę" w systemie i włamie się do niego. Cóż więc zrobić, aby zabezpieczyć swoje dane przez atakiem hakera? Jak znaleźć słabe punkty zabezpieczeń i usunąć je? W jaki sposób zaimplementować odpowiednie zabezpieczenia w tworzonym przez siebie oprogramowaniu? Książka "The Shellcoder’s handbook. Edycja polska" zawiera odpowiedzi na wszystkie te pytania. Książka będąca efektem pracy zespołu złożonego ze specjalistów w zakresie bezpieczeństwa systemów komputerowych, analityków i hakerów przedstawia sposoby wykrywania słabych punktów oprogramowania tworzonego w języku C i sprawdzenia możliwości ich wykorzystania. Opisuje luki w istniejących systemach i programach oraz sposoby ich zabezpieczenia. Zawarte w niej wiadomości pozwolą na tworzenie własnych systemów wykrywania błędów i pomogą ustalić, czy błędy te stanowią potencjalne zagrożenie. * Podstawowe metody włamań do różnych systemów operacyjnych* Techniki przepełniania stosu, wykorzystywania kodu powłoki i błędów łańcuchów formatujących* Kontrola słabych punktów programów metodami wstrzykiwania kodu i fuzzingu* Kontrola kodu źródłowego programów* Klasy błędów* Sposoby śledzenia słabych punktów* Analiza kodu binarnego* Tworzenie eksploitów* Ataki na systemy zarządzania bazami danych Nie dopuść do tego, aby Twoje programy padły ofiarą ataku hakera.

TRANSCRIPT

Page 1: The Shellcoders Handbook. Edycja polska

Wydawnictwo Helion

ul. Chopina 6

44-100 Gliwice

tel. (32)230-98-63

e-mail: [email protected]

PRZYK£ADOWY ROZDZIA£PRZYK£ADOWY ROZDZIA£

IDZ DOIDZ DO

ZAMÓW DRUKOWANY KATALOGZAMÓW DRUKOWANY KATALOG

KATALOG KSI¥¯EKKATALOG KSI¥¯EK

TWÓJ KOSZYKTWÓJ KOSZYK

CENNIK I INFORMACJECENNIK I INFORMACJE

ZAMÓW INFORMACJEO NOWO�CIACH

ZAMÓW INFORMACJEO NOWO�CIACH

ZAMÓW CENNIKZAMÓW CENNIK

CZYTELNIACZYTELNIA

FRAGMENTY KSI¥¯EK ONLINEFRAGMENTY KSI¥¯EK ONLINE

SPIS TRE�CISPIS TRE�CI

DODAJ DO KOSZYKADODAJ DO KOSZYKA

KATALOG ONLINEKATALOG ONLINE

The Shellcoders Handbook.Edycja polska

Usuñ luki w zabezpieczeniach programów i systemów operacyjnych

• Poznaj przyczyny powstawania luk

• Naucz siê sposobów w³amañ do systemów

• Podejmij odpowiednie �rodki zapobiegawcze

Niemal co tydzieñ dowiadujemy siê o nowych „³atach” usuwaj¹cych luki

w zabezpieczeniach systemów operacyjnych i programów. Niestety — czêsto, zanim ³ata

zostanie rozpowszechniona i zainstalowana na komputerach, kto� wykorzysta „dziurê”

w systemie i w³amie siê do niego. Có¿ wiêc zrobiæ, aby zabezpieczyæ swoje dane przez

atakiem hakera? Jak znale�æ s³abe punkty zabezpieczeñ i usun¹æ je? W jaki sposób

zaimplementowaæ odpowiednie zabezpieczenia w tworzonym przez siebie

oprogramowaniu?

Ksi¹¿ka „The Shellcoder’s handbook. Edycja polska” zawiera odpowiedzi na wszystkie

te pytania. Ksi¹¿ka bêd¹ca efektem pracy zespo³u z³o¿onego ze specjalistów w zakresie

bezpieczeñstwa systemów komputerowych, analityków i hakerów przedstawia sposoby

wykrywania s³abych punktów oprogramowania tworzonego w jêzyku C i sprawdzenia

mo¿liwo�ci ich wykorzystania. Opisuje luki w istniej¹cych systemach i programach

oraz sposoby ich zabezpieczenia. Zawarte w niej wiadomo�ci pozwol¹ na tworzenie

w³asnych systemów wykrywania b³êdów i pomog¹ ustaliæ, czy b³êdy te stanowi¹

potencjalne zagro¿enie.

• Podstawowe metody w³amañ do ró¿nych systemów operacyjnych

• Techniki przepe³niania stosu, wykorzystywania kodu pow³oki

i b³êdów ³añcuchów formatuj¹cych

• Kontrola s³abych punktów programów metodami wstrzykiwania kodu i fuzzingu

• Kontrola kodu �ród³owego programów

• Klasy b³êdów

• Sposoby �ledzenia s³abych punktów

• Analiza kodu binarnego

• Tworzenie eksploitów

• Ataki na systemy zarz¹dzania bazami danych

Autorzy: J. Koziol, D. Litchfield, D. Aitel,

Ch. Anley, S. Eren, N. Mehta, R. Hassell

T³umaczenie: Jaromir Senczyk

ISBN: 83-7361-597-0

Tytu³ orygina³u: The Shellcoders Handbook

Format: B5, stron: 560

Przyk³ady na ftp: 165 kB

Page 2: The Shellcoders Handbook. Edycja polska

Spis treści

O Autorach ...................................................................................... 13

Część I Wprowadzenie do metod włamań:Linux na procesorach x86 ..............................................15

Rozdział 1. Wprowadzenie ................................................................................. 17Podstawowe pojęcia ........................................................................................................ 17

Zarządzanie pamięcią................................................................................................ 18Asembler ................................................................................................................... 20

Rozpoznawanie przekładu kodu C++ w języku asemblera.............................................. 21Podsumowanie ................................................................................................................ 23

Rozdział 2. Przepełnienia stosu.......................................................................... 25Bufory ............................................................................................................................. 25Stos.................................................................................................................................. 27

Wywołania funkcji i stos........................................................................................... 28Przepełnianie buforów na stosie ...................................................................................... 31

Wykorzystanie rejestru EIP....................................................................................... 32Zdobywanie uprawnień root............................................................................................ 34

Problem adresu.......................................................................................................... 36Metoda rozkazów NOP ............................................................................................. 39

Stos zabraniający wykonywania rozkazów ..................................................................... 41Metoda powrotu do biblioteki libc ............................................................................ 41

Podsumowanie ................................................................................................................ 44

Rozdział 3. Kod powłoki..................................................................................... 45Wywołania systemowe.................................................................................................... 46Kod powłoki używający wywołania systemowego exit()................................................ 48Wstrzykiwanie kodu powłoki.......................................................................................... 51Tworzenie nowej powłoki ............................................................................................... 53Podsumowanie ................................................................................................................ 61

Rozdział 4. Błędy łańcuchów formatujących ....................................................... 63Warunki wstępne............................................................................................................. 63Łańcuchy formatujące ..................................................................................................... 63Błędy łańcuchów formatujących ..................................................................................... 65

Page 3: The Shellcoders Handbook. Edycja polska

6 The Shellcoder's Handbook. Edycja polska

Włamania za pomocą łańcuchów formatujących............................................................. 69Atak na usługę........................................................................................................... 70Ujawnianie informacji............................................................................................... 71

Przejęcie sterowania ........................................................................................................ 76Jak to możliwe?............................................................................................................... 85Przegląd technik łańcucha formatującego ....................................................................... 85Podsumowanie ................................................................................................................ 88

Rozdział 5. Wprowadzenie do metod przepełnienia sterty.................................... 89Sterta ............................................................................................................................... 89

Zarządzanie stertą...................................................................................................... 91Wyszukiwanie przepełnień sterty .................................................................................... 91

Podstawowe metody przepełniania sterty.................................................................. 92Średnio zaawansowane metody przepełniania stosu ................................................. 98Zaawansowane przepełnienia sterty ........................................................................ 104

Podsumowanie .............................................................................................................. 105

Część II Włamania na platformach Windows, Solaris i Tru64.......107

Rozdział 6. Wprowadzenie do systemu Windows............................................... 109Różnice między systemami Linux i Windows............................................................... 109

Win32 i PE-COFF................................................................................................... 110Sterty ............................................................................................................................. 112

Wątki....................................................................................................................... 113Zalety i wady DCOM i DCE-RPC ................................................................................ 114

Rozpoznanie............................................................................................................ 116Włamania ................................................................................................................ 117Tokeny i podszywanie............................................................................................. 118Obsługa wyjątków w Win32 ................................................................................... 120

Śledzenie działania programów w systemie Windows .................................................. 121Błędy w Win32 ....................................................................................................... 122Tworzenie kodu powłoki w systemie Windows...................................................... 122Przewodnik hakera po funkcjach Win32................................................................. 123Rodzina systemów Windows z punktu widzenia hakera......................................... 123

Podsumowanie .............................................................................................................. 124

Rozdział 7. Kody powłoki w Windows ............................................................... 125Składnia i filtry.............................................................................................................. 125Przygotowywanie kodu powłoki ................................................................................... 126Parsowanie bloków PEB ............................................................................................... 127

Analiza kodu heapoverflow.c.................................................................................. 128Przeszukiwanie z użyciem obsługi wyjątków................................................................ 143Tworzenie nowej powłoki ............................................................................................. 146

Dlaczego nie warto tworzyć nowej powłoki w Windows ....................................... 147Podsumowanie .............................................................................................................. 148

Rozdział 8. Przepełnienia w systemie Windows................................................. 149Przepełnienia buforów na stosie .................................................................................... 149

Procedury obsługi wyjątków dla ramek wywołań funkcji....................................... 150Wykorzystanie procedur obsługi wyjątków na platformie Windows 2003 Server.. 154Końcowe uwagi na temat nadpisań procedur obsługi wyjątków............................. 158

Ochrona stosu i Windows 2003 Server ......................................................................... 159Przepełnienia sterty ....................................................................................................... 164

Sterta procesu.......................................................................................................... 164Sterty dynamiczne................................................................................................... 165

Page 4: The Shellcoders Handbook. Edycja polska

Spis treści 7

Korzystanie ze sterty ............................................................................................... 165Jak działa sterta ....................................................................................................... 165

Wykorzystanie przepełnień sterty.................................................................................. 168Nadpisanie wskaźnika funkcji RtlEnterCriticalSection w bloku PEB..................... 169Nadpisanie wskaźnika pierwszej wektoryzowanej procedury obsługi wyjątków

pod adresem 77FC3210 ........................................................................................ 171Nadpisanie wskaźnika filtra nieobsłużonych wyjątków.......................................... 174Nadpisanie wskaźnika procedury obsługi wyjątków w bloku TEB ........................ 179Naprawa sterty ........................................................................................................ 180Inne aspekty przepełnień sterty ............................................................................... 182Podsumowanie przepełnień sterty ........................................................................... 183

Inne przepełnienia ......................................................................................................... 183Przepełnienia sekcji .data ........................................................................................ 183Przepełnienia bloków TEB i PEB ........................................................................... 185

Przepełnienie buforów i stosy zabraniające wykonania kodu........................................ 185Podsumowanie .............................................................................................................. 190

Rozdział 9. Filtry ............................................................................................. 191Tworzenie eksploitów i filtry alfanumeryczne .............................................................. 191Tworzenie eksploitów i filtry Unicode .......................................................................... 195

Unicode................................................................................................................... 195Konwersja z ASCII na Unicode .............................................................................. 196

Wykorzystanie słabych punktów związanych z kodem Unicode .................................. 196Zbiór rozkazów dostępnych dla eksploitów Unicode.............................................. 197

Metoda wenecka............................................................................................................ 198Implementacja metody weneckiej dla kodu ASCII ................................................. 199

Dekoder i dekodowanie................................................................................................. 202Kod dekodera .......................................................................................................... 203Ustalenie adresu bufora........................................................................................... 204

Podsumowanie .............................................................................................................. 205

Rozdział 10.Wprowadzenie do włamań w systemie Solaris ................................. 207Wprowadzenie do architektury SPARC ........................................................................ 208

Rejestry i okna rejestrów......................................................................................... 208Szczelina zwłoki ..................................................................................................... 210Rozkazy złożone ..................................................................................................... 211

Kody powłoki na platformie Solaris/SPARC ................................................................ 211Kod powłoki i określanie własnego położenia ........................................................ 212Prosty kod powłoki dla platformy SPARC.............................................................. 212Przydatne wywołania systemu Solaris .................................................................... 213Rozkaz NOP i rozkazy wypełniające ...................................................................... 214

Ramki na stosie platformy Solaris/SPARC ................................................................... 214Techniki przepełnień stosu ............................................................................................ 215

Przepełnienia o dowolnym rozmiarze ..................................................................... 215Okna rejestrów komplikują przepełnienia stosu...................................................... 216Inne czynniki utrudniające przepełnienia stosu....................................................... 216Możliwe rozwiązania .............................................................................................. 217Przepełnienia jednym bajtem .................................................................................. 217Położenie kodu powłoki .......................................................................................... 218

Przykłady przepełnień stosu .......................................................................................... 219Atakowany program................................................................................................ 219Eksploit ................................................................................................................... 221

Przepełnienia sterty na platformie Solaris/SPARC........................................................ 224Wprowadzenie do sterty systemu Solaris................................................................ 224Struktura drzewa sterty............................................................................................ 225

Page 5: The Shellcoders Handbook. Edycja polska

8 The Shellcoder's Handbook. Edycja polska

Metoda podstawowa (t_delete)...................................................................................... 243Ograniczenia standardowych przepełnień sterty ..................................................... 246Cele nadpisań .......................................................................................................... 247

Inne słabe punkty sterty................................................................................................. 249Przepełnienia jednym bajtem .................................................................................. 250Podwójne zwolnienie .............................................................................................. 250Inne błędy funkcji free().......................................................................................... 250

Przykład przepełnienia sterty......................................................................................... 251Atakowany program................................................................................................ 251

Inne techniki włamań w systemie Solaris...................................................................... 255Przepełnienia danych statycznych........................................................................... 255Obejście zabezpieczenia stosu................................................................................. 255

Podsumowanie .............................................................................................................. 256

Rozdział 11. Zaawansowane metody włamań w systemie Solaris........................ 257Śledzenie modułu dynamicznej konsolidacji krok po kroku ......................................... 258Sztuczki przepełnień sterty Solaris/SPARC .................................................................. 271Zaawansowany kod powłoki na platformie Solaris/SPARC ......................................... 273Podsumowanie .............................................................................................................. 284

Rozdział 12.Włamania w systemie HP Tru64 Unix ............................................. 285Architektura procesorów Alpha..................................................................................... 286

Rejestry procesorów Alpha ..................................................................................... 286Zbiór rozkazów ....................................................................................................... 287Konwencje wywołań............................................................................................... 287

Pobieranie licznika rozkazów (GetPC).......................................................................... 289Wywołania systemowe.................................................................................................. 291Dekoder XOR dla kodu powłoki ................................................................................... 291Kod powłoki setuid + execve ........................................................................................ 293

Wywołania systemowe setuid(0) i execve("/bin/sh", ...) ......................................... 293Kompilacja kodu w asemblerze i wyodrębnienie kodu powłoki ............................. 294Kodowanie uzyskanych kodów powłoki funkcją XOR........................................... 295Dołączenie zakodowanego kodu do dekodera XOR ............................................... 296Kompilacja i wyodrębnienie ostatecznej postaci kodu powłoki.............................. 297

Kod powłoki zestawiający połączenie zwrotne ............................................................. 299Kod powłoki wyszukujący gniazdo sieciowe ................................................................ 300Kod powłoki dowiązujący gniazdo sieciowe................................................................. 301Przepełnienia stosu........................................................................................................ 303

Obejście ochrony stosu ........................................................................................... 303Włamanie do usługi rpc.ttdbserver ................................................................................ 304Podsumowanie .............................................................................................................. 311

Część III Wykrywanie słabych punktów .......................................313

Rozdział 13. Tworzenie środowiska pracy........................................................... 315Źródła informacji........................................................................................................... 316Narzędzia do tworzenia kodu ........................................................................................ 316

gcc........................................................................................................................... 316gdb .......................................................................................................................... 317NASM..................................................................................................................... 317WinDbg................................................................................................................... 317OllyDbg................................................................................................................... 317SoftICE ................................................................................................................... 318Visual C++.............................................................................................................. 318Python ..................................................................................................................... 318

Page 6: The Shellcoders Handbook. Edycja polska

Spis treści 9

Narzędzia śledzenia kodu.............................................................................................. 318Własne skrypty........................................................................................................ 318Wszystkie platformy ............................................................................................... 320Unix ........................................................................................................................ 320Windows ................................................................................................................. 321

Artykuły, które powinieneś przeczytać ......................................................................... 322Archiwa artykułów.................................................................................................. 324

Optymalizacja procesu tworzenia kodu powłoki ........................................................... 325Plan eksploitu.......................................................................................................... 325Tworzenie kodu powłoki za pomocą asemblera wbudowanego w kompilator........ 325Biblioteka kodów powłoki ...................................................................................... 327Kontynuacja działania atakowanego procesu.......................................................... 327Zwiększanie stabilności eksploitu ........................................................................... 328Wykorzystanie istniejącego połączenia................................................................... 329

Podsumowanie .............................................................................................................. 330

Rozdział 14.Wstrzykiwanie błędów.................................................................... 331Ogólny projekt systemu................................................................................................. 332

Generowanie danych wejściowych ......................................................................... 332Wstrzykiwanie błędów............................................................................................ 335Moduł modyfikacji.................................................................................................. 335Dostarczanie błędów do aplikacji............................................................................ 339Algorytm Nagla....................................................................................................... 340Zależności czasowe................................................................................................. 340Heurystyki............................................................................................................... 340Protokoły ze stanem i bez........................................................................................ 341

Monitorowanie błędów.................................................................................................. 341Wykorzystanie programu uruchomieniowego......................................................... 341FaultMon................................................................................................................. 342

Kompletna aplikacja testująca ....................................................................................... 342Podsumowanie .............................................................................................................. 343

Rozdział 15. Fuzzing.......................................................................................... 345Ogólna teoria fuzzingu .................................................................................................. 345

Analiza statyczna kontra fuzzing............................................................................. 349Fuzzing jest skalowalny .......................................................................................... 349

Wady fuzzerów ............................................................................................................. 351Modelowanie dowolnych protokołów sieciowych ........................................................ 352Inne technologie fuzzerów ............................................................................................ 352

Migotanie bitów ...................................................................................................... 353Modyfikacja programów open source ..................................................................... 353Fuzzing i analiza dynamiczna ................................................................................. 353

SPIKE............................................................................................................................ 354Jak działa SPIKE?................................................................................................... 354Zalety stosowania struktur programu SPIKE

do modelowania protokołów sieciowych.............................................................. 355Inne fuzzery................................................................................................................... 362Podsumowanie .............................................................................................................. 362

Rozdział 16. Kontrola kodu źródłowego .............................................................. 363Narzędzia....................................................................................................................... 364

Cscope..................................................................................................................... 364Ctags ....................................................................................................................... 365Edytory.................................................................................................................... 365Cbrowser ................................................................................................................. 365

Page 7: The Shellcoders Handbook. Edycja polska

10 The Shellcoder's Handbook. Edycja polska

Zautomatyzowane narzędzia kontroli kodu źródłowego ............................................... 366Metodologia .................................................................................................................. 367

Metoda zstępująca................................................................................................... 367Metoda wstępująca.................................................................................................. 367Metoda selektywna.................................................................................................. 367

Klasy błędów................................................................................................................. 368Ogólne błędy logiki................................................................................................. 368(Prawie) wymarłe klasy błędów .............................................................................. 368Błędy łańcuchów formatujących ............................................................................. 369Ogólne błędy określenia zakresu............................................................................. 370Pętle ........................................................................................................................ 371Przepełnienia jednym bajtem .................................................................................. 372Błędy braku zakończenia łańcucha ......................................................................... 373Błędy przeskoczenia bajtu zerowego ...................................................................... 374Błędy porównania wartości ze znakiem .................................................................. 375Błędy związane z wartościami całkowitymi............................................................ 376Konwersje wartości całkowitych o różnej reprezentacji ......................................... 378Błędy podwójnego zwolnienia ................................................................................ 379Użycie obszarów pamięci poza okresem ich ważności ........................................... 380Użycie niezainicjowanych zmiennych .................................................................... 380Błędy użycia po zwolnieniu .................................................................................... 381Wielowątkowość i kod wielobieżny........................................................................ 382

Słabe punkty i zwykłe błędy.......................................................................................... 382Podsumowanie .............................................................................................................. 383

Rozdział 17. Ręczne wykrywanie błędów............................................................ 385Filozofia ........................................................................................................................ 385Przepełnienie extproc systemu Oracle........................................................................... 386Typowe błędy architektury............................................................................................ 390

Problemy pojawiają się na granicach ...................................................................... 390Problemy pojawiają się podczas przekładu danych................................................. 391Problemy występują w obszarach asymetrii............................................................ 393Problemy uwierzytelniania i autoryzacji ................................................................. 393Problemy występują w najbardziej oczywistych miejscach .................................... 394

Obejście kontroli danych wejściowych i wykrywanie ataku ......................................... 394Filtrowanie niedozwolonych danych....................................................................... 395Zastosowanie alternatywnego kodowania ............................................................... 395Dostęp do plików .................................................................................................... 396Unikanie sygnatur ataków....................................................................................... 398Pokonywanie ograniczeń długości .......................................................................... 398

Atak typu DOS na implementację SNMP w Windows 2000 ........................................ 400Wykrywanie ataków typu DOS..................................................................................... 401SQL-UDP...................................................................................................................... 402Podsumowanie .............................................................................................................. 403

Rozdział 18. Śledzenie słabych punktów ............................................................ 405Wprowadzenie............................................................................................................... 406

Przykładowy program zawierający słaby punkt ...................................................... 406Projekt komponentów ............................................................................................. 409Budujemy VulnTrace .............................................................................................. 416Posługiwanie się biblioteką VulnTrace ................................................................... 421Techniki zaawansowane.......................................................................................... 424

Podsumowanie .............................................................................................................. 425

Page 8: The Shellcoders Handbook. Edycja polska

Spis treści 11

Rozdział 19. Audyt kodu binarnego .................................................................... 427Audyt kodu binarnego i kontrola kodu źródłowego — podobieństwa i różnice............ 427IDA Pro ......................................................................................................................... 428

Krótki kurs obsługi.................................................................................................. 429Symbole uruchomieniowe....................................................................................... 430

Wprowadzenie do audytu kodu binarnego .................................................................... 430Ramki stosu............................................................................................................. 430Konwencje wywołań............................................................................................... 432Kod generowany przez kompilator ......................................................................... 433Konstrukcje typu memcpy ...................................................................................... 436Konstrukcje typu strlen ........................................................................................... 437Konstrukcje języka C++.......................................................................................... 438Wskaźnik this.......................................................................................................... 438

Odtwarzanie definicji klas............................................................................................. 438Tablice funkcji wirtualnych .................................................................................... 439Proste, ale przydatne wskazówki............................................................................. 440

Ręczna analiza kodu binarnego ..................................................................................... 440Szybka weryfikacja wywołań bibliotecznych ......................................................... 440Podejrzane pętle i rozkazy zapisu ........................................................................... 440Błędy logiki............................................................................................................. 441Graficzna analiza kodu binarnego........................................................................... 442Ręczna dekompilacja .............................................................................................. 442

Przykłady analizy kodu binarnego ................................................................................ 443Błędy serwera Microsoft SQL................................................................................. 443Błąd RPC-DCOM wykryty przez grupę LSD ......................................................... 444Błąd IIS WebDAV.................................................................................................. 444

Podsumowanie .............................................................................................................. 446

Część IV Techniki zaawansowane ...............................................447

Rozdział 20. Alternatywne strategie eksploitów ................................................. 449Modyfikacja programu .................................................................................................. 450Modyfikacja 3 bajtów kodu systemu SQL Server ......................................................... 450MySQL i modyfikacja 1 bitu......................................................................................... 454Modyfikacja uwierzytelniania RSA w OpenSSH.......................................................... 456Inne koncepcje modyfikacji działającego kodu............................................................. 457

Modyfikacja generatora losowego w GPG 1.2.2..................................................... 458Serwer progletów .......................................................................................................... 459Proxy wywołań systemowych ....................................................................................... 459Problemy związane z proxy wywołań systemowych..................................................... 461Podsumowanie .............................................................................................................. 470

Rozdział 21. Eksploity działające w rzeczywistym środowisku ............................. 471Czynniki wpływające na niezawodność ........................................................................ 471

Magiczne adresy...................................................................................................... 471Problem wersji ........................................................................................................ 472Problemy kodu powłoki .......................................................................................... 473

Środki zaradcze ............................................................................................................. 475Przygotowanie......................................................................................................... 476Metoda pełnego przeglądu ...................................................................................... 476Lokalny eksploit...................................................................................................... 477Sygnatury systemów i aplikacji............................................................................... 477Wycieki informacji.................................................................................................. 479

Podsumowanie .............................................................................................................. 479

Page 9: The Shellcoders Handbook. Edycja polska

12 The Shellcoder's Handbook. Edycja polska

Rozdział 22. Ataki na systemy baz danych ......................................................... 481Ataki w warstwie sieciowej........................................................................................... 482Ataki w warstwie aplikacji ............................................................................................ 491Wykonywanie poleceń systemu operacyjnego .............................................................. 491

Microsoft SQL Server ............................................................................................. 492Oracle...................................................................................................................... 492IBM DB2 ................................................................................................................ 493

Wykorzystanie przepełnień na poziomie języka SQL ................................................... 495Funkcje języka SQL................................................................................................ 496

Podsumowanie .............................................................................................................. 497

Rozdział 23. Przepełnienia jądra......................................................................... 499Typy słabych punktów jądra ......................................................................................... 499Słabe punkty jądra ......................................................................................................... 507

Przepełnienie stosu przez wywołanie exec_ibcs2_coff_prep_zmagic()w systemie OpenBSD........................................................................................... 507

Słaby punkt ............................................................................................................. 508Funkcja vfs_getvfssw() i możliwość przeglądania modułów jądra w systemie Solaris .. 512

Wywołanie systemowe sysfs() ................................................................................ 514Wywołanie systemowe mount().............................................................................. 514

Podsumowanie .............................................................................................................. 515

Rozdział 24.Wykorzystanie słabych punktów jądra ............................................ 517Słaby punkt funkcji exec_ibcs2_coff_prep_zmagic().................................................... 517

Wyznaczenie przesunięć i adresów pułapek ........................................................... 522Nadpisanie adresu powrotu i przejęcie sterowania.................................................. 523Wyszukiwanie deskryptora procesu (lub struktury proc) ........................................ 524Kod eksploitu wykonywany w trybie jądra............................................................. 526Powrót kodu wykonywanego na poziomie jądra..................................................... 528Uzyskanie uprawnień root (uid=0).......................................................................... 533

Eksploit słabego punktu funkcji vfs_getvfssw() systemu Solaris .................................. 538Eksploit ................................................................................................................... 539Moduł jądra............................................................................................................. 540Uzyskanie uprawnień root (uid=0).......................................................................... 543

Podsumowanie .............................................................................................................. 544

Dodatki .......................................................................................545

Skorowidz ..................................................................................... 547

Page 10: The Shellcoders Handbook. Edycja polska

Rozdział 8.

Przepełnienia

w systemie Windows

Zakładamy, że Czytelnik przystępujący do lektury tego rozdziału posiada przynajmniejpodstawową znajomość systemu Windows NT lub jego późniejszych wersji, a takżezna sposoby wykorzystywania przepełnień buforów na tej platformie. W rozdziale omó-wimy bardziej zaawansowane aspekty przepełnień w systemie Windows, na przykładzwiązane z obchodzeniem zabezpieczeń stosu zastosowanych w systemie Windows2003 Server czy przepełnieniami sterty. Zrozumienie tych zagadnień wymagać będzieznajomości kluczowych rozwiązań zastosowanych na platformie Windows, takich jakbloki TEB (Thread Environment Block) i PEB (Process Environment Block), a takżestruktury pamięci procesów, plików wykonywalnych oraz nagłówków PE. Jeśli któreśz tych pojęć są obce Czytelnikowi, to przed przystąpieniem do lektury tego rozdziałupowinien uzupełnić wiadomości w tym zakresie.

W rozdziale będziemy korzystać z narzędzi wchodzących w skład pakietu Visual Studio 6

firmy Microsoft, w szczególności z programu uruchomieniowego MSDEV, kompilatorajęzyka C wywoływanego z wiersza poleceń (cl) oraz programu dumpbin. Programdumpbin jest doskonałym narzędziem uruchamianym z wiersza poleceń — wyświetlawszelkie informacje o plikach binarnych, tabelach importu i eksportu, sekcjach pli-ków oraz kodzie w asemblerze. Czytelnikom, którzy wolą posługiwać się narzędziemwyposażonym w graficzny interfejs użytkownika, proponujemy doskonały deasemblerfirmy Datarescue o nazwie IDA Pro. Tworząc kod eksploitów na platformie Windows,możemy korzystać ze składni asemblera zgodnej z przyjętą przez firmę Intel bądź za-proponowanej przez AT&T. Wybór zależy od indywidualnych upodobań i preferencji.

Przepełnienia buforów na stosie

Metoda przepełniania buforów znana jest już od wielu lat i z pewnością będzie wykorzy-stywana również w przyszłości. I nadal za każdym razem, gdy jest wykrywana w nowo-czesnym oprogramowaniu, nie wiadomo, czy śmiać się, czy płakać. Tak czy owak, błędy

Page 11: The Shellcoders Handbook. Edycja polska

150 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

te stanowią doskonałą pożywkę dla początkujących hakerów. W sieci Internet dostęp-nych jest wiele dokumentów szczegółowo opisujących sposoby wykorzystywania prze-pełnień buforów. Omówiliśmy je również w pierwszych rozdziałach tej książki, dlate-go teraz nie będziemy już powtarzać tych informacji.

Typowy eksploit bazujący na przepełnieniu stosu doprowadza do nadpisania adresu po-wrotu zapisanego na stosie adresem, który wskazuje rozkaz lub blok kodu przekazujący

sterowanie do kodu umieszczonego w buforze użytkownika. Zanim zajmiemy się po-

głębieniem tego zagadnienia, krótko omówimy procedury obsługi wyjątków bazującychna ramkach stosu. Następnie przyjrzymy się sposobom nadpisywania struktur rejestracji

wyjątków na stosie i pokażemy, w jaki sposób technika taka może prowadzić do obej-

ścia zabezpieczeń stosu wbudowanych w system Windows 2003 Server.

Procedury obsługi wyjątkówdla ramek wywołań funkcji

Procedura obsługi wyjątków jest fragmentem kodu, który zostaje wywołany naskutek pojawienia się problemu podczas wykonania procesu, na przykład naruszenia

uprawnień dostępu bądź wykonania dzielenia przez zero. Procedury obsługi wyjątków

mogą być powiązane z konkretnymi funkcjami. Wywołanie każdej funkcji prowadzi

do utworzenia na stosie odpowiadającej jej ramki wywołania. Informacja o procedurze

obsługi wyjątków może zostać umieszczona w ramce wywołania w strukturze �������������� ����. Struktura taka składa się z dwóch elementów: wskaźnika następnej

struktury �������������� ���� oraz wskaźnika właściwej procedury obsługi wy-

jątków. W ten sposób procedury obsługi wyjątków mogą tworzyć listę przedstawioną

na rysunku 8.1.

Rysunek 8.1.Procedury obsługi

wyjątków dla ramek

wywołań funkcji

Page 12: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 151

Każdy wątek procesu Win32 posiada przynajmniej jedną procedurę obsługi wyjątków.Procedura ta tworzona jest podczas uruchamiania wątku. Adres pierwszej struktury�������������� ���� znajduje się w każdym bloku TEB pod adresem ������. W mo-mencie wystąpienia wyjątków lista procedur obsługi przeglądana jest do momentu zna-lezienia właściwej procedury obsługi wyjątku (czyli takiej, która zajmie się obsługąwyjątku). Obsługa wyjątków w oparciu o ramki na stosie odbywa się na poziomie ję-zyka C za pomocą słów kluczowych ��� i ������. Przypominamy, że większość kodówprzedstawionych w tej książce dostępna jest pod adresem ftp://ftp.helion.pl/przyklady/hell.zip

������������ ��������������� �����

�� ����������� ���������� ������������ �������� ��������������!����"� �����#�!������$!%

���&����������''��&�((� � ��)���)*��+� ����,����������%

%''���������������� �������������������� �������!%������$!%

Jeśli w bloku umieszczonym wewnątrz ��� wystąpi wyjątek, to wywołana zostaniefunkcja ������������ �!"��. W przykładzie tym celowo wywołujemy wyjątek, zeru-jąc zawartość rejestru � �, a następnie wykonując rozkaz � ""#� �.

Podczas przepełniania bufora na stosie i nadpisywania adresu powrotu mogą równieżulec nadpisaniu inne zmienne, co może być przyczyną komplikacji podczas włama-nia. Załóżmy na przykład, że funkcja odwołuje się do pewnej struktury za pomocąrejestru � �, który wskazuje początek tej struktury. Niech zmienna lokalna tej funkcjireprezentuje przesunięcie wewnątrz wspomnianej struktury. Jeśli zmienna ta zostanienadpisana przy okazji nadpisywania adresu powrotu, a następnie załadowana do reje-stru ��� i wykonany będzie na przykład rozkaz

& ��� �����-���.���/,���

to musimy zapewnić, że wartość, którą nadpisaliśmy tą zmienną, w połączeniu z za-wartością rejestru � � reprezentuje adres, pod którym dozwolony jest zapis danych.

Page 13: The Shellcoders Handbook. Edycja polska

152 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

W przeciwnym bowiem razie nastąpi naruszenie ochrony pamięci, wywołane zostanąodpowiednie procedury obsługi wyjątków, a działanie procesu zostanie najprawdopo-dobniej zakończone i stracimy szansę wykonania naszego kodu. Nawet jeśli skory-gujemy odpowiednio adres reprezentowany przez � �#$#���, to musimy liczyć się z wy-stąpieniem wielu innych podobnych problemów, którym należy zaradzić, zanimfunkcja zwróci sterowanie. W niektórych przypadkach może to nawet być niemożliwe.Najprostsza metoda rozwiązania tego problemu polega na nadpisaniu struktury�������������� ���� w taki sposób, aby zapewnić sobie kontrolę nad wskaźni-kiem procedury obsługi wyjątku. Dzięki temu w momencie wystąpienia wyjątku mo-żemy przejąć kontrolę nad procesem — na przykład przez zastąpienie wskaźnika proce-dury obsługi wyjątków adresem kodu, który przekaże sterowanie z powrotem donaszego bufora.

Zastanówmy się teraz, w jaki sposób nadpisać wskaźnik procedury obsługi wyjątku,abyśmy mogli wykonać dowolny kod umieszczony w buforze. Rozwiązanie zależy od

konkretnej wersji systemu i zainstalowanych pakietów serwisowych. W systemachWindows 2000 i Windows XP bez zainstalowanych pakietów serwisowych rejestr �%�

wskazuje bieżącą strukturę �������������� ����, czyli właśnie tą, którą nadpi-

sujemy. Możemy wtedy nadpisać wskaźnik procedury obsługi wyjątków za pomocą

adresu, pod którym znajduje się rozkaz &'�#�(� lub � ""#�(�. W ten sposób na skutek

wystąpienia wyjątków powrócimy zawsze do nadpisanej struktury ������������)

�� ����. Wtedy nadpiszemy wskaźnik następnej struktury �������������� ����adresem kodu, który wykona krótki skok ponad adresem rozkazu &'�# �(�. Sposób

nadpisania struktury �������������� ���� ilustruje rysunek 8.2.

Rysunek 8.2.Nadpisywanie

struktury

EXCEPTION_

REGISTRATION

W systemach Windows 2003 Server oraz Windows XP Service Pack 1 sytuacja wy-gląda jednak inaczej. Rejestr �%� nie wskazuje już struktury �������������� ����.

Wszystkie rejestry, które dotąd wskazywały przydatne informacje, teraz zostają wyze-

rowane przed wywołaniem procedury obsługi wyjątków. Zmiany tej firma Microsoft

dokonała prawdopodobnie w odpowiedzi na sposób działania robaka Code Worm, któryużywał tego mechanizmu do przejęcia kontroli nad serwerami IIS. Poniżej przedsta-

wiamy kod odpowiedzialny za wspomnianą modyfikację (dla systemu Windows XP

Professional SP1).

Page 14: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 153

00102340� ����,���00102342� ��5�,�5�00102343� ����,���00102346� ����,���00102341������ �����-���.7$�/00102389������ �����-���.7$�/00102380������ �����-���.7$�/00102383������ �����-���.7$�/00102381������ �����-���.7$�/00102309����0010230�0010230:� ����00102302� ����0010230;� ��5�00102303���#<�0010230������5�00102301& ��5�,���001023:#������ �����-�5�.$=�/001023:<�������001023:4������ �������>-$/001023:=& ��� �������>-$/,���00102329������ �����-�5�.#<�/00102328������ �����-�5�.#$�/00102322������ �����-�5�.$=�/0010232=������ �����-�5�.:/00102321& ����,�� �����-�5�.#:�/001023;7�������

Począwszy od adresu ��**+*,%-*, rejestry � �, �%�, ��� i �.� są kolejno zerowane zapomocą rozkazu ��. Następnie pod adresem ��**+*,%*/ wykonywany jest rozkaz � "",który powoduje przejście do adresu ��**+*,%*�. Rozkaz znajdujący się pod adresem��**+*,%,+ umieszcza w rejestrze ��� wskaźnik procedury obsługi wyjątku, którąwywołuje następny rozkaz.

Nawet mimo tej modyfikacji haker może przejąć kontrolę nad działaniem systemu. Jed-nak nie dysponując wartościami rejestrów, które wskazywałyby ważne dane procesuużytkownika, musi odnaleźć je na własną rękę. A to zmniejsza szansę powodzenia ataku.

Ale czy rzeczywiście? Zaraz po wywołaniu procedury obsługi wyjątku zawartość stosubędzie wyglądać następująco:

�?"@������ �� ���$�001023;<��?".<@��+�A��+������)*�+��$�=$$$$$$4��?".:@���������+�����B=�"C DE'F�G ?CF;C DE

Zamiast nadpisywać wskaźnik procedury obsługi wyjątków adresem rozkazu &'�#�(�lub � ""#�(�, wystarczy nadpisać go adresem kodu zawierającego następujące rozkazy:

� ���H� ���H���

Wykonanie każdego rozkazu ��� zwiększa wartość rejestru ��� o 4, wobec czego w mo-mencie wykonania rozkazu �� rejestr ��� wskazuje dane procesu użytkownika. Przypo-mnijmy, że rozkaz �� pobiera adres znajdujący się na wierzchołku stosu (wskazywanyprzez ���) i powoduje przekazanie sterowania na ten adres. Dzięki temu haker niepotrzebuje już rejestru wskazującego bufor ani nie musi domyślać się jego położenia.

Page 15: The Shellcoders Handbook. Edycja polska

154 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

Gdzie znajdziemy blok potrzebnych do tego rozkazów? Praktycznie na końcu kodukażdej funkcji. Paradoksalnie najlepszym miejscem okazuje się blok rozkazów w kodzie,który zeruje rejestry przed wywołaniem procedury obsługi wyjątku. Blok ten znajdujesię pod adresem ��**+*,%*,.

00102302� ����0010230;� ��5�00102303���#<�

To, że zamiast rozkazu ��� znajduje się tam rozkaz ���#01, nie ma większego znaczenia.Zwiększy on zawartość rejestru ��� o ��01 zamiast o ��1. Wykonanie tych rozkazówprzeniesie nas z powrotem do struktury �������������� ���� na stosie. Koniecznebędzie też zastąpienie wskaźnika następnej struktury �������������� ���� kodemrozkazu krótkiego skoku oraz dwóch rozkazów ���2#��#��34�"�#� '#�'��56# !���#4�7 )38&5��#("�7#��37 394#���2#���#�#���.

Każdy proces Win32 i każdy wątek takiego procesu posiada przynajmniej jedną pro-cedurę obsługi wyjątków bazującą na ramce na stosie. Procedurę tę otrzymuje w mo-mencie jego uruchamiania. Jeśli stosujemy metodę przepełnień buforów na platformieWindows 2003 Server, to wykorzystanie takich procedur obsługi wyjątków umożliwinam obejście zabezpieczeń stosu zastosowanych na tej platformie.

Wykorzystanie procedur obsługi wyjątkówna platformie Windows 2003 Server

Wykorzystanie procedur obsługi wyjątków umożliwia obejście zabezpieczeń stosuzastosowanych na platformie Windows 2003 Server. (Omówienie tego zagadnieniazawiera punkt „Ochrona stosu i Windows 2003 Server”). W momencie wystąpienia wy-jątku na platformie Windows 2003 Server sprawdzana jest poprawność pierwszej pro-cedury obsługi skonfigurowanej dla tego wyjątku. W ten sposób Microsoft chce za-

bezpieczyć się przed atakami na zasadzie przepełnienia stosu, które powodująnadpisanie adresu procedury obsługi wyjątków.

W jaki sposób sprawdzana jest poprawność procedury obsługi wyjątków? Za kontrolę tęodpowiedzialny jest kod funkcji :�;������������.��� ��<�� znajdującej się w bi-bliotece ��.==>.==. Najpierw sprawdza ona, czy wskaźnik procedury obsługi wyjątku niewskazuje adresu na stosie. W tym celu używane są wartości w bloku TEB określającezakres adresów stosu i znajdujące się pod adresami +���1� i +���?�. Jeśli adres proce-dury obsługi wyjątku wypada w tym zakresie, to nie zostanie ona wywołana. Jeśli adresprocedury obsługi wyjątku nie jest adresem stosu, to następnie adres ten porównywanyjest z listą załadowanych modułów (zarówno wykonywalnych, jak i DLL). Co ciekawe,jeśli adres procedury obsługi wyjątków nie przypada w przestrzeni adresowej żadnegoz tych modułów, to uważany jest za bezpieczny i procedura zostaje wywołana. W prze-ciwnym razie adres procedury obsługi wyjątków porównywany jest jeszcze z listą za-rejestrowanych procedur obsługi wyjątków.

Następnie pobierany jest wskaźnik nagłówka PE za pomocą wywołania funkcji �)"�' @����� !��. Jeśli bajt przesunięty ��-+ względem początku nagłówka (jest to naj-starszy bajt pola charakterystyki DLL w nagłówku PE) jest równy ���1, to moduł ten

Page 16: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 155

jest niedozwolony. Jeśli adres procedury obsługi wyjątku należy do zakresu adresówtego modułu, to procedura nie zostanie wywołana. Wskaźnik nagłówka PE zostajeprzekazany jako parametr funkcji �"�' @�.���������������. � . W tym przypadkuwywołanie tej funkcji dotyczy katalogu Load Configuration Directory i zwraca adresoraz rozmiar tego katalogu. Jeśli moduł nie dysponuje tym katalogiem, to funkcjazwraca wartość 0 i na tym kończy się kontrola poprawności procedury obsługi wyjątków,która zostaje wywołana. Jeśli moduł posiada taki katalog, to sprawdzany jest jegorozmiar. Gdy należy on do zakresu od � do ��1?, to procedura obsługi wyjątku zostajewywołana. W odległości ��1� bajtów od początku katalogu znajduje się wskaźnik tabeliadresów RVA (Relative Virtual Address) zarejestrowanych procedur obsługi wyjątków.Jeśli wskaźnik ten jest równy NULL, to procedura obsługi wyjątku zostaje wywołana.Przesunięta o ��11 bajtów względem początku katalogu jest liczba elementów tabeliadresów RVA. Jeśli równa się ona 0, to procedura obsługi wyjątku zostaje wywołana.Jeśli wszystkie dotychczasowe kontrole powiodły się, adres bazowy modułu zostajeodjęty od adresu procedury obsługi wyjątków i w wyniku tej operacji otrzymujemyadres RVA tej procedury. Adres RVA jest następnie porównywany z adresami RVAw tabeli zarejestrowanych procedur obsługi wyjątków. Jeśli zostanie tam odnaleziony,to procedura zostanie wywołana. W przeciwnym razie procedura zostanie odrzucona.

Stosując przepełnienia buforów na stosie w systemie Windows 2003 Server i nadpi-sując wskaźnik procedury obsługi wyjątków, mamy do wyboru następujące możliwości:

1. Wykorzystać istniejącą procedurę obsługi wyjątku w taki sposób, byprzekazała sterowanie do naszego bufora.

2. Znaleźć blok kodu spoza zakresu adresów danego modułu, który przekażesterowanie do naszego bufora.

3. Znaleźć blok kodu należący do zakresu adresów danego modułu, który nieposiada katalogu Load Configuration Directory.

Przyjrzymy się im na przykładzie wykorzystania przepełnienia bufora przez funkcjęDCOM o nazwie ��'��� ���A ����.

Wykorzystanie istniejącej procedury obsługi wyjątków

Adres ��**+1- /1 wskazuje zarejestrowaną procedurę obsługi wyjątków w ��.==>.==.Jeśli przeanalizujemy działanie tej procedury, to dojdziemy do wniosku, że można jąwykorzystać do wykonania własnego kodu. Wskaźnik naszej struktury �������������� ���� znajduje się pod adresem �%�$��<.

001<4;91& ��5�,�� �����-�5�.$=�/��001<4;8#& ����,�� �����-�5�.$=�/001<4;8#& ����,�� �����-�5�.:/��001<4;04������,-���.���I7/001<4;0:& ����,�� �����-���.���I<.</��001<4;:1�������

Wskaźnik naszej struktury �������������� ���� został umieszczony w rejestrze �%�.Następnie wartość typu !4��! znajdująca się ���� bajtów za adresem umieszczonymw rejestrze �%� zostaje załadowana do rejestru ���. Ponieważ wcześniej przepełniliśmy

Page 17: The Shellcoders Handbook. Edycja polska

156 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

strukturę �������������� ����, to posiadamy kontrolę nad tą wartością, a w konse-kwencji nad zawartością rejestru ���. W podobny sposób kontrolowana przez nas wartośćtypu dword o przesunięciu 0x08 względem adresu znajdującego się w rejestrze �%�zostaje umieszczona w rejestrze �.�. Następnie do rejestru ��� zostaje załadowanyadres efektywny ���#$#���#B#C (czyli ���#B#/). Ponieważ kontrolujemy zawartość reje-stru ���, to również możemy zagwarantować odpowiednią wartość tego adresu. Kolejnyrozkaz umieszcza w rejestrze � � wartość !4��! znajdującą się pod adresem stanowiącymsumę zawartości kontrolowanego przez nas rejestru �.� oraz ���#B#1#$#1. Następniewywołana zostaje procedura znajdująca się pod adresem umieszczonym w rejestrze � �.

Podczas pierwszego włamania do modułu �A�<���#położenie bloku TEB oraz położenie

stosu są łatwe do określenia. Sytuacja może się zmienić w przypadku mocno obciążo-

nego serwera. Zakładając, że jest stabilna, możemy odnaleźć wskaźnik naszej struktury

�������������� ���� pod adresem ��%$� (��*++.%���) i użyć go jako wskaźnika

naszego kodu. Jednak tuż przed wywołaniem procedury obsługi wyjątków wskaźnik

ten zostanie zaktualizowany, wobec czego nie możemy zastosować takiej metody.

Struktura �������������� ���� wskazywana przez ��%$� posiada pod adresem

����-�+/+� wskaźnik do naszej struktury �������������� ����, a ponieważ położenie

stosu jest zawsze znane podczas pierwszego ataku, możemy wykorzystać ten

wskaźnik. Inny wskaźnik naszej struktury �������������� ���� znajduje się również

pod adresem ����-�+/�1. Jeśli chcemy użyć tego adresu, musimy zapisać wartość

��1���0--1 (która zostanie następnie załadowana do rejestru ���) ���� bajtów za naszą

strukturą �������������� ���� oraz wartość ����-%+/+� ���? bajtów za tą strukturą

(wartość ta zostanie następnie załadowana do rejestru �.�). Po odpowiednim wymnoże-

niu i dodaniu otrzymamy właśnie adres ����-�+/�1. Do rejestru � � zostanie następnie

załadowany wskaźnik znajdujący się pod tym adresem i wywołana odpowiednia proce-

dura. Wywołanie to spowoduje, że trafimy do naszej struktury �������������� ����

w miejscu, w którym znajduje się wskaźnik następnej takiej struktury. Jeśli umieści-

my tam kod, który wykona skok o 14 bajtów, to przeskoczymy kod, który był nam

wcześniej potrzebny, by sterowanie dotarło w obecne miejsce.

Rozwiązanie to przetestowaliśmy na czterech maszynach działających pod kontrolą

systemu Windows 2003 Server, z których trzy działały z wersją Enterprise Edition,

a czwarta ze Standard Edition. Wszystkie próby zakończyły się sukcesem. Musimy jed-

nak zawsze mieć pewność, że włamanie tą metodą przeprowadzane jest po raz pierw-

szy. W przeciwnym razie jest wielce prawdopodobne, że zakończy się ono niepowo-

dzeniem. Na marginesie warto również zauważyć, że opisana możliwość wykorzystania

procedury obsługi wyjątków wynika prawdopodobnie z tego, że jest ona przewidziana

do współpracy z wektoryzowanym mechanizmem obsługi wyjątków, a nie używającym

ramek na stosie.

Do włamań możemy wykorzystać również inne moduły, które używają tej samej proce-

dury obsługi wyjątków. Inne procedury obsługi wyjątków zarejestrowane w tej samej

przestrzeni adresowej zwykle przekazują obsługę do funkcji ������< �!"��/ eks-

portowanej przez bibliotekę '�A���>!"" lub jej odpowiednik.

Page 18: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 157

Wykorzystanie bloku kodu o adresie,który nie należy do żadnego modułu

Podobnie jak w innych wersjach systemu Windows pod adresem ���#$#? możemyodnaleźć wskaźnik do naszej struktury �������������� ����. Jeśli potrafimy od-naleźć blok rozkazów

� ���H� ���H���

pod adresem, który nie jest związany z żadnym z załadowanych modułów, to możemyprzejąć sterowanie. Każdy proces działający w systemie Windows 2003 Server zawierapod adresem ��*++�� �- taki blok rozkazów. Ponieważ adres ten nie jest związanyz żadnym modułem, zostanie uznany za bezpieczny, a znajdujący się pod nim kod wyko-nany jako procedura obsługi wyjątków. Istnieje jednak pewien problem. Na innej ma-szynie działającej pod kontrolą systemu Windows 2003 Server Standard Edition tensam blok rozkazów znajduje się w pobliżu podanego adresu, ale nie jest to ten samadres. Skoro nie możemy zagwarantować położenia bloku rozkazów ���, ���, ���, tonie jest to właściwe rozwiązanie. Zamiast tego bloku możemy poszukać rozkazu:

������ �����-���.:/

albo:

)&��� �����-���.:/

w przestrzeni adresowej atakowanego procesu. Chociaż żaden z tych rozkazów nie ist-nieje pod odpowiednim adresem, to jednak wiele wskaźników naszej struktury �����)��������� ���� znajduje się w otoczeniu wskazywanym przez rejestry ��� i �%�.Wskaźnik naszej struktury możemy znaleźć pod jednym z następujących adresów:

���.:���.#<���.#=���.7=���.<<���.4$

�5�.$=�5�.7<�5�.9$�5�J<�5�J=�5�J#:

Każdego z nich możemy użyć dla rozkazu &'� lub � "". Jeśli sprawdzimy przestrzeńadresową �A�<���, to pod adresem ����0%�%�% znajdziemy rozkaz:

������ �����-�5�.$�9$/

Pod adresem �%�#$#/� znajduje się wskaźnik naszej struktury �������������� ����.Adres ten nie jest związany z żadnym modułem, i co więcej, wydaje się, że prawiekażdy proces działający w systemie Windows 2003 Server (jak również wiele pro-cesów w systemie Windows XP) ma te same bajty właśnie pod tym adresem. Proce-sy, które są wyjątkiem od tej reguły, posiadają natomiast te bajty pod adresem ����0��%�%.

Page 19: The Shellcoders Handbook. Edycja polska

158 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

Jeśli nadpiszemy wskaźnik procedury obsługi wyjątków adresem ����0%�%�%, to po-wrócimy do naszego bufora i uzyskamy możliwość wykonania dowolnego kodu. Adres����0%�%�% sprawdziliśmy na wszystkich czterech maszynach z systemem Windows2003 Server i we wszystkich przypadkach zawierał on właściwe bajty reprezentującerozkaz � ""#!4��!#�����(�$��/��. Wydaje się więc, że opisana metoda powinna byćstosunkowo niezawodna na platformie Windows 2003 Server.

Wykorzystanie bloku kodu należącego do modułu,który nie posiada katalogu Load Configuration Directory

Plik wykonywalny �A�<���>��� nie posiada katalogu Load Configuration Directory.Kod z przestrzeni adresowej tego procesu zostałby zaakceptowany jako procedura ob-sługi wyjątku, gdyby nie wyjątek wskaźnika �;== występujący podczas wykonania funkcji:�;������������.��� ��<��DE. Funkcja �"�' @����� !�� zwraca bowiem wartość 0 ja-ko wskaźnik nagłówka PE dla �A�<���. Funkcja :�;������������.��� ��<��DE niesprawdza, czy wykorzystywany przez nią wskaźnik jest różny od �;==.

����F�� &�H�E�����������5������-���.41�/,<)�K$�0018:;70

Na skutek wystąpienia wyjątku działanie procesu zostaje zakończone. Dlatego też nieuda nam się wykorzystać żadnego kodu należącego do �A�<���>!"". Plik ��'����>!""również nie posiada katalogu Load Configuration Directory. Jednak ponieważ polecharakterystyki DLL znajdujące się w nagłówku PE ma wartość ���1��, to test wyko-nywany po wywołaniu funkcji �"�' @����� !�� zakończy się niepowodzeniem i ste-rowanie zostanie przekazane pod adres ��**+F? C* z dala od naszego kodu. Jeśliprzejrzymy wszystkie moduły załadowane w przestrzeni adresowej procesu, to okażesię, że żaden z nich nie spełnia naszych wymagań. Większość posiada katalog LoadConfiguration Directory i zarejestrowane procedury obsługi wyjątków. Natomiast po-zostałe moduły, które nie mają tego katalogu, nie są odpowiednie z tego samego po-wodu co ��'�����>!"". W tym przypadku metoda ta nie jest więc przydatna.

Ponieważ w większości przypadków możemy spowodować wyjątek, próbując wyko-nać operację zapisu za końcem stosu, to przepełniając bufor, możemy użyć takiegosposobu jako ogólnej metody obejścia ochrony stosu w systemie Windows 2003 Se-rver. Należy jednak pamiętać, że metoda ta jest skuteczna w chwili obecnej. Nie mawątpliwości, że kolejne wersje systemu lub nawet pakiety serwisowe usuną ten słabypunkt i sprawią, że metoda przestanie być skuteczna. Wtedy pozostanie nam odkurzyćprogram uruchomieniowy i asembler i zabrać się za projektowanie nowej metody.Firmie Microsoft możemy natomiast polecić wykonywanie wyłącznie zarejestrowa-nych procedur obsługi wyjątków i dołożenie starań, by nie mogły one zostać użyteprzez hakerów w taki sposób, jaki przedstawiliśmy w tym podrozdziale.

Końcowe uwagina temat nadpisań procedur obsługi wyjątków

Gdy słaby punkt występuje w wielu systemach operacyjnych — tak jak ma to miejscew przypadku przepełnienia bufora DCOM ��'��� ���A ���� odkrytego przez polskągrupę badawczą The Last Stage of Delirium — to najlepszym sposobem poprawy

Page 20: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 159

przenośności eksploitu jest zaatakowanie procedur obsługi wyjątków. Przesunięciepoczątku bufora względem położenia struktury �������������� ���� może bowiembyć różne dla poszczególnych systemów. I tak w przypadku wspomnianego słabegopunktu DCOM struktura ta znajduje się 1412 bajtów od początku bufora w systemieWindows 2003 Server, 1472 bajty w systemie Windows XP i 1540 bajtów w systemieWindows 2000. Mimo tych różnic możliwe jest napisanie pojedynczego eksploitu dlawszystkich tych systemów. Wystarczy jedynie umieścić w odpowiednich miejscachpseudoprocedury obsługi wyjątków.

Ochrona stosu i Windows 2003 Server

System Windows 2003 Server posiada wbudowaną ochronę stosu. Zastosowanie tegosamego mechanizmu umożliwia Microsoft Visual C++ .NET. Opcja kompilatora G��

(która jest domyślnie włączona) sprawia, że podczas generowania kodu na stosie

umieszczane są znaczniki bezpieczeństwa, których zadaniem jest ochrona adresu powrotu

przed nadpisaniem. Znaczniki te stanowią odpowiednik rozwiązania zastosowanego

przez Crispina Cowana w kompilatorze StackGuard. Po wywołaniu procedury na sto-

sie umieszczane są 4 bajty (!4��!), które są sprawdzane, zanim procedura zwrócisterowanie. W ten sposób chroniony jest adres powrotu oraz zawartość rejestru �%� za-

pisana na stosie. Logika działania tego mechanizmu jest prosta: jeśli lokalny bufor został

przepełniony i spowodował nadpisanie adresu powrotu, to po drodze musiał również nad-

pisać znacznik bezpieczeństwa. W ten sposób proces może rozpoznać sytuację,

w której nastąpiło przepełnienie bufora i podjąć działania zapobiegające wykonaniuniewłaściwego kodu. Zwykle działania te sprowadzają się do zakończenie pracy procesu.

Chociaż może wydawać się, że rozwiązanie takie zapewnia skuteczną ochronę przed

atakami wykorzystującymi przepełnienie, to jednak na przykładzie wykorzystania

procedur obsługi wyjątków pokazaliśmy już, że tak nie jest. Ochrona za pomocą

znaczników bezpieczeństwa utrudnia takie włamania, ale nie eliminuje ich.

Przyjrzyjmy się bliżej sposobowi działania mechanizmu ochrony stosu i spróbujmyznaleźć jeszcze inne metody jego obejścia. Znaczniki bezpieczeństwa generowane są

w wystarczająco losowy sposób, aby próbować odgadnąć ich wartość. Przedstawionyponiżej kod w języku C naśladuje mechanizm generowania znaczników w momencie

uruchamiania procesu.

������������ ��������������� �����

���&������1 L�C ����!����H������= +��@$!����H�������&�@$!����H������I���@$!L;FG�' EC�G�F����� ���!

G��?����&C�&�;�1���C�&��M���!= +��@�������H�6���C�&�N�����L �6���C�&�!= +��@= +��NG��=������"� ���� ���!

Page 21: The Shellcoders Handbook. Edycja polska

160 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

= +��@= +��NG��=������C����� ���!= +��@= +��NG��C��+= �����!O����"��� �&����= ������M����� ����!���@�����H�������M����� ���!�&�@I����.#�NI���!= +��@= +��N�&�!��������= +��>P�:BQ��,= +���!������$!%

Najpierw wywołana zostaje funkcja ��������'��'� �+�"���'�. Wypełnia ona dwaelementy struktury +�=����� — !4��@<. ����'� i !4=�4. ����'�. Te dwie wartości są

następnie poddawane operacji różnicy symetrycznej. Otrzymany wynik poddawany

jest tej samej operacji, której drugim argumentem są kolejno: identyfikator procesu,

identyfikator wątku oraz liczba milisekund, które upłynęły od momentu startu systemu(wartość tę zwraca funkcja ������7��8��DE). Na końcu wywoływana jest funkcja H8���

������' �����8����, której parametrem jest wskaźnik wartości 64-bitowej. Wartość ta

jest następnie dzielona na dwie wartości 32-bitowe, na których wykonywana jest

operacja ��. Uzyskany wynik jest jeszcze raz poddawany operacji �� ze znacznikiem

bezpieczeństwa. Uzyskana wartość znacznika bezpieczeństwa umieszczana jest w pliku

w sekcji >! � .

Zastosowanie opcji G�� powoduje również zmianę układu zmiennych lokalnych podczasgenerowania kodu przez kompilator. Porządek zmiennych lokalnych pozostaje w zgodziez kolejnością ich definicji w programie w języku C, ale wszystkie tablice zostają przesu-

nięte na koniec listy zmiennych lokalnych i w efekcie znajdą się w pobliżu adresu powrotu

na stosie. W ten sposób zapobiega się nadpisaniu zmiennych lokalnych na skutek prze-

pełnienia. Zadaniem tego rozwiązania jest przede wszystkim ochrona zmiennych lo-

gicznych decydujących o przepływie sterowania oraz wskaźników funkcji.

Aby zilustrować pierwszą z wymienionych korzyści, wyobraźmy sobie program, któ-ry uwierzytelnia użytkowników, a procedura uwierzytelniania podatna jest na atak naskutek przepełnienia. Jeśli uwierzytelni ona użytkownika, to nadaje zmiennej typu

dword wartość 1, a w przeciwnym razie 0. Jeśli zmienna taka znajdowałaby się za bu-

forem, to haker mógłby go przepełnić i nadać w ten sposób zmiennej wartość 1, mimo

że nie uwierzytelnił się za pomocą nazwy i odpowiedniego hasła.

Gdy funkcja chroniona za pomocą znaczników bezpieczeństwa zwraca sterowanie, tosprawdza, czy znacznik bezpieczeństwa jest taki sam jak w momencie jej wywołania.

Kopia znacznika zapamiętywana jest w sekcji >! � #pliku zawierającego daną funkcję.

I to jest pierwszy poważny problem takiego rozwiązania — wyjaśnimy to za chwilę.

Jeśli wartość znacznika bezpieczeństwa się nie zgadza, to wywołana zostaje procedu-ra bezpieczeństwa (jeśli została zdefiniowana). Wskaźnik tej procedury przechowy-wany jest również w sekcji >! � . Jeśli wskaźnik ten jest różny od �;==, to zostaje zała-

dowany do rejestru � � i wykonywany jest rozkaz � ""#� �. Stanowi on drugą słabość

tego rozwiązania. Jeśli nie została zdefiniowana procedura bezpieczeństwa, to wy-

woływana jest funkcja ;�< �!"�!���������+�"���. Funkcja ta nie powoduje zakoń-

czenia procesu, lecz wykonuje szereg operacji i wywołuje wiele różnych funkcji.

Page 22: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 161

Czytelnikowi zalecamy przeanalizowanie działania funkcji ;�< �!"�!���������+�"���za pomocą IDA Pro. W skrócie działanie tej funkcji polega na załadowaniu biblioteki

� 8"����>!"", a następnie wykonaniu funkcji �����+ 8"� eksportowanej przez tę bi-

bliotekę. Funkcja ta odpowiedzialna jest między innymi za wyświetlenie okna dialo-

gowego, które umożliwia poinformowanie firmy Microsoft o zaistniałym błędzie.

Funkcja �����+ 8"� wykorzystuje potoki ���� �@���������� i ���+ 8"�����������.

Zajmijmy się teraz wspomnianymi problemami omawianego rozwiązania. Najlepiejbędzie zilustrować je przykładowym kodem.

������������ ��������������� �����

�;E6L���@ERLL!���F������ ��1� &R�������II,����I�!

���&����������I���@ERLL!��@����=������$,$�#$$$,$�#$$$$�!F������ ��J1� &R���M���,�����>((�����H�� �������� &(��������&���!��������� ����P��,����!����1������,$,����!������$!

%

���F������ ��1� &R�������II5��,����I��������� ���@$!����I�@ERLL!����5�����-<$/@��!

((��+�A��+� �K*�+�������RFL�@����������,�����>((��!���S��������$!�@�.0!((��K�����K�� +���*+ ��T�������5�����,��!((JJJJJJRU;G;#((���K�+�)�������K��+ V��+������5�����-� ���/S@W(W�� ���..!((�K���T��)�H 5�)��&K�� ��&5�����-� ���/@$!((C���K�5�� �K�K��)��)���T��K��� ���((C� �K�&�)�)+ ��T����������@�����I�����;�� ����,$,�������5������.#�!���S��������$!��������,5������!I5��@�!((JJJJJJJJJJJJJJRU;G;7������$!%

Page 23: The Shellcoders Handbook. Edycja polska

162 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

Program ten wyodrębnia nazwę hosta z adresu URL. Funkcja ��8������+��';�"narażona jest na przepełnienie bufora na stosie w miejscu oznaczonym komentarzem;I � #0. Pozostawmy na chwilę omówienie tego problemu i przyjrzyjmy się prototy-powi tej funkcji. Posiada ona dwa parametry — pierwszy jest wskaźnikiem wskaźni-ka D�< �#BBE, a drugi wskaźnikiem adresu URL. Komentarzem ;I � #C opatrzyliśmyinstrukcję, która pierwszemu parametrowi nadaje wartość wskazującą nazwę hostaumieszczoną na stercie. Przyjrzyjmy się reprezentacji tej instrukcji na poziomie roz-kazów asemblera.

$$<$##3=& ����,�� �����-�5�.:/$$<$##31& ����,�� �����-�5�J:/$$<$##=7& ��� �����-���/,���

Pierwszy z rozkazów umieszcza adres wskaźnika przekazanego jako parametr w reje-strze ���. Następnie do rejestru �.� zostaje załadowany wskaźnik nazwy hosta znaj-dującej się na stercie. Ostatni z rozkazów umieszcza ten wskaźnik pod adresem wska-zywanym przez rejestr ���. I tutaj pojawia się jeden ze wspomnianych problemów.Jeśli przepełnimy bufor na stosie, nadpiszemy znacznik bezpieczeństwa oraz adrespowrotu, to kolejnymi nadpisywanymi wartościami będą parametry funkcji. Ilustrujeto rysunek 8.3.

Rysunek 8.3.Stos przed

i po przepełnieniu

bufora

Na skutek przepełnienia bufora haker może więc uzyskać kontrolę nad parametramiprzekazanymi funkcji. Z tego powodu wykonanie rozkazów znajdujących się w pamięcipocząwszy od adresu ����1�00%� (należących do rozwinięcia instrukcji B(8�# J# �),może zostać użyte do nadpisania dowolnej wartości w pamięci bądź może spowodowaćnaruszenie ochrony pamięci. Druga z tych możliwości wystąpi na przykład w sytuacji,gdy nadpiszemy parametr znajdujący się pod adresem �%�#$#? wartością ��10101010.Następnie proces spróbuje zapisać wskaźnik pod adresem reprezentowanym przez tęwartość, co spowoduje naruszenie ochrony pamięci. Jednocześnie sytuacja taka pozwolinam wykorzystać mechanizm struktur opisujących procedury obsługi wyjątków doobejścia mechanizmu zabezpieczeń stosu. A co w przypadku, gdy nie chcemy spowo-dować wyjątku? Ponieważ obecnie zastanawiamy się nad innymi sposobami obejściazabezpieczeń stosu, to przyjrzyjmy się dokładnie pierwszej z wymienionych możli-wości (zapisowi dowolnej wartości w pamięci).

Wróćmy zatem do problemów wskazanych w procesie sprawdzania wartości znaczni-ka bezpieczeństwa. Pierwszy z nich pojawia się na skutek przechowania oryginalnejwartości znacznika w sekcji >! � . Dla określonej wersji pliku znacznik ten znajduje

Page 24: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 163

się zawsze w tym samym miejscu (może to być prawdą nawet dla różnych wersji pli-ku). Jeśli adres wskaźnika nazwy naszego hosta na stosie jest zawsze taki sam, mo-żemy nadpisać nim oryginalną wartość znacznika znajdującą się w sekcji >! � , a na-stępnie wartość znacznika umieszczoną na stosie. W ten sposób obie wartości będątakie same w momencie ich kontroli. Po pomyślnym wyniku kontroli znacznikówprzejmiemy kontrolę nad działaniem programu i przekażemy sterowanie do wybrane-go przez nas adresu — tak jak w klasycznym przepełnieniu bufora na stosie.

Jednak metoda ta nie jest wcale najlepszym rozwiązaniem w naszym przypadku. Kodeksploitu możemy umieścić w buforze i nadpisać adres pewnej funkcji adresem tego

bufora. Gdy funkcja ta zostanie wywołana, to zostanie wykonany nasz kod znajdujący

się w buforze. Jednak kontrola znaczników bezpieczeństwa da wynik negatywny. I w ten

sposób dochodzimy do drugiego ze wspomnianych problemów. Przypomnijmy jednak,że gdy kontrola znaczników bezpieczeństwa nie powiedzie się i zdefiniowana została

procedura bezpieczeństwa, to procedura ta zostanie wywołana. Stanowi to dla nas do-

skonałą okazję, ponieważ możemy nadpisać wskaźnik procedury bezpieczeństwa

(który umieszczony jest w sekcji >! � ) wskaźnikiem naszego bufora. W ten sposób

przejmiemy sterowanie w momencie, gdy kontrola znaczników da wynik negatywny.

Przyjrzyjmy się zatem innemu sposobowi. Przypomnijmy, że jeśli kontrola znacznikówwypadnie negatywnie i nie jest zdefiniowana żadna procedura bezpieczeństwa, towywołana zostanie funkcja ;�< �!"�!���������+�"��� (przy założeniu, że również

wskaźnik właściwej procedury obsługi wyjątków posiada wartość �;==). Funkcja ta

wykonuje tak wiele kodu, że stanowi dla hakera doskonałe pole do popisu. Na przykład

funkcja ta wywołuje funkcję ��������'.��������I, a następnie z uzyskanego katalogu

systemowego ładuje bibliotekę � 8"����>!"". W przypadku przepełnienia posługującego

się kodem Unicode moglibyśmy nadpisać wskaźnik katalogu systemowego przecho-wywany w sekcji >! � modułu 7����"/C>!"" za pomocą wskaźnika naszego własnego

katalogu i w rezultacie spowodować załadowanie własnej wersji biblioteki � 8"����>!""

zamiast wersji systemowej. Wystarczy, że wersja ta będzie eksportować funkcję �)

����+ 8"�, która zostanie automatycznie wywołana.

Kolejną interesującą możliwość (na razie tylko teoretyczną, ponieważ nie mieliśmyjeszcze czasu jej sprawdzić) stanowi koncepcja wtórnego, zagnieżdżonego przepełnienia.

Większość funkcji wywoływanych przez ;�< �!"�!���������+�"��� nie jest chronionaznacznikami. Załóżmy na przykład, że funkcja ��������'.��������I jest narażona na

przepełnienie, ponieważ zakłada, że długość łańcucha katalogowego nie przekracza nigdy

260 bajtów i pochodzi on zawsze z zaufanego źródła. Jeśli nadpiszemy wskaźnik ka-

talogu systemowego wskaźnikiem naszego bufora, to możemy spowodować kolejne

przepełnienie i w momencie powrotu funkcji uzyskać sterowanie. W praktyce okazuje

się, że funkcja ��������'.��������I jest odporna na tego rodzaju atak. Jednak takisłaby punkt może kryć się w innych fragmentach kodu wykonywanego przez ;�< �)

!"�!���������+�"���. Pozostaje tylko go odnaleźć.

W naturalny sposób nasuwa się pytanie, czy scenariusz, w którym uzyskujemy moż-liwość modyfikacji dowolnego miejsca w pamięci, zanim dokonana zostanie kontrolaznaczników, może zdarzyć się w praktyce. Odpowiedź na to pytanie jest pozytyw-na, a sytuacja taka występuje dość często. Przykładem może być słaby punkt DCOMwykryty przez grupę The Last Stage of Delirium. W tym przypadku parametr jednej

Page 25: The Shellcoders Handbook. Edycja polska

164 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

z funkcji posiada typ 4�< �#BB. Umożliwia on nadpisanie dowolnego miejsca w pa-mięci tuż przed powrotem tej funkcji. Jedyny problem z wykorzystaniem tej technikipolega na konieczności wywołania przepełnienia za pomocą danych wejściowych, któremuszą być ścieżką UNC zakodowaną w Unicode i rozpoczynającą się od dwóch znakówodwrotnego ukośnika. Przy założeniu, że nadpisujemy wskaźnik procedury bezpieczeństwawskaźnikiem naszego bufora, pierwszymi rozkazami po jego wywołaniu powinny być:

� ����

���5������-���.���.�/,5�

gdzie n jest następnym bajtem w buforze. Ponieważ zapis pod adresem � �$� �$� niejest nigdy możliwy, to nastąpi naruszenie ochrony pamięci i utracimy nasz proces. Zewzględu na dwa znaki odwrotnego ukośnika znajdujące się na początku bufora wyko-

rzystanie tej metody nie jest więc możliwe. Gdyby nie te znaki, to wystarczyłoby na-stępnie zastosować jedną z omówionych wcześniej technik.

Pokazaliśmy, że istnieje wiele sposobów obejścia mechanizmu ochrony stosu za po-mocą znaczników bezpieczeństwa. Można wykorzystać w tym celu struktury związa-ne z obsługą wyjątków bądź parametry przekazywane funkcjom przez stos. Z pewno-ścią jednak kolejne wersje systemów firmy Microsoft posiadać będą udoskonalonemechanizmy bezpieczeństwa, które utrudnią wykorzystanie przepełnień stosu.

Przepełnienia sterty

Przepełnienia stery są co najmniej tak samo groźne jak przepełnienia stosu. Zanimprzejdziemy do ich omówienia, przypomnijmy definicję sterty. Sterta jest obszarempamięci używanym przez programy do przechowywania dynamicznie tworzonychdanych. Weźmy na przykład pod uwagę serwer Web. W momencie kompilacji jego kodunie jest znana liczba i rodzaj żądań, które będzie on musiał obsłużyć. Niektóre z nichbędą zawierać jedynie 20 bajtów, a inne 20 000 bajtów. Serwer musi poradzić sobie w obusytuacjach. Zamiast używać w tym celu bufora o stałym rozmiarze przydzielonego nastosie, może zażądać przydzielenia obszaru pamięci na stercie o rozmiarze odpowiednimdla obsługiwanego żądania. Zastosowanie stosu usprawnia zarządzanie pamięcią,umożliwiając tworzenie aplikacji, które lepiej się skalują.

Sterta procesu

Każdy proces Win32 posiada domyślną stertę określaną mianem sterty procesu. Wy-wołanie funkcji ������������ �DE zwraca uchwyt sterty procesu. Wskaźnik sterty procesuprzechowywany jest również w bloku PEB (Process Environment Block). Poniższyfragment kodu w języku asemblera zwraca wskaźnik sterty procesu w rejestrze EAX.

& ����,�� �������>-$�9$/

& ����,�� �����-���.$�#:/

Wiele funkcji Win32 używa właśnie sterty procesu.

Page 26: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 165

Sterty dynamiczne

Oprócz domyślnej sterty proces może posiadać również dowolną liczbę stert tworzo-

nych dynamicznie. Sterty dynamiczne są dostępne globalnie w obrębie danego proce-

su i tworzone przez wywołanie funkcji �� ���� ��DE.

Korzystanie ze sterty

Zanim proces może umieścić dane na stercie, musi przydzielić im pewien obszar

sterty. W tym celu wywołuje funkcję �� � ""�� ����DE, podając rozmiar żądanego ob-

szaru. Jeśli przydział zakończy się pomyślnie, funkcja zwróci wskaźnik przydzielonego

obszaru. Menedżer sterty zarządza przydziałem obszarów, wykorzystując w tym celu

odpowiednie struktur. Struktury te zawierają informacje o rozmiarze przydzielonego blo-

ku oraz wskaźniki do poprzedniego oraz następnego obszaru.

Zwykle aplikacja używa funkcji �� � ""�� ����DE, ale istnieje również wiele innych

funkcji operujących na stercie, głównie ze względu na konieczność zachowania zgod-

ności ze wcześniejszymi wersjami systemu Windows. W systemach Win16 istniały dwa

rodzaje stert: globalna sterta dostępna dla wszystkich procesów oraz lokalna sterta

każdego procesu. Win32 nadal posiada funkcje �"�( " ""��DE i =�� "# ""��DE. Jednak

w przypadku Win32 obie wymienione funkcje przydzielają obszary pamięci na do-

myślnej stercie procesu. W rzeczywistości obie funkcje delegują to zadanie do funkcji

�� � ""�� ��DE w następujący sposób:

�@����;�� �����G��"� ����������,$,��K��!

Gdy przydzielony obszar nie jest już dłużej potrzebny, proces może zwolnić go, wy-

wołując jedną z funkcji �� �+���DE, =�� "+���DE bądź �"�( "+���DE.

Więcej informacji na temat korzystania ze sterty można znaleźć w dokumentacji MSDN

na stronie http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/

memory_management_reference.asp

Jak działa sterta

Podczas gdy stos wzrasta w kierunku adresu ����������, to sterta rozbudowywana

jest w kierunku przeciwnym. Jeśli funkcja �� � ""�� �� zostanie wywołana dwukrotnie,

to za pierwszym razem zostanie przydzielony obszar o niższym adresie wirtualnym

niż podczas drugiego wywołania. W ten sposób przepełnienie pierwszego bufora mo-

że spowodować nadpisanie informacji w drugim buforze, a nie na odwrót.

Każda sterta, domyślna lub dynamiczna, rozpoczyna się od struktury, w której oprócz

innych danych znajduje się tablica +���=��� zawierająca 128 struktur =������K słu-

żących do zarządzania wolnymi blokami pamięci. Każda struktura =������K (zdefi-

niowana w I����><) zawiera dwa wskaźniki, a tablica +���=���� przesunięta jest

o ��0*? bajtów względem początku sterty. Po utworzeniu sterty struktura +���=�������

zawiera dwa wskaźniki pierwszego wolnego obszaru, który może zostać przydzielony.

Page 27: The Shellcoders Handbook. Edycja polska

166 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

Pod adresem wskazywanym przez te wskaźniki znajdują się natomiast dwa wskaźniki

struktury +���=�������. Zakładając, że adres bazowy sterty wynosi ����/-����, a pierwszy

wolny blok ma adres ����/-�F??, to:

� Pod adresem ����/-�0*?#(+���=������>+"��7) znajduje się wskaźnik

posiadający wartość ����/-�F?? (adres pierwszego wolnego bloku).

� Pod adresem ����/-�0*� (+���=������>%"��7) znajduje się wskaźnik

posiadający wartość ����/-�F?? (adres pierwszego wolnego bloku).

� Pod adresem ����/-�F?? (pierwszy wolny blok) znajduje się wskaźnik

posiadający wartość ����/-�0*? (adres struktury +���=������).

� Pod adresem ����/-�F?� (pierwszy wolny blok + 4) znajduje się wskaźnik

posiadający wartość ����/-�0*? (adres struktury +���=������).

W przypadku przydziału bloku pamięci (na przykład na skutek wywołania funkcji

�" ""�� ���� � żądającego obszaru 260 bajtów) wskaźniki +���=������>+"��7

i +���=������>%"��7 zostaną zaktualizowane w taki sposób, by wskazywały następny

wolny blok, który może zostać przydzielony. Co więcej, dwa wskaźniki wskazujące

tablicę +���=��� zostaną przeniesione na koniec przydzielonego bloku. Każdy nowy

przydział lub zwolnienie bloku pamięci spowoduje aktualizację tych wskaźników.

W ten sposób przydzielone bloki utworzą dwukierunkową listę powiązaną za pomocą

wskaźników. Gdy przepełnienie bufora umieszczonego w jednym z bloków spowoduje

nadpisanie wskaźników innego bloku, to mogą one zostać użyte do nadpisania dowolnego

podwójnego słowa (!4��!) w pamięci. Może nim być na przykład wskaźnik funkcji,

co pozwoli hakerowi przejąć kontrolę nad działaniem programu. Jeśli jednak przed wy-

wołaniem tej funkcji wystąpi wyjątek, to hakerowi nie uda się przejąć sterowania.

Dlatego lepszym rozwiązaniem jest nadpisanie wskaźnika procedury obsługi wyjątków.

Zanim przejdziemy do omówienia sposobów wykorzystania przepełnień sterty do

włamań, przyjrzyjmy się związanym z tym problemom.

Poniższy program narażony jest na atak przez przepełnienie sterty.

������������ ��������������� �����

6UDF6��������� ���������� ���!���� �����I5���!

���&���������H�,����I��H�-/����D6RL��!�@L ��L�5������&�����������!�@L ��L�5������������97������!��������Q�Q����� ����� ��� H��&�Q���!�����H�S@7���������������;FG?S��!� ���H�-#/�!������$!%

Page 28: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 167

6UDF6��������� ���������� ������������ �������� ��������������!����"� �����#�!������$!%

���� �����I5�����LD=;L�#@$,�7@$!�;E6L���!

''������@����=������$,$�#$$$,$�#$$$$�!���S�����������������1������ �����������Q���!

�#@����;�� ����,��;"'X�FD'���DFY,78$�!

����������;">P�:BP�:BQ��,�#,M�#�!

((����)��K���Z������������>��������#,5���!

((6��H����� Z��������;�� �������T��)�)�[((� ��K�)T������� ������7@����;�� ����,��;"'X�FD'���DFY,78$�!������������ ��!%''���������������� �������������������� �������!%������$!%

Program najlepiej skompilować za pomocą Microsoft Visual C++ 6.0, używając po-

lecenia �"#G��#<� �>�.

Słabym punktem tego programu jest wywołanie funkcji ������DE przez funkcję ���DE.Jeśli łańcuch (8� jest dłuższy niż 260 znaków, to nadpisze on strukturę sterty. Struktura

ta posiada dwa wskaźniki, wskazujące element tablicy +���=���, który zawiera kolejną

parę wskaźników do pierwszego wolnego bloku. Gdy blok pamięci jest przydzielany

lub zwalniany, to wskaźniki te zamieniane są miejscami.

Jeśli programowi temu przekażemy argument o długości na przykład 300 bajtów (któryz kolei zostanie przekazany funkcji ���DE, wewnątrz której zachodzi przepełnienie), to

kod naruszy ochronę pamięci, wykonując następujące rozkazy podczas drugiego wy-wołania funkcji �� � ""��DE:

00187481:2$#& ��� �����-���/,���0018740#:2<:$<& ��� �����-���.</,���

Page 29: The Shellcoders Handbook. Edycja polska

168 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

Chociaż rezultat ten uzyskaliśmy wywołując po raz drugi funkcję �� � ""��DE, towywołanie funkcji �� �+���DE lub �� �� ""��DE spowodowałoby ten sam efekt.Jeśli przyjrzymy się zawartości rejestrów ��� i � �, zobaczymy, że zawierają one danełańcucha, który przekazaliśmy jako parametr programu. Ponieważ nadpisaliśmy wskaź-niki znajdujące się w strukturze używanej do zarządzania stertą, a podczas kolejnegowywołania funkcji �� � ""��DE zostaną one użyte dla aktualizacji sterty, to w rezultacieuzyskamy kontrolę nad zawartością obu rejestrów. Przyjrzyjmy się poszczególnymrozkazom:

& ��� �����-���/,���

Wykonanie tego rozkazu spowoduje umieszczenie zawartości rejestru � � pod adre-sem wskazywanym przez rejestr ���. W ten sposób możemy nadpisać 32 bity znajdują-ce się w dowolnym miejscu wirtualnej przestrzeni adresowej procesu (pod warunkiem,że konfiguracja pamięci dopuszcza operację zapisu) za pomocą dowolnie wybranejprzez nas wartości 32-bitowej. Możemy wykorzystać to do nadpisania danych steru-jących działaniem programu. Jest jednak pewien problem. Przyjrzyjmy się drugiemuz rozkazów:

& ��� �����-���.</,���

Nastąpiła teraz zamiana rejestrów miejscami. Zawartość rejestru � � (której użyliśmyw poprzednim rozkazie do nadpisania wartości wskazywanej przez zawartość rejestru ���)musi równocześnie reprezentować prawidłowy adres w pamięci umożliwiającej operacjęzapisu, ponieważ drugi z rozkazów umieszcza zawartość rejestru ��� pod adresem � �$1.W przeciwnym razie nastąpi naruszenie ochrony pamięci. Jak się okazuje, sytuacjataka wcale nie działa na naszą niekorzyść, a nawet stanowi jeden z powszechniej sto-sowanych sposobów wykorzystania przepełnienia sterty. Hakerzy często nadpisująwskaźnik procedury obsługi wyjątków umieszczony w strukturze �������������� ����znajdującej się na stosie lub wskaźnik procedury Unhandled Exception Filter wartościąwskazującą blok kodu, który w momencie wystąpienia wyjątku przekaże sterowaniedo ich własnego kodu. Nawet jeśli rejestr � � wskazuje adres, pod którym możliwyjest zapis, to i tak zawartość tego rejestru jest inna niż rejestru ���, wobec czego ist-nieje znaczne prawdopodobieństwo, że funkcje niskiego poziomu zarządzające stertąi tak spowodują wyjątek. Dlatego też najłatwiejszą metodą wykorzystania przepełnie-nia stery jest nadpisanie wskaźnika procedury obsługi wyjątków.

Wykorzystanie przepełnień sterty

Wielu programistów uważa, że w przeciwieństwie do przepełnień stosu, przepełnieniasterty nie stanowią większego zagrożenia i w związku z tym dość lekkomyślnie uży-wają potencjalnie niebezpiecznych funkcji takich jak ������DE lub ���� �DE dla bufo-rów przydzielonych na stercie. Z poprzednich punktów tego rozdziału wiemy już, żenajlepszym sposobem wykorzystania przepełnień sterty w celu uruchomienia własne-go kodu jest użycie procedur obsługi wyjątków. Nadpisanie wskaźnika procedury ob-sługi wyjątków stanowi powszechnie używaną metodę. Podobnie nadpisanie wskaź-nika Unhandled Exception Filter. Zamiast zagłębiać się teraz w szczegóły obu metod(zostaną one omówione pod koniec tego punktu), przejdziemy do omówienia dwóchzupełnie nowych technik.

Page 30: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 169

Nadpisanie wskaźnika funkcjiRtlEnterCriticalSection w bloku PEB

Wcześniej omówiliśmy już strukturę bloku PEB. W tym miejscu warto przypomniećkilka najistotniejszych faktów. Zawiera ona wskaźniki szeregu funkcji, między innymi�"����������� "�������DE i �"=� A������� "�������DE. Wskaźników tych używająfunkcje �" �L8�����(=��7DEoraz �"�"� ����(=��7DE eksportowane przez ��.==>.==.Funkcje te wywoływane są przez funkcję �����������DE. Dzięki temu możemy wy-korzystać bloki PEB do wykonania dowolnego kodu, zwłaszcza podczas kończenia pra-cy procesu. Procedury obsługi wyjątków często wywołują funkcję �����������DE i należyto wykorzystać. Posiadając możliwość nadpisania dowolnej wartości dword w pamięci,możemy zmodyfikować jeden ze wspomnianych wskaźników w bloku PEB. Szczególnązaletą tej metody jest stałe położenie bloku PEB niezależnie od wersji systemu Win-dows NT i zainstalowanych pakietów serwisowych czy poprawek. Oznacza to, że in-teresujące nas wskaźniki znajdują się zawsze w tym samym miejscu.

Wskaźniki te nie są używane na platformie Windows 2003 Server (patrz omówie-nie pod koniec tego podrozdziału).

Wskaźnik funkcji �"����������� "�������DE znajduje się zawsze pod adresem��*++.+�C�. Korzystając z przepełnienia sterty, będziemy jednak posługiwać się adresem��*++.+�0�, ponieważ wskazuje go � �#$#1.

0018740#:2<:$<& ��� �����-���.</,���

Sposób działania jest bardzo prosty. Przepełniamy bufor, nadpisujemy dowolną wartośćw pamięci, wywołując wyjątek związany z naruszeniem ochrony pamięci, co w efekciedoprowadza do wywołania funkcji �����������. Pamiętajmy jednak, że pierwsząoperacją wykonaną przez nasz kod musi być przywrócenie oryginalnej wartości wskaź-nika. Wskaźnik ten może bowiem zostać użyty poza naszym kodem i jeśli jego war-tość będzie niewłaściwa, to utracimy nasz proces. W zależności od sposobu działanianaszego kodu może zachodzić również konieczność naprawienia sterty uszkodzonejprzez przepełnienie.

Naprawianie sterty ma oczywiście sens tylko wtedy, gdy nasz kod wykonuje pewneoperacje podczas kończenia działania procesu. Jak już wspomnieliśmy, sterowanietrafia do naszego kodu zwykle na skutek wywołania funkcji �����������DE przez pro-cedurę obsługi wyjątków. Technika wykorzystania naruszenia ochrony pamięci w celuskierowania sterowania do własnego kodu jest szczególnie przydatna w połączeniuz przepełnieniami sterty stosowanymi podczas ataku na programy CGI.

Przedstawiony poniżej kod ilustruje wykorzystanie naruszenia ochrony pamięci dowykonania własnego kodu. Celem włamania będzie przedstawiony wcześniej program.

������������ ��������������� �����

����H������G��;�����������I��5,����I�����!� ���������������������I�&�,����H��������!

Page 31: The Shellcoders Handbook. Edycja polska

170 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

���&����������H�������5�����-9$$/@��!����H�����������-:/@��!����H���������5�-:/@��!����H������������� ��-7$$/@��!����H�������������' �'�����&@$!����H�������������' �'F�������=�������?���� �@$!����H��������&�-:/@��!����H���������@$!

��������G�����H������������Q���!�������' �'�����&@G��;��������&����������,������&��!�������' �'F�������=�������?���� �@G��;�J�����������������,�F�������=�������?���� ���!����������' �'�����&@@$\\��J�����' �'F�������=�������?���� �@@$���������������1������ H�����������Q���!��������;������ �&�����������&Q�Q�Q�@P�:BQ��,�������' �'�����&�!��������;������ �������F�������=�������?���� �Q�@P�:BQ��,�������' �'F�������=�������?���� ��!�������5�����,�����#��!

((+ �� �Z +�J��������5� +"�3,�����T������� Z�)������&��������!�������5�����,�Q�Q�2$Q�2$Q�2$Q�2$Q�$#Q�2$Q�2$Q�8;Q�9$Q�42Q�8<Q�:3Q�$#Q�32��!����������������&�,�������' �'F�������=�������?���� ��!�������5�����,�&��!�������5�����,�Q�:2Q�<:Q�7$Q�99Q�=$Q�4$Q�8:Q�89Q�8#Q�8=Q�89Q�4<Q�43Q�4$Q�49Q�32��!����������������&�,�������' �'�����&�!�������5�����,�&��!�������5�����,�Q�11Q�6#��!

((�K���Z���������������4:���������5�����,�6666��!���..!%

((��+�A��+� ��+�A��+�F�������=�������?���� �J<�5� +�"�3�������5�����,�Q�#=Q�1$Q�16Q�0���!

((��+�A��+���������&��&�&+ ��� �Z +��������5�����,�Q�::Q�$8Q�94��!

�������5�����,�Q���!��������Q���������H����#������������� ��� ����Q���!�����&�5������!������$!%

����H������G��;�����������I��5,����I��������D6RL��@ERLL!����H�������@$!�@L ��L�5�������5�!���S��������$!

Page 32: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 171

�@G��"� �;��������,�����!���S��������$!�������!%

� ���������������������I�&�,����H�������������H�������@$!�@�!�@�7<!�@���7<!�&�-$/@�!�@�!�@���:!�@�7<!�@���7<!�&�-#/@�!�@�!�@���#8!�@�7<!�@���7<!�&�-7/@�!�@�!�@���7<!�&�-9/@�!%

Jak już wspomnieliśmy, wskaźniki te nie są używane w systemie Windows 2003 Server.

W bloku PEB na platformie Windows 2003 Server posiadają one wartość �;==. Mimo

to nadal możliwe jest przeprowadzenie podobnego ataku. Funkcja �����������DE

lub ;�< �!"�!���������+�"���DE wywołuje wiele funkcji =!�B takich jak na przykład

=!�;�"� !.""DE. Wiele funkcji =!�B posługuje się wskaźnikami funkcji. Wskaźniki te są

zwykle inicjowane przez silnik SHIM. Nie są one wykorzystywane dla zwykłych procesów.

Ten sam efekt możemy osiągnąć nadpisując wskaźnik podczas przepełnienie bufora.

Nadpisanie wskaźnika pierwszej wektoryzowanejprocedury obsługi wyjątków pod adresem 77FC3210

Wektoryzowana obsługa wyjątków wprowadzona została w systemie Windows XP.

W przeciwieństwie do tradycyjnego mechanizmu obsługi wyjątków, który przechowuje

struktury �������������� ���� na stosie, wektoryzowana obsługa wyjątków posługuje

się informacją o procedurach obsługi umieszczoną na stercie. Informacja ta przecho-

wywana jest w strukturach bardzo przypominających struktury �������������� ����.

������']�=CDF�6'�B=�"C DE'ED6���� ��&'�E���E ��!�� ��&'�"���� ��E ��!"]D 6&'���]��� ����������!%

Page 33: The Shellcoders Handbook. Edycja polska

172 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

'�������!� wskazuje następną strukturę M�����.�����������.�, '����A��8���!�poprzednią strukturę M�����.�����������.�, a '���M������!� �!"�� właściwą

procedurę obsługi wyjątków. Wskaźnik struktury M�����.�����������.�, która

zostanie użyta jako pierwsza podczas obsługi wyjątku, znajduje się pod adresem

��**+�/C0� (należy jednak pamiętać, że adres ten może się zmienić w momencie instalacji

pakietów serwisowych). Korzystając z przepełnienia sterty, możemy nadpisać ten

wskaźnik za pomocą adresu naszej własnej struktury M�����.�����������.�. Zaletątakiej techniki jest przede wszystkim to, że wektoryzowane procedury obsługi wyjątków

zostają wywołane przed tradycyjnymi procedurami obsługi wyjątków.

Przedstawiony poniżej kod (dla Windows XP Service Pack 1) odpowiedzialny jest za

przydzielenie procedury obsługi w momencie wystąpienia wyjątku:

00101<2�& ����,�� �������>-001=97#$�/00101<;<)&�00101<3<00101<;8������,-�5�J:/00101<;2�������00101<;;������ �����-���.:/00101<;6�&����,$11�00101<3$)�00101<==00101<37& ����,�� �����-���/00101<3<�&����,���00101<38)��00101<;8

Kod ten umieszcza w rejestrze ��� wskaźnik struktury M�����.�����������.� dla

pierwszej wywoływanej wektoryzowanej procedury obsługi wyjątków. Następnie wywo-

łuje funkcję wskazywaną przez ���#$#?. Wykorzystując przepełnienie sterty, możemy

przejąć kontrolę nad procesem, modyfikując wartość wskaźnika znajdującego się pod

adresem ��**+�/C0�.

Jak to osiągnąć? Najpierw musimy uzyskać wskaźnik naszego bloku przydzielonego

na stercie. Jeśli przechowuje go zmienna lokalna, dostępny jest w bieżącej ramce

stosu. Nawet jeśli wskaźnik ten przechowywany jest za pomocą zmiennej globalnej,

to i tak istnieje duża szansa, że znajduje się gdzieś na stosie odłożony jako parametr

wywołania funkcji, zwłaszcza jeśli wywołaną funkcją jest �� �+���DE (wskaźnik blo-

ku jest wtedy trzecim parametrem). Po zlokalizowaniu tego wskaźnika (załóżmy, że

znajduje się on pod adresem ����0C++-�) możemy udać, że jest on wskaźnikiem

'���M������!� �!"�� należącym do struktury M�����.�����������.� o adresie

����0C++1?. Dlatego też przepełniając adres, dostarczymy wartość ����0C++1? dla

jednego wskaźnika i wartość ��**+�/C�� dla drugiego z nich. Dzięki temu wykonanie

rozkazów

00187481:2$#& ��� �����-���/,���0018740#:2<:$<& ��� �����-���.</,���

spowoduje zapisanie wartości ��**+�/C�� (zawartość rejestru � �) pod adresem ����0C++1?

(���) oraz wartości ����0C++1? (zawartość rejestru ���) pod adresem ��**+�/C0�

(� �#$#1). W wyniku tych operacji przejęliśmy kontrolę nad wskaźnikiem pierwszej

struktury M�����.�����������.� znajdującym się pod adresem ��**+�/C0�. Dzięki

temu w momencie wystąpienia wyjątku rozkaz znajdujący się pod adresem ��**+*+1,�

umieści w rejestrze ��� wartość ����0C++1?, a chwilę później zostanie wywołana funkcja

Page 34: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 173

wskazywana przez ���#$#?. Adres tej funkcji jest adresem naszego buforu przydzie-

lonego na stercie i wobec tego zostanie następnie wykonany nasz kod. Poniżej przed-

stawiamy przykład kodu, który wykonuje opisane działania:

������������ ��������������� �����

����H������G��;�����������I��5,����I�����!� ���������������������I�&�,����H��������!

���&����������H�������5�����-9$$/@��!����H�����������-:/@��!����H���������5�-:/@��!����H������������� ��-7$$/@��!����H�������������' �'�����&@$!����H��������&�-:/@��!����H���������@$!

��������G�����H������� ������&���Q���!

�������' �'�����&@G��;��������&����������,������&��!����������' �'�����&@@$���������������1������ H����������Q���!

��������;������ �&�����������&Q�Q�Q�@P�:BQ��,�������' �'�����&�!

�������5�����,�����#��!

���������4���������5�����,�Q�2$Q�2$Q�2$Q�2$��!���..!%

((+ �� �Z +���� Z�)*�������&��������!�������5�����,�Q�2$Q�99Q�=$Q�4$Q�8:Q�89Q�8#Q�8=Q�89Q�4<Q�43Q�4$Q�49Q�32��!����������������&�,�������' �'�����&�!�������5�����,�&��!�������5�����,�Q�11Q�6#��!!

���@$!���������4:���������5�����,�6666��!���..!%

((U�+�A��+� $�001=97#$J<�$�001=97#$��K��� ��)�((��+�A��+������K�)����+����']�=CDF�6'�B=�"C DE'ED6��������5�����,�Q�$=Q�97Q�1=Q�00��!

((U�+�A��+���K�)����� ����+����']�=CDF�6'�B=�"C DE'ED6�(( �������$�$$#711<:�" ���&������&� ��T+�K ��& :((K��)��)���T��+�A��+���K�H 5�� ���^ �K��H 5�� ��((K ����������� &� ���& &�����K��K��Z����&������K&���+� ��K ����)

Page 35: The Shellcoders Handbook. Edycja polska

174 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

(( 5�Z�H���)*�+_��U��� V`�T����[�� ��� ��`� � Z [����((+ �+�����H 5�� ��������&��=K������+���������5�����,�Q�<:Q���Q�#7Q�$$��!

��������Q���������H����#������������� ��� ����Q���!�����&�5������!������$!%

����H������G��;�����������I��5,����I��������D6RL��@ERLL!����H�������@$!�@L ��L�5�������5�!���S��������$!�@G��"� �;��������,�����!���S��������$!�������!%

� ���������������������I�&�,����H�������������H�������@$!�@�!�@�7<!�@���7<!�&�-$/@�!�@�!�@���:!�@�7<!�@���7<!�&�-#/@�!�@�!�@���#8!�@�7<!�@���7<!�&�-7/@�!�@�!�@���7<!�&�-9/@�!%

Nadpisanie wskaźnika filtranieobsłużonych wyjątków

Na konferencji Blackhat Security Briefings odbywającej się w Amsterdamie w 2001roku Halvar Flake jako pierwszy zaproponował wykorzystanie filtra nieobsłużonychwyjątków. Filtr ten stosowany jest w systemie Windows w sytuacji, gdy żadna innaprocedura obsługi wyjątków nie obsłużyła bieżącego wyjątku bądź gdy żadna proce-dura obsługi wyjątków nie została zdefiniowana. Aplikacja może skonfigurować tenfiltr, korzystając z funkcji ���;�< �!"�!���������+�"���DE. Kod tej funkcji wykonujenastępujące rozkazy:

Page 36: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 175

00�0�4;#& ����,�� �����-���.</00�0�4;4& ����,�� �������>-00�6093<�/00�0�4;;& ��� �������>-00�6093<�/,���00�0�43$���<

Jak łatwo zauważyć, wskaźnik filtra nieobsłużonych wyjątków przechowywany jest

pod adresem ��**�.*/%1 — przynajmniej w przypadku systemu Windows XP Service

Pack 1. W innych systemach może to być inny adres. Aby go odnaleźć, należy prze-

analizować działanie funkcji ���;�< �!"�!���������+�"���DE.

Gdy pojawia się nieobsłużony wyjątek, to system wykonuje poniższy blok kodu:

00�29##<& ����,-00�6093</00�29##2�&����,���00�29##3)�00�29#9700�29##6�������00�29##��������

Adres filtra nieobsłużonych wyjątków zostaje załadowany do rejestru � � i procedura

zostaje wywołana. Rozkaz �8�<#�!� poprzedzający wywołanie filtra odkłada na stosie

adres struktury ����������������. Szczegół ten warto zapamiętać, ponieważ okaże

się on przydatny.

Przepełniając stertę, możemy wykorzystać filtr nieobsłużonych wyjątków w sytuacji,

gdy spowodowany wyjątek nie zostanie obsłużony. W tym celu musimy skonfiguro-

wać własny filtr nieobsłużonych wyjątków. Wskaźnik filtra możemy nadpisać adre-

sem naszego bufora, jeśli jest on łatwy do ustalenia, bądź adresem fragmentu kodu,

który przekaże sterowanie do tego bufora. Przypomnijmy w tym miejscu, że przed

wywołaniem filtra na stosie zostaje umieszczona zawartość rejestru �.�. Reprezentuje

ona adres struktury ���������������. ��*? bajtów za tym adresem, prawie pośrodku

naszego bufora, znajduje się adres, który jest wskaźnikiem końca naszego bufora.

Mimo że adres ten nie stanowi części struktury ���������������, możemy wyko-

rzystać rejestr �.�, aby sterowanie trafiło z powrotem do naszego kodu. W tym celu

musimy odnaleźć jeszcze adres w przestrzeni danego procesu, który zawiera nastę-

pujący rozkaz:

������ �����-���.$�0:/

Chociaż może wydawać się to trudnym zadaniem, to jednak istnieje kilka miejsc,

w których można odnaleźć taki rozkaz. Zależy to jednak od bibliotek załadowanych

przez proces oraz wersji systemu. Poniżej przedstawiamy kilka przykładów lokaliza-

cji tego rozkazu w systemie Windows XP Service Pack 1.

������ �����-���.$�0:/� �����$�0#�9��88-������97����/������ �����-���.$�0:/� �����$�00�955��-������97����/������ �����-���.$�0:/� �����$�00�<#�#4-������97����/������ �����-���.$�0:/� �����$�00�27�9<-����97����/������ �����-���.$�0:/� �����$�0:$4#98�-�����<����/������ �����-���.$�0:/� �����$�0:$4#<48-�����<����/

W systemie Windows 2000 pod adresem ���#$#��1� oraz ���#$#��*1 znajdujesię wskaźnik naszego bufora.

Page 37: The Shellcoders Handbook. Edycja polska

176 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

Wywołania filtra nieobsłużonych wyjątków podczas pracy z programem uruchomieniowym

Każdy wyjątek zostaje przechwycony przez system i sterowanie trafia natychmiast do funkcji

:�;������������.��� ��<��DE w ��!"">!"". Funkcja ta odpowiedzialna jest za mechanizm

obsługi wyjątków. W systemie Windows XP funkcja :�;������������.��� ��<��DE wywołuje

najpierw wektoryzowane procedury obsługi wyjątków, następnie tradycyjne procedury obsługiwyjątków, a na końcu filtr nieobsłużonych wyjątków. Podobnie działa ona w systemie Win-dows 2000, który jednak nie dysponuje mechanizmem wektoryzowanych procedur obsługiwyjątków. Jeden z problemów, które napotkać można tworząc eksploit wykorzystujący przepełnie-nia sterty, polega na tym, że podczas śledzenia atakowanego programu za pomocą programuuruchomieniowego nie jest wywoływany filtr nieobsłużonych wyjątków. Jest to szczególnie irytują-ce, gdy tworzony eksploit wykorzystuje właśnie ten filtr. Istnieje jednak rozwiązanie tego problemu.

Funkcja :�;������������.��� ��<��DE wywołuje funkcję ;�< �!"�!���������+�"���DE, którasprawdza, czy proces nie jest śledzony i czy należy wywołać filtr nieobsłużonych wyjątków. W tym

celu funkcja ;�< �!"�!���������+�"���DE wywołuje funkcję jądra ��GN4H8��������' �����������, która nadaje zmiennej na stosie wartość ��++++++++, jeśli wykonanie procesu jest

śledzone. Gdy funkcja ��GN4H8��������' �����������#zwróci sterowanie, to wartość tej zmiennej

porównywana jest z wyzerowanym rejestrem. Jeśli wartości są takie same, wywoływany jestfiltr nieobsłużonych wyjątków. W przeciwnym razie filtr nie jest wywoływany. Jeśli chcemy, abyfiltr został wywołany podczas śledzenia programu, to powinniśmy zastawić pułapkę na rozka-zie dokonującym porównania. Gdy sterowanie programu dotrze do pułapki, należy zmienić war-

tość zmiennej z ��++++++++ na ���������� i kontynuować śledzenie programu. Dzięki temu

filtr nieobsłużonych wyjątków zostanie wywołany.

Page 38: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 177

Na rysunku na poprzedniej stronie przedstawiony został kod wykonywany przez funkcję ;�< �!"�)!���������+�"��� w systemie Windows XP Service Pack 1. W tym przypadku należy zastawić

pułapkę pod adresem ��**�,/0�% i poczekać na pojawienie się wyjątku. Po osiągnięciu pułapki

należy zapisać wartość ���������� pod adresem ��%�)C�<� i wtedy zostanie wywołany filtr

nieobsłużonych wyjątków.

Jeśli nadpiszemy wskaźnik filtra nieobsłużonych wyjątków jednym z przedstawionychwyżej adresów, to w przypadku wystąpienia nieobsłużonego wyjątku zostanie wykonany

rozkaz, który przekaże sterowanie do naszego bufora. Należy przy tym pamiętać, że filtrnieobsłużonych wyjątków wywoływany jest wyłącznie wtedy, gdy program wykonywany

jest w zwykłym trybie, a nie w trybie uruchomieniowym. W ramce wyjaśnione zo-

stało, jak poradzić sobie z tym problemem.

Aby zademonstrować wykorzystanie filtra nieobsłużonych wyjątków podczas włama-nia metodą przepełnienia sterty, musimy zmodyfikować przykład atakowanego pro-

gramu w taki sposób, by nie zawierał on procedury obsługi wyjątków. Jeśli bowiem

wyjątek zostanie obsłużony, to filtr nie będzie wywołany.

������������ ��������������� �����

���� �����I5���!

���&���������H�,����I��H�-/����D6RL��!�@L ��L�5������&�����������!�@L ��L�5������������97������!��������Q�Q����� ����� ��� H��&�Q���!�����H�S@7���������������;FG?S��!� ���H�-#/�!������$!%

���� �����I5�����LD=;L�#@$,�7@$!�;E6L���!

��@����=������$,$�#$$$,$�#$$$$�!���S�����������������1������ �����������Q���!�#@����;�� ����,��;"'X�FD'���DFY,78$�!����������;">P�:BP�:BQ��,�#,M�#�!

������������������������������ �������������������������#,5���!

((���� �������K�)&�)�&�� ��K�����H��H ��� Z��������;�� ��7@����;�� ����,��;"'X�FD'���DFY,78$�!������������ ��!������$!%

Page 39: The Shellcoders Handbook. Edycja polska

178 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

Włamania dokonuje następny z przedstawionych programów. Nadpisuje on strukturęzwiązaną z zarządzaniem stertą dwoma wskaźnikami. Pierwszy z nich wskazuje filtrnieobsłużonych wyjątków o adresie ��**�.*/%1, a drugi rozkaz � ""#!4��!#�����!�$��*?�znajdujący się w kodzie biblioteki ��� ��/C>!"" pod adresem ��**�/%% .. Gdy atakowa-ny program drugi raz wywoła funkcję �� � ""��DE, to wystąpi wyjątek, który nie zo-stanie obsłużony i trafi do naszego filtra, wskutek czego sterowanie zostanie prze-kazane z powrotem do naszego bufora. Zwróćmy uwagę na rozkaz krótkiego skokuumieszczony w buforze tam, gdzie wskazuje �.�#$#��*?. Służy on ominięciu koduzwiązanego z zarządzaniem stertą.

������������ ��������������� �����

����H������G��;�����������I��5,����I�����!� ���������������������I�&�,����H��������!

���&����������H�������5�����-#$$$/@��!����H�����������-:/@��!����H���������5�-:/@��!����H������������� ��-7$$/@��!����H�������������' �'�����&@$!����H��������&�-:/@��!����H�������@$!������@$!

��������G�����H������� ������&���Q���!�������' �'�����&@G��;��������&����������,������&��!����������' �'�����&@@$���������������1������ H����������Q���!��������;������ �&�����������&Q�Q�Q�@P�:BQ��,�������' �'�����&�!�������5�����,�����#��!���������88���������5�����,�6666��!���..!%

������������������ ������������������������������������� ���!���������"��� �"��������5�����,�Q��3Q�#<��!

((�K���Z�������������5�����,�Q�<<Q�<<Q�<<Q�<<Q�<<Q�<<��!

((" ���&������&�$�00=933;6>������97����B"?"#�K��)��)���T((� K+�K������� �����-���.$�0</��;�����&��&������K�&�((��+�A��+��������� 5�Z�[ ������)*�+_��

�������5�����,�Q���Q�55Q��9Q�00��!

((��+�A��+��������� 5�Z�[ ������)*�+_��������5�����,�Q�3<Q�09Q��6Q�00��!((00�6093<

���@$!

Page 40: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 179

���������7#���������5�����,�Q�2$��!���..!%((+ �� �Z +���� Z�)*�������&��������!�������5�����,�Q�99Q�=$Q�4$Q�8:Q�89Q�8#Q�8=Q�89Q�4<Q�43Q�4$Q�49Q�32��!����������������&�,�������' �'�����&�!�������5�����,�&��!�������5�����,�Q�11Q�6#Q�2$Q�2$��!��������Q���������H����#������������� ��� ����Q���!�����&�5������!������$!%

����H������G��;�����������I��5,����I��������D6RL��@ERLL!����H�������@$!�@L ��L�5�������5�!���S��������$!�@G��"� �;��������,�����!���S��������$!�������!%

� ���������������������I�&�,����H�������������H�������@$!�@�!�@�7<!�@���7<!�&�-$/@�!�@�!�@���:!�@�7<!�@���7<!�&�-#/@�!�@�!�@���#8!�@�7<!�@���7<!�&�-7/@�!�@�!�@���7<!�&�-9/@�!%

Nadpisanie wskaźnika procedury obsługi wyjątkóww bloku TEB

Podobnie jak w przypadku metody wykorzystującej filtr nieobsłużonych wyjątkówHalvar Flake jako pierwszy zaproponował nadpisanie wskaźnika struktury �������������� ���� przechowywanego w bloku TEB (Thread Environment Block). Każdy

Page 41: The Shellcoders Handbook. Edycja polska

180 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

wątek posiada blok TEB, który dostępny jest za pośrednictwem rejestru segmento-wego +�. Pod adresem +�����# znajduje się wskaźnik pierwszej struktury �����)��������� ����. Dokładne położenie bloku TEB zmienia się w zależności od mo-mentu utworzenia wątku, liczby wątków i wielu innych czynników. Zwykle blok TEBpierwszego wątku znajduje się pod adresem ��*++.����, następnego wątku pod adre-sem ��*++..���, czyli w odległości ��0��� bajtów od poprzedniego, i tak dalej. BlokiTEB kolejnych wątków tworzone są zawsze w kierunku adresu ����������. Poniższykod podaje adres bloku TEB pierwszego wątku:

������������ ���

���&������''��&�& ����,�� �������>-$�#:/�������%��������C�3>P�:BQ���!

''��&�������,<%

������$!%

Gdy jeden z wątków kończy swoje działanie, przestrzeń zajmowana przez jego blok TEBzostaje zwolniona i będzie użyta dla bloku TEB wątku, który zostanie utworzony jakonastępny. Stosując przepełnienie sterty, możemy nadpisać wskaźnik struktury �����)��������� ����, który dla pierwszego wątku znajduje się pod adresem ��*++.����.Gdy wystąpi wyjątek związany z naruszeniem ochrony dostępu do pamięci, to będziemyposiadać kontrolę nad wywoływaną procedurą obsługi wyjątków. Zwykle jednak,zwłaszcza w przypadku serwerów o architekturze wielowątkowej, wykorzystanie tej me-tody nastręcza pewnych trudności, ponieważ nie jesteśmy pewni, gdzie dokładnieznajduje się blok TEB bieżącego wątku. Dlatego też metoda ta najlepiej sprawdza sięw przypadku programów jednowątkowych, na przykład uruchamianych w oparciuo interfejs CGI. W przypadku serwerów wielowątkowych najlepiej jest uruchomićwiele wątków i wybrać posiadający najniższy adres TEB.

Naprawa sterty

Po uszkodzeniu sterty przez przepełnienie z reguły powinniśmy ją naprawić. W prze-ciwnym razie możemy być prawie pewni, że nasz proces naruszy mechanizm ochrony

pamięci, zwłaszcza gdy przepełnienie dotyczyło domyślnej sterty procesu. Naprawasterty może polegać na wykonaniu pewnej pracy w zakresie inżynierii odwrotnej dla

atakowanej aplikacji i wyznaczeniu dokładnych rozmiarów bufora oraz następnego

bloku pamięci. Rozmiarom tym możemy przywrócić oryginalne wartości, jednak taki

sposób działania okaże się zbyt pracochłonny, gdy będzie wykonywany dla każdego

włamania z osobna. Bardziej przydatna byłaby ogólna metoda. Najbardziej nieza-

wodna i ogólna metoda naprawiania sterty polega na przywróceniu jej postaci, jakąposiada każda nowa (lub prawie nowa) sterta. Przypomnijmy, że po utworzeniu nowej

Page 42: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 181

sterty, ale przed przydzieleniem jakiegokolwiek jej bloku struktura +���=�������(�� �% ��#$#��0*?) zawiera dwa wskaźniki wskazujące pierwszy wolny blok (�� �% ��

$#��F??) oraz dwa wskaźniki w obrębie tego bloku wskazujące strukturę +���=�������.

Wskaźniki umieszczone w strukturze +���=������� możemy zmodyfikować, tak aby

wskazywały koniec naszego bloku, dzięki czemu powstanie sytuacja, w której pierwszy

wolny blok będzie znajdować się za naszym buforem. Musimy również zmodyfikować

dwa wskaźniki znajdujące się na końcu naszego bufora i poprawić kilka innych szcze-gółów. Jeśli zniszczyliśmy blok znajdujący się na domyślnej stercie procesu, to mo-

żemy naprawić go za pomocą przedstawionego poniżej kodu w asemblerze. Kod ten

powinien zostać wykonany, zanim kod powłoki rozpocznie inne operacje, aby zapobiec

naruszeniu ochrony pamięci. Dobrą praktyką jest również naprawienie wykorzystanego

mechanizmu obsługi wyjątków, ponieważ zapobiega wejściu w pętlę w momencie na-

ruszenia ochrony pamięci.

((" ��+ ������ K+�K������� �����-���.0:/���� �����((�����Z � ���K�H 5�� ������.0:(()�����+�A��+��&����+����K��K*�K���������*�((U�+�A��+����&��V��&����)����K����((��[�)�&�H � � 5������& ����+��)�������((��)����+������������#��"�$�"���"���%�"���&'((U��K����+������&�U��� ��7$$$((K�&����� ��[�K�H � K+�K�����[��[�`((& ����,�� �����-���.$�<=/(( �+Z���$�#:���� ����������(���)�((�Z���)��T���� V`K��� ��� �3B��������*�((" 5������+�A��+5� +�C�3((K��>-#:/�������#����$�"���"����+��%�*�'((" 5������+�A��+5� +�"�3((K5� +�C�3��������#����$�"���"���%������,�'((" 5������+�A��+� &�V���)�������� ����((K5� +�"�3�������#����$�"���"���%������)�'((F�)�������K����������K��+�A��+������((;�������&�� ���`$�$$��$$$$((^ ��H�)�&���+�A��+,��+5���+�K���Z((���� V`C ���1���?�K������� ��������""��-$��.�((Z���)��Z � C ���1���?�K�� ���������#���$����"���%���'((�K�����)�)�����K�)����+���K�K��K*�K����((�����*��������#����"���%�"�'$��((K��T+�K���� 7����������"�����������"�((X&������ K&���� ��K�����H 5� +���:�������#�*������%�"�'$��������������"�((E���)�+ ��)��&75�)� &���� V`$�������#���$����"���%�"�'

Page 43: The Shellcoders Handbook. Edycja polska

182 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

������������"���%�"�'$������������"�����������"�((E���)�K���K��+ &���� V`$�#<�������#�*������%�"�'$��)&����������"�((�����T���&75�)� &���� V`$�������#���$����"���%�"�'������������"���%�"�'$������������"�����������"�((+ ��H�)����,�5���+�K���Z����'5���.$�#0:((�����K&����� V`����'5���.$�7:�������""���$��)/�((�����+�K�)�����K1���L����-$/((K�����)����)�+ 1���L����-$/�1���+�������#�"���"���%���'$�"�(( ��K)�+ 1���L����-$/�3���+�������#�"���"���%����&'$�"�((� ����+�)���+�A��+�K��)��)*����T��+ a��((���K�H 5� +�,�5���+�K���Z�1���L����-$/�������#�"���"���%�"�'$����������#�"���"���%�"��&'$���

Po naprawieniu sterty możemy wykonać dowolny kod. Stercie nie została przywróco-na postać zupełnie nowej sterty, ponieważ inne wątki mogły już wcześniej umieścić

na niej swoje dane. Dane takie umieszcza na stercie na przykład wywołanie funkcjiI� �� ��8�. Jeśli dane te zostaną zniszczone, ponieważ stercie został przywrócony

stan wyjściowy, to jakiekolwiek wywołanie funkcji związanej z gniazdami sieciowy-

mi spowoduje naruszenie ochrony pamięci.

Inne aspekty przepełnień sterty

Nie zawsze przepełnienie sterty zostaje wykorzystane na skutek wywołania funkcji

�� � ""��DE lub �� �+���DE. Inne możliwości wykorzystania przepełnień sterty doty-

czą między innymi prywatnych danych klas języka C++ oraz obiektów modelu COM

(Common Object Model). Model COM umożliwia programistom tworzenie obiektów

na bieżąco przez inne programy. Obiekt taki posiada funkcje czy raczej metody, które

mogą zostać wywołane w celu realizacji pewnych zadań. Dobrym źródłem informacji

na temat możliwości modelu COM jest oczywiście witryna firmy Microsoft (www.

microsoft.com/com/). Dlaczego jednak model COM jest tak interesujący z punktu widze-

nia przepełnień sterty?

Obiekty COM i sterta

Instancja obiektu COM tworzona jest na stercie. Dla każdego obiektu tworzona jest

tabela wskaźników funkcji, znana jako vtable. Wskaźniki te wskazują kod metod, któ-

re obsługują dany obiekt. Powyżej tabeli vtable (w sensie adresów pamięci wirtual-

nej) przydzielony zostaje obszar dla danych obiektu. Gdy tworzone są kolejne obiekty

COM, to ich tabele vtable oraz dane umieszczane są ponad poprzednimi obiektami.

Zastanówmy się, co się stanie, gdy bufor należący do sekcji danych jednego z obiektów

Page 44: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 183

zostanie przepełniony. Przepełnienie takie może nadpisać tabelę vtable następnego

obiektu. W ten sposób haker może przejąć kontrolę nad metodami tego obiektu. Wy-

starczy, że nadpisze wskaźnik jednej z metod adresem swojego bufora. Gdy metoda ta

zostanie wywołana, to sterowanie trafi do kodu umieszczonego w buforze przez hakera.

Metoda taka jest często stosowana w przypadku obiektów ActiveX ładowanych przez

przeglądarkę Internet Explorer. Wykorzystanie przepełnień w przypadku obiektów

COM jest więc niezwykle łatwe.

Przepełnianie danych sterujących logiką programu

Włamania przeprowadzane za pomocą przepełnienia sterty nie muszą prowadzić do

wykonania kodu wprowadzonego przez hakera. Celem ataku mogą być zmienne prze-

chowywane na stosie, które decydują o sposobie działania aplikacji. Wyobraźmy so-

bie na przykład serwer Web, które przechowuje na stercie informacje o uprawnieniach

dotyczących wirtualnych katalogów. Nadpisanie takiej struktury za pomocą przepełnienia

na stercie umożliwi atakującemu uzyskanie prawa zapisu w katalogu nadrzędnym i zała-

dowanie własnych treści na serwer.

Podsumowanie przepełnień sterty

Przedstawiliśmy kilka mechanizmów umożliwiających wykorzystanie przepełnień

sterty. Wykorzystanie każdego przepełnienia sterty wymaga indywidualnego podej-

ścia, ponieważ przepełnienia te zawsze różnią się między sobą. Omówiliśmy również

niebezpieczeństwa wynikające z nieostrożnego obchodzenia się ze stertą. Konse-

kwencje mogą być nieprzyjemne, wobec czego lepiej zachować ostrożność.

Inne przepełnienia

Podrozdział ten poświęciliśmy przepełnieniom, które nie zachodzą ani na stosie, ani

na stercie.

Przepełnienia sekcji .data

Każdy program podzielony jest na szereg obszarów zwanych sekcjami. Właściwy kodprogramu umieszczony jest w sekcji .text. Sekcja >! � zawiera zmienne globalne.Informacje o sekcjach programu możemy uzyskać na podstawie jego pliku wyko-nywalnego za pomocą narzędzia !8'�(�� wywołanego z opcją G�� .�� oraz opcjąG���������>nazwa_sekcji, która wyświetla informacje o wybranej sekcji. Chociaż prze-pełnienia sekcji >! � są rzadziej spotykane niż przepełnienia stosu lub sterty, to sąone również z powodzeniem wykorzystywane na platformie Windows. Podstawowymutrudnieniem w ich przypadku jest konieczność zachowania odpowiednich zależnościczasowych. Przeanalizujmy to na poniższym przykładzie kodu w języku C:

Page 45: The Shellcoders Handbook. Edycja polska

184 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

������������ ��������������� �����

����H�������5�����-97/@��!1;F"FD=&������@$!1;F"FD=&������@$!

���&���������H�,����I��H�-/����D6RL��@$!�@L ��L�5������&�����������!���S��������$!&������@G��"� �;��������,���������!���S&�������������$!&������@G��"� �;��������,���������!���S&�������������$!�&��������5�����,��H�-#/�!''��&�������,:%�&���������P��,5������!''��&�������,:%1���L�5�������!

������$!%

Program ten ładuje dynamicznie bibliotekę runtime języka C ('�A���>!""), a następniepobiera adresy funkcji ������DE i ������DE. Adresy te zostają umieszczone w zmiennychglobalnych, które przechowywane są w sekcji >! � . Zdefiniowany został równieżglobalny bufor mieszczący 32 bajty. Wskaźniki funkcji używane są następnie w celuskopiowania danych do tego bufora oraz wyświetlenia jego zawartości. Zwróćmy jednakuwagę na uporządkowanie zmiennych globalnych. Pierwszy jest bufor, a dopiero za nimznajdują się wskaźniki. W tej samej kolejności zmienne te zostaną umieszczone w sekcji>! � . Jeśli bufor zostanie przepełniony, to wskaźniki funkcji zostaną nadpisane. W tensposób haker może przejąć kontrolę nad programem w momencie wywołania jednejz funkcji.

Przeanalizujmy, co się stanie, gdy nasz program zostanie uruchomiony ze zbyt długimłańcuchem argumentu. Pierwszy z argumentów wywołania programu zostaje skopiowanydo bufora za pomocą funkcji ������. Przepełnienie tego bufora sprawia, że nadpisanezostają wskaźniki funkcji. Następnie program próbuje wywołać funkcję ������, posłu-gując się jej wskaźnikiem. Wywołanie to umożliwia przejęcie sterowania przez kodwprowadzony przez hakera. Oczywiście opisana tutaj sytuacja została znacznieuproszczona dla potrzeb ilustracji. W rzeczywistości sprawa nie jest taka prosta. Nad-pisany wskaźnik może zostać użyty przez program znacznie później, a w międzycza-sie zostanie usunięta zawartość bufora. Dlatego właśnie zależności czasowe stanowiąpodstawową przeszkodę przy tego rodzaju atakach. W naszym przykładzie w momenciewywołania funkcji ������ za pomocą wskaźnika rejestr � � wskazuje początek bufora,wobec czego możemy nadpisać wskaźnik printf adresem rozkazu &'�#� � lub � ""#� �.Co więcej, ponieważ bufor jest parametrem przekazywanym funkcji ������, to jegoadres możemy znaleźć na stosie pod adresem ���#$#?. Oznacza to, że równie dobrze

Page 46: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 185

moglibyśmy nadpisać wskaźnik funkcji adresem bloku kodu zawierającego sekwencjęrozkazów ���, ���, ���. Dwa pierwsze rozkazy odsłonią nam na stosie adres bufora.Wykonanie rozkazu �� przekaże sterowanie do tego bufora. Przypomnijmy jednakraz jeszcze, że nie jest to typowa sytuacja dla rzeczywistych programów. Zaletą prze-pełnień sekcji >! � jest przede wszystkim możliwość odnalezienia bufora w sekcji>! � zawsze pod tym samym adresem.

Przepełnienia bloków TEB i PEB

Aby przegląd przepełnień był kompletny, należy wspomnieć o możliwości przepeł-niania bloków TEB. Należy jednak zaznaczyć, że nie istnieją żadne publicznie ujawnio-ne raporty na temat wykorzystania takich przepełnień w praktyce. Każdy blok TEB za-wiera bufor, który używany jest do konwersji łańcuchów znakowych z kodu ASCII nakod Unicode na przykład przez funkcje �����'�8���� '� czy �����!8"�� �!"� . Prze-pełnienie tego bufora może nastąpić, gdy funkcja nie sprawdza długości umieszczanegow nim łańcucha bądź gdy istnieje sposób wprowadzenia ją w błąd co do rzeczywistej dłu-gości łańcucha w kodzie ASCII. Załóżmy, że znaleźliśmy metodę wywołania takiegoprzepełnienia. Zastanówmy się, w jaki sposób możemy wykorzystać to przepełnienie dowykonania własnego kodu. Sposób ten zależy od tego, w którym z bloków TEB nastąpiłoprzepełnienie. Jeśli przepełnienie nastąpiło w bloku TEB pierwszego wątku danegoprocesu, to w efekcie nadpisany został blok PEB tego procesu. Przypomnijmy, że w blokuPEB znajduje się szereg ważnych wskaźników, które używane są podczas kończeniapracy procesu. Przepełniając bufor bloku TEB, możemy nadpisać jeden z tych wskaźni-ków i przejąć sterowanie przed zakończeniem procesu. Natomiast gdy przepełnionyblok TEB należy do innego wątku, nadpisana zostanie zawartość innego bloku TEB.

W każdym bloku TEB znajduje się wiele interesujących wskaźników, które możemy

nadpisać. Przykładem może być wskaźnik pierwszej struktury �������������� ����.Po nadpisaniu tego wskaźnika musimy jeszcze wywołać wyjątek w wątku, do któregonależy dany blok TEB. Możliwe jest również przepełnienie wielu bloków TEB i nad-pisanie wskaźników znajdujących się w bloku PEB. Pewnym utrudnieniem związanymz wykorzystaniem takich przepełnień jest to, że nadpisują one wskaźniki danymi w ko-dzie Unicode.

Przepełnienie buforówi stosy zabraniające wykonania kodu

W systemie Sun Solaris wprowadzono możliwość takiego konfigurowania stosu, byuniemożliwiał on wykonanie znajdującego się na nim kodu. Oczywiście celem tegorozwiązania było zapobieżenie atakom wykorzystującym przepełnienia buforów na

stosie. Jednak w przypadku procesorów x86 rozwiązanie takie nie jest możliwe. Do-stępne są jedynie produkty, które śledzą stosy wszystkich działających procesów. Jeśliwykryta zostanie próba uruchomienia kodu znajdującego się na stosie, działanie procesuzostaje zakończone.

Page 47: The Shellcoders Handbook. Edycja polska

186 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

Istnieje szereg sposobów obejścia mechanizmów ochrony stosu. Jedna z nich, zapro-

ponowana przez hakera o pseudonimie Solar Designer, polega na nadpisaniu adresu

powrotu za pomocą adresu funkcji �����'DE. David Litchfield napisał artykuł poświę-

cony zastosowaniu tej metody na platformie Windows. Okazuje się jednak, że istnieje

jeszcze lepsza metoda. Rafał Wojtczuk opisał ją na łamach Bugtraq (http://community.

core-sdi.com/~juliano/non-exec-stack-problems.html). Metoda ta wykorzystuje kopiowa-

nie łańcuchów i nie została jeszcze opisana dla platformy Windows. Uczynimy to poniżej.

Z nadpisaniem adresu powrotu za pomocą adresu funkcji �����'DE wiąże się następują-

cy problem. Funkcja �����'DE eksportowana jest w systemie Windows przez bibliote-

kę '�A���>!"", której położenie w pamięci zmienia się dla różnych systemów (a nawet

dla różnych procesów działających w tym samym systemie). Co gorsza, wykonując

polecenie, tracimy dostęp do interfejsu Win32, co znacznie ogranicza nasze możliwości.

Dlatego lepszym rozwiązaniem byłoby skopiowanie naszego bufora na stertę procesu

lub do innego obszaru pamięci, który umożliwia zapis danych i wykonanie kodu. W tym

celu nadpiszemy adres powrotu adresem funkcji kopiującej łańcuchy. Nie będzie to jednak

funkcja ������DE, ponieważ jest ona, podobnie jak funkcja �����'DE, eksportowana

przez bibliotekę '�A���>!"". Natomiast funkcja "������DE eksportowana jest przez

bibliotekę 7����"/C>!"", która posiada zawsze ten sam adres bazowy przynajmniej dla

wszystkich procesów działających w tym samym systemie. Jeśli wykorzystanie funkcji

"������DE natrafia na pewne przeszkody (na przykład jej adres zawiera niedozwolo-

ny znak, taki jak ��� ), to możemy użyć jeszcze funkcji "���� �DE.

Gdzie skopiujemy zawartość naszego bufora? Moglibyśmy umieścić ją na stercie,

ale istnieje duża szansa, że uszkodzimy stertę i tym samym zakończymy działanie

procesu. Dlatego wybierzemy blok TEB. Każdy blok TEB posiada 520-bajtowy bu-

for używany do konwersji łańcuchów z Unicode na ASCII. Bufor ten jest przesunięty

o ����� bajtów względem początku bloku TEB. Blok TEB pierwszego z wątków da-

nego procesu posiada adres ��*++.���� i wobec tego interesujący nas bufor ma adres

��*++.����. Bufor ten używany jest do konwersji łańcuchów na przykład przez funk-

cję �����!8"�� �!"� . Jego adres moglibyśmy przekazać jako adres bufora docelowe-

go funkcji "������, ale ze względu na bajt zerowy na końcu łańcucha posłużymy się

w praktyce adresem ��*++.���1. Musimy jeszcze określić położenie naszego bufora na

stosie. Ponieważ adres ten znajdzie się na końcu naszego łańcucha, nie ma znaczenia,

czy rozpoczyna się od bajtu zerowego (np. ����0C++.�). Bajt ten spełnia wtedy równocze-

śnie funkcję oznaczenia końca łańcucha. Pozostaje nam jeszcze skonfigurować od-

powiednio adres powrotu, aby po zakończeniu funkcji "������ sterowanie trafiło do

naszego bufora zawierającego kod powłoki.

Zaatakowana funkcja, kończąc swoje działanie, zdejmuje ze stosu adres powrotu. Adresten nadpisaliśmy za pomocą adresu funkcji "������DE, wobec czego wykonanie rozkazupowrotu przekaże sterowanie do funkcji "������DE. Dla funkcji "������DE rejestr ���wskazywać będzie adres powrotu. Funkcja pominie ten adres i przejdzie do swoichparametrów — bufora źródłowego i bufora docelowego. Następnie będzie kopiowaćkolejne bajty, począwszy od adresu ����0C++.�, do bufora o adresie ��*++.���1 takdługo, aż natrafi na bajt zerowy kończący łańcuch źródłowy (wskaźnik bufora źródłowegoznajduje się w dolnym prostokącie po prawej stronie rysunku 8.4). Po zakończeniu kopio-wania funkcja "������ zwraca sterowanie do naszego bufora. Oczywiście umieszczony

Page 48: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 187

Rysunek 8.4.Stos przed i po

przepełnieniu

tam kod powłoki musi mieć rozmiar mniejszy niż 520 bajtów. W przeciwnym bo-wiem razie spowoduje przepełnienie bufora bloku TEB i nadpisze kolejny blok TEBlub PEB. (Możliwości przepełnień bloków TEB i PEB omówimy później).

Zanim przejdziemy do tworzenia kodu, musimy najpierw zastanowić się, jak będziedziałał tworzony eksploit. Jeśli użyje on jakiejkolwiek funkcji, która wykorzystujebufor bloku TEB do konwersji pomiędzy kodami Unicode i ASCII, działanie procesumoże zostać zakończone. Na szczęście w blokach TEB istnieją inne wolne obszary,które nie są używane lub ich nadpisanie nie jest krytyczne. Na przykład począwszy odadresu ��**++.�0%� (dla bloku TEB pierwszego wątku danego procesu), zaczyna sięblok bajtów zerowych.

Przyjrzyjmy się teraz kodowi przykładów. Najpierw kod atakowanego programu:

������������ ���

���� �����I�!

���&���������H�,����I��H�-/������H�������5�����-47$/@��!�����H�S@7���������������"���������������H�&���SQ���!� ���H�-#/�!������$!%

���� �����I�����������H�������5�����-8$$/@��!��������P�:BQ��,M5������!�������5�����,������!������$!%

Przepełnienie bufora na stosie zachodzi w funkcji ���DE. Funkcja ������DE kopiuje danewprowadzone przez użytkownika do bufora o rozmiarze 600 znaków bez sprawdzeniarozmiaru łańcucha źródłowego. Powodując przepełnienie nadpiszemy adres powrotuadresem funkcji "���� � .

Page 49: The Shellcoders Handbook. Edycja polska

188 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

W systemie Windows XP Service Pack 1 adres funkcji "������ zawiera bajt ��� .

Następnie modyfikujemy adres powrotu, aby funkcja "���� � , kończąc swoje dzia-

łanie, przekazała sterowanie do naszego nowego bufora w bloku TEB. A także przy-

gotowujemy parametry funkcji, z których bufor docelowy znajduje się w bloku TEB,

a bufor źródłowy na stosie. Program kompilujemy w środowisku Microsoft Visual

C++ 6.0 na platformie Windows XP Service Pack 1. Nasz eksploit jest przenośnym

kodem powłoki. Działa poprawnie dla systemu Windows NT i jego następnych wer-

sji. Z bloku PEB pobiera najpierw listę załadowanych modułów. Następnie odnajduje

adres bazowy modułu 7����"/C>!""#i parsuje jego nagłówek PE w celu odnalezienia

adresu funkcji ������� !!����. Dysponując tym adresem oraz adresem bazowym

7����"/C>!"", może uzyskać również adres funkcji =� !=�(� �� . Korzystając z obu

wymienionych funkcji, może już zrealizować swoje zadanie. Za pomocą następujące-

go polecenia uruchomimy program ���� �, aby nasłuchiwał na podanym porcie:

=>Q���J�J�49

a następnie uruchomimy nasz eksploit. W efekcie powinniśmy uzyskać nową powłokę.

������������ ��������������� �����

����H����������� ��-4#$/@�Q�44Q�:3Q��=Q��3Q�$9Q�43Q��3Q�$4Q��:Q�1:Q�11Q�11Q�11Q�3�Q�11Q�11��Q�11Q�11Q�:#Q�18Q�6=Q�1�Q�11Q�11Q�$9Q�6�Q�99Q�=$Q�4$Q�4$Q�4$Q�4$��Q�4$Q�4$Q�4$Q�4$Q�4$Q�4$Q�11Q�69Q�4$Q�8:Q�8#Q�07Q�02Q�<#Q�8:Q�<=��Q�82Q�87Q�07Q�8:Q�<=Q�81Q�8#Q�8<Q�4<Q�11Q�04Q�1=Q�11Q�44Q�1<Q�:2��Q�<4Q�1$Q�:9Q�=9Q�89Q�:9Q�=9Q�46Q�99Q�=2Q�3#Q�<�Q�37Q�11Q�9$Q�#9��Q�:9Q��3Q�$#Q��7Q�12Q�<9Q�49Q�11Q�04Q�1=Q�11Q�44Q�1<Q�:2Q�<4Q��=��Q�:9Q�=9Q�#$Q�49Q�11Q�04Q�1=Q�11Q�44Q�1<Q�:2Q�<4Q��:Q�:9Q�=9Q�$=��Q�49Q�11Q�44Q�1$Q�:2Q�<4Q�1:Q�:9Q�=9Q�$=Q�49Q�4$Q�11Q�44Q�1<Q�:2��Q�<4Q��<Q�:9Q�=9Q�$=Q�49Q�11Q�04Q�1:Q�11Q�44Q�1<Q�:2Q�<4Q��$Q�:9��Q�=9Q�$=Q�49Q�11Q�04Q�1:Q�11Q�44Q�1<Q�:2Q�<4Q�6=Q�:9Q�=9Q�$:Q�:2��Q�46Q�6:Q�99Q�67Q�88Q�:9Q�=7Q�$7Q�4<Q�47Q�11Q�44Q��<Q�99Q�=$Q�99��Q�=2Q�88Q�32Q�$<Q�$#Q�4$Q��7Q�16Q�:2Q�<4Q�6<Q�:2Q�<4Q�6$Q�31Q�$;��Q�$#Q�$#Q�78Q�:2Q�06Q�==Q�<$Q�<$Q�:2Q�<4Q�=:Q�88Q�3:Q�11Q�11Q�88��Q�94Q�11Q�=;Q�88Q�:2Q�<4Q�=;Q�8;Q�$#Q�8;Q�$7Q�11Q�44Q��$Q�:2Q�<4��Q��$Q�8;Q�#$Q�:6Q�04Q�=:Q�48Q�:3Q�46Q��$Q�49Q�11Q�44Q�6=Q�:9Q�=$��Q�<<Q�:2Q�:4Q�4:Q�11Q�11Q�11Q�:9Q�=$Q�4�Q�:9Q�=$Q�4�Q�:2Q�<4Q�:<��Q�:2Q�46Q�2$Q�:2Q�46Q�2<Q�:2Q�46Q�2:Q�:6Q�36Q�<:Q�11Q�11Q�11Q�40��Q�:6Q�36Q�4:Q�11Q�11Q�11Q�40Q�99Q�=$Q�4$Q�4$Q�4$Q�:9Q�=$Q�$#Q�4$��Q�:9Q��:Q�$#Q�4$Q�4$Q�:3Q�46Q�6:Q�49Q�4$Q�11Q�44Q��=Q�11Q�44Q��:��Q�8$Q�99Q�67Q�:9Q�=7Q�9$Q�8<Q�:3Q�$7Q�:3Q�<$Q�$=Q�:3Q�0$Q�#=Q�;6��Q�:3Q�4$Q�$:Q�47Q�:3Q�=7Q�:3Q�17Q�:3Q�6;Q�:3Q�=;Q�$9Q�47Q�9=Q�$9��Q�<7Q�0:Q�$9Q�4:Q�#=Q�4#Q�8;Q�#1Q�42Q�<#Q�$9Q�9<Q�$:Q�42Q�$9Q�<:��Q�7<Q�4;Q�47Q�:3Q�1;Q�$9Q�9�Q�:#Q�91Q�<0Q�84Q�0<Q�4$Q�0<Q�$:Q�:9��Q�=8Q�$<Q�:9Q�=#Q�$7Q��3Q��=Q�:9Q�=0Q�$<Q�:#Q�91Q�07Q�81Q�89Q�<#��Q�0<Q�$:Q�:9Q�=8Q�$<Q�:9Q�=#Q�$7Q��3Q�62Q�:3Q�1;Q�$1Q�30Q�$#Q�$9��Q�9=Q�:9Q�:2Q�0=Q�7<Q�<<Q�:3Q�9=Q�7<Q�:2Q�0=Q�7<Q�<=Q�41Q�8#Q�=9��Q�2$Q�2$Q�2$Q�3=Q�:6Q�2;Q�2�Q�:3Q�2;Q�;1Q�:6Q�2$Q�2=Q�2;Q�:=Q�:=��Q�3�Q�11Q�11Q�3;Q�:0Q�28Q�:3Q�;3Q�20Q�:6Q�2;Q�2�Q�23Q�11Q�11Q�;:��Q�:=Q�=6Q�;$Q�==Q�=6Q�6#Q�23Q�29Q�29Q�11Q�11Q�;:Q�;=Q�3�Q�;=Q�:3�

Page 50: The Shellcoders Handbook. Edycja polska

Rozdział 8. ♦ Przepełnienia w systemie Windows 189

�Q�2�Q�:6Q�:3Q�:;Q�:1Q�11Q�11Q�;:Q�;=Q�3�Q�;=Q�2$Q�2=Q�2<Q�2;Q�:3��Q�3�Q�11Q�11Q�2=Q�2$Q�2#Q�2#Q�2;Q�2=Q�:3Q�11Q�2=Q�27Q�23Q�11Q�11��Q�11Q�11Q�11Q�11�!

���&���������H�,����I��H�-/��������@$!����H�������5�����-#$$$/@��!

�����H�S@9�������$!

?����U��� �+��!

((R���������� "���&��� ����+ �K��� �Z +�((;���� "���� ������K������`5�)�_�K�� ����,((� �����[K ������ 5��T���?��R����� �����H�-#/,�� ����H�-7/��!

((��K�����+ ����H �� H��&��������5�����,������!((+ ���)�+ �� �Z +�� 5�� ���������5�����,���� ���!

((RK���Z���5�� ����������74���������5�����,�Q�2$Q�2$Q�2$Q�2$��!���..!%

�������5�����,�Q�2$Q�2$Q�2$Q�2$��!

((;����� �� ��K ���������������((������&���+�)��������;������&��U��� ��B"?"#((�_���&$�00�0<388�������5�����,�Q�88Q�<3Q��0Q�00��!

((^ ���H���)������� �� ��������+�)��������;(()�+ ��������K�H + ���5� +�C�3�������5�����,�Q�3=Q��#Q�16Q�01��!

((^ ���H���)�5�� �� ��� ��������+�)��������;((��_����[5�� ��5� +�C�3��������5�����,�Q�3=Q��#Q�16Q�01��!

((3�� �A�_�Z ���" �������&��&K��)��)���T((���K ��H������5�� ����� ����������5�����,�Q�#$Q�13Q�#7��!

((R�����&��&����+ ������ H��&SU�������5�����,?U'�;B � X��!

������$!%

Page 51: The Shellcoders Handbook. Edycja polska

190 Część II ♦ Włamania na platformach Windows, Solaris i Tru64

���?����U��� �+���������@$!UDF6�]���� �F�b������!U?;6;C;���6���!

�]���� �F�b������@�;^�UDF6�7,$�!���@U?;?��������]���� �F�b������,M���6����!������S@$�������$!���LD3YC�����6�����]���� ��S@7\\� 3YC�����J6�����]���� ��S@$��U?;=��������!������$!%������$!%���?��R����� �������I&���,���&�� ��������H��������@$!����H����� �����@$!����I���@��!����I����@��!

��@����'�����&����!

���@�����I�M��!���� ��-#2#/@���-$/!���� ��-#27/@���-#/!���� ��-#29/@���-7/!���� ��-#2</@���-9/!

(( +��V��� ��C="((��+�_��&���Z����)�������((���>��J�J�49

���@�� ��������H����� ���&�� ���!���@���N$�1111!����@�����I�M���!���� ��-7$2/@����-$/!���� ��-7#$/@����-#/!

������$!%

Podsumowanie

W tym rozdziale omówiliśmy bardziej zaawansowane metody wykorzystania prze-pełnień na platformie Windows. Z przedstawionych przykładów płynie nauka, żeprawie zawsze można rozwiązać lub obejść trudności pojawiające się podczas przy-gotowywania włamania. W praktyce można nawet założyć, że każda możliwość prze-pełnienia nadaje się do wykorzystania podczas włamania. Wystarczy jedynie znaleźćodpowiedni sposób.