すべての NTFS ファイルはその内容を保持する $DATA 属性(タイプ 0x80)を持ちます。ほとんどのファイルでは、$DATA は非レジデントです。属性ヘッダはボリューム上の他の場所のクラスタランを指すランリストを保持しています。小さなファイルでは、バイトは MFT レコード自体にインラインで存在します。その後者のケースは、NTFS フォレンジックで最も有用なアーティファクトの 1 つであり、アナリストが忘れ続けるのを私が見続けているケースでもあります。
どれくらい小さければ十分か
MFT レコードは 1,024 バイトです。そこから 56 バイトのヘッダ、fixup 配列、$STANDARD_INFORMATION(約 72 バイト)、少なくとも 1 つの $FILE_NAME(可変、典型的な名前で約 90 バイト)、パディング、属性終了センチネルを差し引きます。残りが、レジデント $DATA と他のレジデント属性のための使用可能な予算です。
実務上、しきい値は 約 700 バイト のデータです。一部の参考資料はとても短い名前で他のレジデント属性がないファイルでは最大 750 バイト程度と述べ、より長い名前または追加属性のあるファイルでは最低 580 バイト程度と述べています。しきい値は定数ではなく、レコード内の他の要素に依存します。
私が常に見る、収まるファイル。
- 小さなテキストファイル。メモ、TODO リスト、スクラッチドラフト。
- 小さな構成ファイル。
.ini、.cfg、小さな.json、小さな.xml。 - PowerShell ワンライナーと短いスクリプト。
- 小さな
.lnkショートカットファイル(ほとんどの LNK は十分小さい。彼らがエンコードする内容については LNK forensics を参照)。 - レジストリエクスポートのスニペットと
.regファイル。 - 小さな
.batと.cmdファイル。 - 短い PEM 形式の証明書ファイル。
- 空のファイルと 0 バイトのプレースホルダ。「データ」は 0 バイトで、
$DATAは自明にレジデントです。 - 多くの小さなディレクトリの
$INDEX_ROOT属性。
なぜこれが重要か
レジデント $DATA 属性は、ディスクの残りを読まずに回復できます。$MFT のコピーがあれば、すでに次が得られています。
- 小さなテキストファイルの完全な内容。
- ディレクトリ用の多くの
$INDEX_ROOTデータ(ディレクトリのエントリ、インラインリスト)。 - 短い代替データストリーム(小さな内容を持つ名前付き
$DATA属性)。 - リパースポイントと symlink ターゲット(ターゲットパスは
$REPARSE_POINTに存在し、これも通常はレジデント)。
これは、単一の 200 MB から 2 GB の MFT 抽出内にある証拠の量としては驚くべきものです。削除された小さなファイルの場合、データ領域が上書きされてもレジデントバイトは生き残ります。データ領域はそもそも触れられていません。バイトは MFT 内に存在しました。
私は次のものを回復したことがあります。
- データクラスタが存在しなかった、削除済みレコードからの 320 バイトの PowerShell ローダー。
- 取得の 3 週間前に削除された、攻撃者のステージングディレクトリを指す 480 バイトの
.lnk。 - アンインストールされたサービスからの 700 バイトの
.config。ディレクトリはなくなっていましたが、MFT レコードはスロット 412,000 に手付かずで座っていました。
MFT はそれらのファイルが依然として存在する唯一の場所でした。
レジデントは安定していない
レジデントファイルがレコードの空きスペースを超えて成長すると、NTFS は非レジデントに変換します。データはクラスタに移動し、$DATA はランリストになります。変換は変更が起こると $LogFile にログされます。
逆も技術的には起こり得ます(しきい値を下回って縮小したファイルが再びレジデントになる)が、Windows がそれを自発的に行うことはまれです。一度 $DATA が非レジデントになると、そのままになる傾向があります。かつて大きかったとわかっているファイルのレジデント $DATA を持つレコードを見つけたら、それは異常で調査の価値があります。意図的な操作か、ファイルをその場で縮小した一般的でないコードパスを示唆します。
解析中のレジデントデータ検出
すべての MFT パーサは $DATA 属性ヘッダで「レジデント」フラグを公開します。MFTECmd の CSV 出力はそれをブール列として持ちます。mft_dump の JSON には header.is_resident があります。libmft は属性オブジェクトで公開します。Sleuth Kit の istat は属性リストの一部としてそれを示します。
このサイトのブラウザパーサは、IN_USE=0 でレジデント $DATA を持つものを 2 クリックでフィルタします。そのフィルタは、小さなファイル回復が重要な抽出された MFT に対して最初に実行するものです。
バイトはどう見えるか
レジデント $DATA の場合、属性ヘッダの後に 16 バイトのレジデントヘッダ(コンテンツサイズ、コンテンツオフセット、indexed フラグ、パディング)、そして生のバイトが続きます。バイトは、ファイルがディスク上で持っていたものと正確に同じです。ファイルが使用したエンコーディングでのテキスト、ネイティブ形式のバイナリ内容です。変換はありません。
UTF-8 の小さなテキストファイルの場合、バイトをコピーアウトして任意のエディタでファイルを読めます。バイナリ内容(小さな PE、コンパイル済み .pyc、シリアル化されたオブジェクト)の場合、バイトは同様に使用可能で、ボリュームから抽出されたファイルとして扱います。
限界
ほとんどのファイルはレジデントではありません。 通常の Windows インストールでは、ユーザーファイルの 5% 未満がレジデントです。残りは Office 関連のすべて、すべてのブラウザキャッシュファイル、\Program Files\ のすべてのプログラム、すべてのダウンロードです。レジデント回復は高価値なニッチであり、デフォルトモードではありません。
しきい値は正確ではありません。 「700 バイト未満のファイルは回復可能」と仮定しないでください。実際のしきい値はレコードの他の属性に依存します。分析している特定の MFT でテストしてください。
レジデントは、十分大きなファイルへの圧縮や暗号化を生き延びません。 EFS で暗号化されたファイルは暗号化メタデータに $LOGGED_UTILITY_STREAM を使用し、$DATA は暗号文です。暗号文がレジデントになるくらい小さい場合、暗号化されたバイトは得られますが、読むには依然として EFS キーが必要です。
これを使うワークフロー
次に削除されたファイルの回復ケースがあり、気にしているファイルが小さい場合。
- ホスト(または最近のものがあれば VSS スナップショット)から
$MFTを取得します。 - 解析します。
IN_USE=0でプライマリ$DATAがレジデントのすべてのレコードを取得します。 - ファイル名がわかっている場合、
$FILE_NAMEの正規表現でフィルタします。ディレクトリがわかっている場合、親参照でフィルタします。 - レジデント
$DATAバイトをインラインで検査します。ファイルはまさにそこにあります。
シグネチャカービングなら数時間かかり、小さな断片化ファイルではおそらく失敗していたであろう回復に対して、5 分の作業です。
参考資料
- linux-ntfs プロジェクトの レジデント属性のメモ。レジデントヘッダレイアウトの明瞭な説明です。
- Microsoft, NTFS allocation algorithm。レジデント/非レジデント決定がどのように行われるかの公式リファレンス。
- Sleuth Kit の
istat。個別レコードを検査し、コンテキスト内でレジデントフラグを見るために。