Master File Table

MFT

Najbardziej godnym uwagi źródłem cennych dla analityka informacji z systemu plików NTFS jest Master File Table (MFT). Położenie sektora startowego MFT można znaleźć w sektorze startowym dysku, a każdy plik i katalog w woluminie ma swój wpis w MFT. Każdy wpis w MFT ma rozmiar 1024 bajtów, co sprawia, że MFT jest bardzo prosty w parsowaniu. Każdy rekord lub wpis MFT zaczyna się od ciągu ASCII „FILE” (jeśli we wpisie jest błąd, zacznie się on od „BAAD”) i składa się z jednego lub więcej (najczęściej więcej) atrybutów, z których każdy ma swój własny identyfikator i strukturę. Rysunek 4.1 ilustruje fragment wpisu MFT.

Rysunek 4.1. Fragment rekordu MFT, czyli wpisu.

Pierwsze 42 bajty każdego wpisu MFT zawierają strukturę nagłówka z 12 elementami, a pozostałe 982 bajty zależą w dużej mierze od wartości zawartych w nagłówku i różnych atrybutów zawartych w wpisie. Nie wszystkie elementy w nagłówku wpisu MFT są natychmiast przydatne dla analityka sądowego; jednakże, Rysunek 4.2 ilustruje pięć z elementów, które są natychmiast przydatne.

Rysunek 4.2. Elementy nagłówka rekordu MFT (w porządku little endian).

Jak widać na rysunku 4.2 (który jest fragmentem wyodrębnionym z rysunku 4.1), widzimy sygnaturę „FILE” widoczną na początku rekordu. Następnie widzimy numer sekwencyjny lub wartość, która jest inkrementowana, gdy wpis jest przydzielany lub nieprzydzielany. Ponieważ ten konkretny wpis MFT jest właściwie pierwszym rekordem w MFT i odnosi się do pliku „$MFT”, zrozumiałe jest, że numer sekwencji wynosi 1. Następnie widzimy liczbę odnośników (link count), która odnosi się do liczby katalogów, w których znajdują się wpisy dla tego rekordu (twarde odnośniki powodują inkrementację tej wartości). Kolejnym elementem jest offset do pierwszego atrybutu w rekordzie; jeśli spojrzymy na offset 0x38 w rekordzie, zobaczymy, że pierwszy atrybut ma identyfikator 0x10, czyli 16. Na koniec widzimy wartość flag, która mówi nam, czy wpis jest alokowany (jeśli bit 0x01 jest ustawiony) i czy wpis jest katalogiem (jeśli bit 0x02 jest ustawiony). W skrócie, na podstawie tych dwóch wartości możemy określić, czy wpis jest alokowany czy usunięty, oraz czy dotyczy pliku czy katalogu. Gdy nagłówek jest parsowany, pseudokod może być przedstawiony w następujący sposób:

if ($mft{flags} & 0x0001) – allocated; else unallocated/deleted

if ($mft{flags} & 0x0002) – folder/katalog; else file

Wartość flag widoczna na rysunku 4.2 to „0x01”, co oznacza zaalokowany plik. Wartość 0x00 wskazywałaby na usunięty plik, a wartość 0x03 na przydzielony katalog.

Wskazówka

Rekordy MFT

Rekordy MFT nie są usuwane po ich utworzeniu; nowe rekordy są dodawane do MFT w miarę potrzeb, a rekordy dla usuniętych plików są ponownie wykorzystywane.

Jak wspomniano wcześniej, tylko pierwsze 42 bajty są ustrukturyzowane; potem reszta wpisu MFT składa się z jednego lub więcej pól atrybutów. Nie istnieje żadna formalna specyfikacja ani deklaracja, która mówi, że we wpisie MFT muszą znajdować się określone atrybuty, ale w większości wpisów MFT można się spodziewać atrybutów $STANDARD_INFORMATION i $FILE_NAME. W tej sekcji przyjrzymy się tym dwóm atrybutom, ponieważ dostarczają one informacji o znacznikach czasu, które są cenne dla analityków sądowych. Przyjrzymy się również krótko atrybutowi $DATA, a pozostałe atrybuty pozostawimy jako ćwiczenie dla zainteresowanego i ciekawskiego czytelnika.

Nagłówek każdego atrybutu zawiera 16-bajtowy nagłówek, który identyfikuje typ atrybutu, ogólną długość atrybutu oraz to, czy atrybut jest rezydentny dla wpisu MFT, czy nie, wśród innych elementów.

Uwaga

Pliki metadanych MFT

Pierwszych 16 wpisów MFT zawiera informacje o plikach metadanych; jednakże, nie wszystkie mogą być używane. Te, które nie są używane, są pozostawione w stanie alokacji i zawierają tylko podstawowe informacje.

