MFT
Den mest bemærkelsesværdige kilde til værdifulde oplysninger for en analytiker fra NTFS-filsystemet er Master File Table (MFT). Placeringen af startsektoren for MFT kan findes i diskens opstartssektor, og hver fil og mappe på disken har en post i MFT’en. Hver MFT-post er 1024 bytes stor, hvilket gør MFT’en meget enkel at analysere. Hver MFT-record, eller post, begynder med ASCII-strengen “FILE” (hvis der er en fejl i posten, begynder den med “BAAD”) og består af en eller flere (oftest flere) attributter, som hver har deres egen identifikator og struktur. Figur 4.1 illustrerer en del af en MFT-post.
De første 42 bytes af hver MFT-post omfatter en header-struktur med 12 elementer, og de resterende 982 bytes afhænger i høj grad af værdierne i headeren og de forskellige attributter, der er indeholdt i posten. Ikke alle elementer i MFT-postens header er umiddelbart anvendelige for en kriminalteknisk analytiker; figur 4.2 illustrerer dog fem af de elementer, der er umiddelbart anvendelige.
Figur 4.2. MFT-record header-elementer (i lille endiansk rækkefølge).
Som illustreret i figur 4.2 (som er en del uddraget fra figur 4.1), ser vi “FILE”-signaturen synlig i begyndelsen af posten. Dernæst ser vi sekvensnummeret eller værdien, som øges, når posten allokeres eller afallokeres. Da denne MFT-post faktisk er den første post i MFT’en og henviser til filen “$MFT”, er det logisk, at sekvensnummeret er 1. Dernæst er der link count, som henviser til antallet af mapper, der har poster for denne post (hårde links får denne værdi til at stige). Det næste er offset i posten til den første attribut; hvis du kigger på offset 0x38 i posten, vil du se, at den første attribut har en identifikator på 0x10, eller 16. Endelig ser vi flags-værdien, som fortæller os, om posten er allokeret (hvis bit 0x01 er sat), og om posten er en mappe (hvis bit 0x02 er sat). Kort sagt kan vi ud fra disse to værdier afgøre, om posten er allokeret eller slettet, og om det drejer sig om en fil eller en mappe. Når overskriften analyseres, kan pseudokode for dette repræsenteres som følger:
if ($mft{flags} & 0x0001) – allokeret; ellers uallokeret/slettet
if ($mft{flags} & 0x0002) – mappe/mappe; ellers fil
Den flag-værdi, der er synlig i figur 4.2, er “0x01”, hvilket indikerer en allokeret fil. En værdi på 0x00 ville indikere en slettet fil, og en værdi på 0x03 ville indikere en allokeret mappe.
Tip
MFT-poster
MFT-poster slettes ikke, når de er blevet oprettet; nye poster tilføjes til MFT’en efter behov, og poster for slettede filer genbruges.
Som tidligere nævnt er det kun de første 42 bytes, der er struktureret; derefter består resten af MFT-posten af et eller flere attributfelter. Der er ingen formel specifikation eller erklæring, der siger, at der skal være specifikke attributter i en MFT-post, men for det meste kan du forvente at finde en $STANDARD_INFORMATION- og en $FILE_NAME-attribut i de fleste MFT-poster. I dette afsnit ses der på disse to attributter, da de giver oplysninger om tidsstempel, som er værdifulde for retsmedicinske analytikere. Vi vil også tage et kort kig på $DATA-attributten og lade de resterende attributter være en øvelse for den interesserede og nysgerrige læser.
Hovedteksten for hver attribut indeholder en 16-byte-hovedtekst, som bl.a. identificerer attributtens type, attributtens samlede længde og om attributten er resident i MFT-posten eller ej.
Note
MFT-metadatafiler
De første 16 poster i MFT’en indeholder oplysninger om metadatafiler; de kan dog ikke alle anvendes. De, der ikke bruges, bliver efterladt i en allokeret tilstand og indeholder kun grundlæggende oplysninger.
Ved hjælp af disse headeroplysninger kan vi analysere MFT-posten og udtrække værdifulde oplysninger fra hver enkelt attribut. F.eks. findes attributten $STANDARD_INFORMATION (som altid er resident) for hver fil og mappepost og har en identifikator på 0x10 (dvs. 16). Denne attribut indeholder filtidspunkterne for MFT-posten (i hvert fald tre af dem), som vi ser, når vi skriver “dir” på kommandoprompten; den ændrede tid, sidste adgangstidspunkt og oprettelsesdatoen (født) for filen eller mappen, også kaldet “MAC”-tidspunkter. Attributten indeholder en fjerde tidsværdi, der angiver det sidste tidspunkt, hvor MFT-posten sidst blev ændret. Tilsammen kaldes disse tidspunkter for “MACE”- (hvor “E” henviser til ændringstidspunktet for MFT-posten) eller “MACB”- (hvor “C” henviser til ændringstidspunktet for MFT-posten) tidspunkter.
Varsling
Filtidspunkter
NTFS-filtidspunkter registreres i UTC-format (Universal Coordinated Time), som svarer til Greenwich Mean Time. Dette gælder for alle tidspunkter; i hver MFT-post vil en filoptegnelse sandsynligvis have mindst 8 tidspunkter tilknyttet; mange gange 12 eller flere. På FAT-filsystemet vedligeholdes filtider i det lokale systemtidsformat.
Attributten $FILE_NAME (identifikator 0x30, eller 48) findes også med de fleste MFT-poster for filer og mapper; faktisk vil mange MFT-poster have mere end én $FILE_NAME-attribut. Ligesom attributten $STANDARD_INFORMATION er denne attribut altid resident og indeholder også fire tidsværdier; disse tidsværdier er dog normalt indstillet, når filen oprettes på systemet. I modsætning til filtider i attributten $STANDARD_INFORMATION påvirkes disse filtider ikke af normal systemaktivitet eller ondsindet manipulation, og de kan derfor bruges til at bestemme indikatorer for skadelig aktivitet, og der kan tages skridt til at sløre det tidspunkt, hvor et system blev inficeret. Følgende kodeeksempel (funktionen parseSIAttr()) giver et eksempel på, hvordan attributten $STANDARD_INFORMATION kan analyseres:
sub parseSIAttr {
my $si = shift;
my %si;
my ($type,$len,$res,$name_len,$name_ofs,$flags,$id,$sz_content,$ofs_content)
= unpack(“VVCCvvvvvVVv”,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;
}
Tip
GetTime
Funktionen getTime(), der ses i kodelisten for attributten parseSIAttr(), der netop er givet, består af kode lånt fra Andreas Schuster, der oversætter 64-bit FILETIME-objektets tidsstempler til en 32-bit Unix-tid, der kan oversættes yderligere til en menneskeligt læsbar tid via den indbyggede gmtime()-funktion i Perl. Denne kode ser ud som følger:
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;
}
Denne kode er meget nyttig til parsing og oversættelse af ethvert FILETIME-objekt, uanset hvorfra det er udtrukket.
På et normalt system kan mange MFT-poster have to $FILE_NAME-attributter: en til at indeholde det fulde navn på filen (eller mappen) og en til at indeholde DOS, 8.3-filnavnet. Hvis en fil f.eks. hedder “myreallylongfile.txt”, vil filnavnet i 8.3 blive vist som “myreal~1.txt”. Dette er bevaret af hensyn til kompatibilitet med ældre filsystemer og dem, der ikke understøtter lange filnavne. Så det er ikke usædvanligt på et normalt Windows-system at have en række MFT-poster med to $FILE_NAME-attributter med næsten identisk indhold. Følgende kodeeksempel (funktionen parseFNAttr()) giver et eksempel på, hvordan en $FILE_NAME-attribut fra en MFT-post kan analyseres og tilgængelige data udtrækkes:
sub parseFNAttr {
my $fn = shift;
my %fn;
my ($type,$len,$res,$name_len,$name_ofs,$flags,$id,$sz_content,$ofs_content)
= unpack(“VVCCvvvvvvVv”,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} = udpakning(“V”,substr($content,56,4));
$fn{len_name} = udpakning(“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/\x0c/\x2e/g;
$fn{name} =~ s////g;
return %fn;
}
Den sidste attribut, vi diskuterer, er $DATA-attributten (identifikator 0x80, eller 128). Denne attribut indeholder eller henviser til det faktiske indhold af filen. Hvis nonresident-flaget i attributhovedet ikke er sat, er filens indhold resident i $DATA-attributten i MFT-posten, efter hovedet og to yderligere strukturer. Dette gælder generelt for f.eks. korte tekstfiler eller andre filer på mindre end 700 bytes. Hvis data er ikke-residente, skal “datakørsler”, eller hvor data er placeret på disken, oversættes.
Eksempelkode til parsing af datakørsler i $DATA-attributten er meget omfattende og præsenteres ikke her. På samme måde er kode til udtrækning af oplysninger fra residente $DATA-attributter triviel og består af parsing af nogle yderligere oplysninger (størrelse af indhold og offset til indhold) efter attributhovedet.
Der findes nogle open source-værktøjer til parsing af MFT (specifikt $STANDARD_INFORMATION og $FILE_NAME-attributter) og til at gøre tidsstemplede data tilgængelige for analytikeren. Et af dem er David Kovars analyzemft.py Python-script, som findes på nettet på http://www.integriography.com/projects/analyzeMFT. Et andet er mft.pl Perl-scriptet, hvorfra funktionerne parseSIAttr() og parseFNAttr() blev uddraget, og som er tilgængeligt i WinForensicAnalysis Google Code projected, der findes på nettet på http://code.google.com/p/winforensicaanalysis.
Brian Carriers “The SleuthKit” (TSK)-værktøjer er nok de mest kendte værktøjer til indsamling af en lang række filsystem- og filsystemmetadataoplysninger fra erhvervede billeder og endda live-systemer. For eksempel kan en analytiker for at indsamle en liste over filsystemets $STANDARD_INFORMATION-attributfiltider fra et erhvervet billede bruge en kommando svarende til følgende:
C:\tsk>fls -f ntfs -m C:/ -p -r G:\case\xp.img > G:\case\files\bodyfile.txt
Denne kommando producerer det, der er kendt som en “bodyfile”, som er et mellemliggende filformat, der bruges til at gemme disse oplysninger, før de konverteres til en tidslinje for filsystemaktivitet. I nogle tilfælde kan analytikeren være nødt til at tilføje “-o”-skiftet for at identificere offset til den partition, der på det levende system optrådte som “C:\”-drevet; denne offset-information kan bestemmes manuelt via en hex-editor eller ved hjælp af mmls.exe.
En analytiker kan også indsamle de samme oplysninger fra et levende, fjerntliggende system ved hjælp af F-Response. Hvis analytikeren har oprettet en korrekt forbindelse til fjernsystemet og har monteret systemets C:\-drev som F:\ på sit eget system, kan han/hun derefter bruge en kommando svarende til følgende for at indsamle $STANDARD_INFORMATION-attributfiltider for filerne i C:\-partitionen:
C:\tsk>fls -f ntfs -m C:/ -p -r \\.\F: > g:\case\files\bodyfile.txt
Det komplette sæt TSK-værktøjer samt dokumentation og oplysninger om brug kan findes på nettet på SleuthKit-webstedet, http://www.sleuthkit.org.