Używając tych informacji nagłówkowych, możemy prześledzić wpis MFT i wydobyć cenne informacje z każdego atrybutu. Na przykład, atrybut $STANDARD_INFORMATION (który zawsze jest rezydentny) istnieje dla każdego wpisu pliku i katalogu i ma identyfikator 0x10 (tj. 16). Atrybut ten zawiera czasy plików dla wpisu MFT (no, w każdym razie trzy z nich), które widzimy, gdy wpisujemy „dir” w wierszu poleceń; czas zmodyfikowany, czas ostatniego dostępu i datę utworzenia (narodzin) pliku lub katalogu, zwane również czasami „MAC”. Atrybut ten zawiera czwartą wartość czasu, która określa ostatni raz, kiedy wpis MFT został zmieniony. Wszystkie razem, czasy te są określane jako czasy „MACE” (z „E” odnoszącym się do czasu modyfikacji wpisu MFT) lub „MACB” (z „C” odnoszącym się do czasu modyfikacji wpisu MFT).

Ostrzeżenie

Czasy plików

Czasy plików NTFS są zapisywane w formacie Uniwersalnego Czasu Koordynowanego (UTC), który jest analogiczny do Greenwich Mean Time. Jest to prawdziwe dla wszystkich czasów; w każdym wpisie MFT, rekord pliku będzie miał prawdopodobnie co najmniej 8 czasów z nim związanych; wiele razy, 12 lub więcej. W systemie plików FAT czasy plików są utrzymywane w formacie czasu lokalnego systemu.

Atrybut $FILE_NAME (identyfikator 0x30, czyli 48) występuje również w większości wpisów MFT dotyczących plików i katalogów; w rzeczywistości wiele wpisów MFT będzie miało więcej niż jeden atrybut $FILE_NAME. Podobnie jak atrybut $STANDARD_INFORMATION, atrybut ten jest zawsze rezydentny i również zawiera cztery wartości czasu; jednakże, te wartości czasu są zwykle ustawiane podczas tworzenia pliku w systemie. W przeciwieństwie do czasów plików w atrybucie $STANDARD_INFORMATION, na te czasy plików nie ma wpływu normalna aktywność systemu lub złośliwa ingerencja i dlatego mogą one być użyte do określenia wskaźników złośliwej aktywności, a także można podjąć kroki w celu ukrycia czasu, w którym system został zainfekowany. Poniższa próbka kodu (funkcja parseSIAttr()) przedstawia przykład, w jaki sposób atrybut $STANDARD_INFORMATION może zostać przetworzony:

sub parseSIAttr {

my $si = shift;

my %si;

my ($type,$len,$res,$name_len,$name_ofs,$flags,$id,$sz_content,$ofs_content)

= unpack(„VVCCvvVv”,substr($si,0,22));

my $content = substr($si,$ofs_content,$sz_content);

my ($t0,$t1) = unpack(„VV”,substr($content,0,8));

$si{c_time} = getTime($t0,$t1);

my ($t0,$t1) = unpack(„VV”,substr($content,8,8));

$si{m_time} = getTime($t0,$t1);

my ($t0,$t1) = unpack(„VV”,substr($content,16,8));

$si{mft_m_time} = getTime($t0,$t1);

my ($t0,$t1) = unpack(„VV”,substr($content,24,8));

$si{a_time} = getTime($t0,$t1);

$si{flags} = unpack(„V”,substr($content,32,4));

return %si;

}

Wskazówka

GetTime

Funkcja getTime() widoczna w listingu kodu dla podanego przed chwilą atrybutu parseSIAttr() składa się z kodu zapożyczonego od Andreasa Schustera, który tłumaczy 64-bitowe znaczniki czasu obiektu FILETIME na 32-bitowy czas uniksowy, który może być dalej tłumaczony na czas czytelny dla człowieka poprzez wbudowaną w Perla funkcję gmtime(). Kod ten wygląda następująco:

sub getTime($$) {

my $lo = shift;

my $hi = shift;

my $t;

if ($lo == 0 && $hi == 0) {

$t = 0;

} else {

$lo -= 0xd53e8000;

$hi -= 0x019db1de;

$t = int($hi*429.4967296 + $lo/1e7);

};

$t = 0 if ($t < 0);

return $t;

}

Ten kod jest bardzo przydatny do parsowania i tłumaczenia dowolnego obiektu FILETIME, niezależnie od tego, skąd został wyodrębniony.

W normalnym systemie, wiele wpisów MFT może mieć dwa atrybuty $FILE_NAME: jeden przechowujący pełną nazwę pliku (lub katalogu) i jeden przechowujący DOS-ową, 8.3 nazwę pliku. Na przykład, jeśli plik nosi nazwę „myreallylongfile.txt”, nazwa pliku w wersji 8.3 będzie brzmiała „myreal~1.txt”. Jest to zachowane dla kompatybilności ze starszymi systemami plików i tymi, które nie obsługują długich nazw plików. Tak więc w normalnym systemie Windows nie jest niczym niezwykłym posiadanie wielu wpisów MFT z dwoma atrybutami $FILE_NAME o niemal identycznej zawartości. Poniższa próbka kodu (funkcja parseFNAttr()) dostarcza przykładu tego, jak atrybut $FILE_NAME z wpisu MFT może zostać przetworzony i wyodrębnić dostępne dane:

sub parseFNAttr {

my $fn = shift;

my %fn;

my ($type,$len,$res,$name_len,$name_ofs,$flags,$id,$sz_content,$ofs_content)

= unpack(„VVCCvvVv”,substr($fn,0,22));

my $content = substr($fn,$ofs_content,$sz_content);

$fn{parent_ref} = unpack(„V”,substr($content,0,4));

$fn{parent_seq} = unpack(„v”,substr($content,6,2));

my ($t0,$t1) = unpack(„VV”,substr($content,8,8));

$fn{c_time} = getTime($t0,$t1);

my ($t0,$t1) = unpack(„VV”,substr($content,16,8));

$fn{m_time} = getTime($t0,$t1);

my ($t0,$t1) = unpack(„VV”,substr($content,24,8));

$fn{mft_m_time} = getTime($t0,$t1);

my ($t0,$t1) = unpack(„VV”,substr($content,32,8));

$fn{a_time} = getTime($t0,$t1);

$fn{flags} = unpack(„V”,substr($content,56,4));

$fn{len_name} = unpack(„C”,substr($content,64,1));

$fn{namespace} = unpack(„C”,substr($content,65,1));

$fn{len_name} = $fn{len_name} * 2 if ($fn{namespace} > 0);

$fn{name} = substr($content,66,$fn{len_name});

$fn{name} = cleanStr($fn{name}) if ($fn{namespace} > 0);

$fn{name} =~ s/ /g;

$fn{name} =~ s///g;

return %fn;

}

Ostatnim atrybutem, który omawiamy jest atrybut $DATA (identyfikator 0x80, czyli 128). Atrybut ten zawiera lub odnosi się do rzeczywistej zawartości pliku. Jeśli flaga nonresident w nagłówku atrybutu nie jest ustawiona, to zawartość pliku jest umieszczona w atrybucie $DATA wpisu MFT, po nagłówku i dwóch dodatkowych strukturach. Jest to ogólnie prawdziwe dla krótkich plików tekstowych, na przykład, lub innych plików mniejszych niż 700 bajtów. Jeśli dane są nierezydentne, wówczas należy przetłumaczyć „przebiegi danych”, czyli miejsca, w których dane znajdują się na dysku.

Przykładowy kod parsowania przebiegów danych atrybutu $DATA jest bardzo skomplikowany i nie został tu przedstawiony. Podobnie, kod do wyodrębniania informacji z rezydentnych atrybutów $DATA jest trywialny i polega na parsowaniu pewnych dodatkowych informacji (rozmiar zawartości i offset do zawartości) po nagłówku atrybutu.

Dostępne są pewne narzędzia open source do parsowania MFT (w szczególności atrybutów $STANDARD_INFORMATION i $FILE_NAME) i udostępniania analitykowi danych ze znacznikiem czasu. Jednym z nich jest skrypt Pythona analyzemft.py Davida Kovara, który można znaleźć w sieci pod adresem http://www.integriography.com/projects/analyzeMFT. Innym jest skrypt mft.pl Perla, z którego wyodrębniono funkcje parseSIAttr() i parseFNAttr(), dostępny w projekcie kodu Google WinForensicAnalysis, znajdującym się w sieci pod adresem http://code.google.com/p/winforensicaanalysis.

Narzędzia Briana Carriera „The SleuthKit” (TSK) są prawdopodobnie najbardziej znanymi narzędziami do zbierania szerokiej gamy informacji o systemie plików i metadanych systemu plików z przejętych obrazów, a nawet żywych systemów. Na przykład, aby zebrać listę czasów plików z atrybutem $STANDARD_INFORMATION systemu plików z pozyskanego obrazu, analityk może użyć polecenia podobnego do poniższego:

C:\tsk>fls -f ntfs -m C:/ -p -r G:\tsk.img > G:case\files\bodyfile.txt

To polecenie produkuje to, co jest znane jako „bodyfile”, który jest pośrednim formatem pliku używanym do przechowywania tych informacji przed przekształceniem ich w oś czasu aktywności systemu plików. W niektórych przypadkach, analityk może potrzebować dodać przełącznik „-o” w celu zidentyfikowania offsetu do partycji, która pojawiła się w systemie na żywo jako dysk „C:\”; ta informacja o offsecie może być określona ręcznie za pomocą edytora heksów lub przy użyciu mmls.exe.

Analityk może również zebrać te same informacje z żywego, zdalnego systemu przy użyciu F-Response. Jeśli analityk prawidłowo połączył się ze zdalnym systemem i zamontował dysk C:™ systemu jako F:™ we własnym systemie, może użyć polecenia podobnego do poniższego, aby zebrać czasy plików atrybutu $STANDARD_INFORMATION dla plików na partycji C:™:

C:™tsk>fls -f ntfs -m C:/ -p -r ™.\F: > g:\file.txt

Kompletny zestaw narzędzi TSK, wraz z dokumentacją i informacjami o użytkowaniu, można znaleźć w sieci na stronie SleuthKit Web, http://www.sleuthkit.org.

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.