mcpField
A
analyzing-slack-space-and-file-system-artifacts

analyzing-slack-space-and-file-system-artifacts

github.com/mukul975セキュリティ35.2k230 回インストール8 週間前に更新
リポジトリ

analyzing-slack-space-and-file-system-artifacts について

標準的なファイル復旧を超えて、NTFS ディスクイメージを調べるデジタルフォレンジック向けスキルです。各種フォレンジックツールを使い、スラック領域、MFT、USN ジャーナル、代替データストリームを分析します。

主な機能

  1. 01NTFSスラック領域の調査
  2. 02MFTと削除エントリの分析
  3. 03USNジャーナルの活動再構成
  4. 04代替データストリームの検出
  5. 05タイムスタンプ改ざんの確認

活用シーン

  1. 01スラック領域の残存データや隠しデータの発見
  2. 02削除ファイルのメタデータ復元
  3. 03ファイル変更や削除の経緯の再構成
  4. 04代替データストリーム内の隠しデータの特定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill analyzing-slack-space-and-file-system-artifacts

インストール後、Claude Code で/analyzing-slack-space-and-file-system-artifactsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE
references/
api-reference.md
scripts/
agent.py

詳細

スラック領域とファイルシステムアーティファクトの分析

使用する場面

  • ファイルシステムのスラック領域に隠されたデータや残存データを検索する場合
  • 削除されたファイルのメタデータを調べるため、NTFS の Master File Table(MFT)エントリを分析する場合
  • USN Change Journal からファイル操作を再構築する場合
  • データやマルウェアの隠蔽に使われる Alternate Data Streams(ADS)を検出する場合
  • 標準的なファイル復元の範囲を超える調査が必要な、詳細なフォレンジック分析を行う場合

前提条件

  • NTFS ファイルシステムを含むフォレンジックディスクイメージ
  • The Sleuth Kit(TSK)ツール:istat、icat、fls、blkls、blkstat
  • MFT 解析用の MFTECmd(Eric Zimmerman)
  • 対話型 MFT 分析用の MFTExplorer
  • NTFS 構造(MFT、$UsnJrnl、$LogFile、ADS)に関する知識
  • 自動解析用の analyzeMFT または mft ライブラリを備えた Python

ワークフロー

ステップ 1:NTFS ファイルシステムアーティファクトの特定と抽出
# Determine partition layout
mmls /cases/case-2024-001/images/evidence.dd

# Extract key NTFS system files
# $MFT - Master File Table
icat -o 2048 /cases/case-2024-001/images/evidence.dd 0 > /cases/case-2024-001/ntfs/MFT

# $UsnJrnl:$J - USN Change Journal
icat -o 2048 /cases/case-2024-001/images/evidence.dd 62-128 > /cases/case-2024-001/ntfs/UsnJrnl_J

# $LogFile - Transaction log
icat -o 2048 /cases/case-2024-001/images/evidence.dd 2 > /cases/case-2024-001/ntfs/LogFile

# Extract all slack space from the volume
blkls -s -o 2048 /cases/case-2024-001/images/evidence.dd > /cases/case-2024-001/ntfs/slack_space.raw

# Get file system information
fsstat -o 2048 /cases/case-2024-001/images/evidence.dd | tee /cases/case-2024-001/ntfs/fs_info.txt
ステップ 2:Master File Table(MFT)の分析
# Parse MFT with MFTECmd (Eric Zimmerman)
MFTECmd.exe -f "C:\cases\ntfs\MFT" --csv "C:\cases\analysis\" --csvf mft_analysis.csv

# Parse with analyzeMFT (Python)
pip install analyzeMFT

analyzeMFT.py -f /cases/case-2024-001/ntfs/MFT \
   -o /cases/case-2024-001/analysis/mft_analysis.csv \
   -c

# Custom MFT analysis with Python
python3 << 'PYEOF'
from mft import PyMft
import csv

mft = PyMft(open('/cases/case-2024-001/ntfs/MFT', 'rb').read())

deleted_files = []
suspicious_files = []

for entry in mft.entries():
    if entry is None:
        continue

    filename = entry.get_filename()
    if filename is None:
        continue

    is_deleted = not entry.is_active()
    is_directory = entry.is_directory()
    created = entry.get_created_timestamp()
    modified = entry.get_modified_timestamp()
    mft_modified = entry.get_mft_modified_timestamp()
    size = entry.get_file_size()

    # Flag deleted files for recovery
    if is_deleted and not is_directory and size > 0:
        deleted_files.append({
            'filename': filename,
            'size': size,
            'created': str(created),
            'modified': str(modified),
            'entry_number': entry.entry_number
        })

    # Detect timestomping (MFT modified time != $SI modified time)
    si_modified = entry.get_si_modified_timestamp()
    fn_modified = entry.get_fn_modified_timestamp()
    if si_modified and fn_modified:
        if abs((si_modified - fn_modified).total_seconds()) > 86400:  # >1 day difference
            suspicious_files.append({
                'filename': filename,
                'si_modified': str(si_modified),
                'fn_modified': str(fn_modified),
                'delta': str(si_modified - fn_modified)
            })

print(f"=== DELETED FILES (recoverable metadata) ===")
print(f"Total: {len(deleted_files)}")
for f in deleted_files[:20]:
    print(f"  [{f['modified']}] {f['filename']} ({f['size']} bytes)")

print(f"\n=== POTENTIAL TIMESTOMPING ===")
print(f"Total suspicious: {len(suspicious_files)}")
for f in suspicious_files[:10]:
    print(f"  {f['filename']}: $SI={f['si_modified']}, $FN={f['fn_modified']} (delta: {f['delta']})")
PYEOF
ステップ 3:隠しデータを探すためのスラック領域の分析
# Search slack space for strings
strings -a /cases/case-2024-001/ntfs/slack_space.raw > /cases/case-2024-001/analysis/slack_strings.txt

# Search for specific patterns in slack space
grep -iab "password\|secret\|confidential\|credit.card\|ssn" \
   /cases/case-2024-001/ntfs/slack_space.raw > /cases/case-2024-001/analysis/slack_keywords.txt

# Analyze individual file slack
python3 << 'PYEOF'
import struct

# File slack consists of:
# 1. RAM slack: bytes between file end and next sector boundary (filled with RAM content or zeros)
# 2. Drive slack: remaining sectors in the cluster after the last file sector

# Analyze slack for specific MFT entries
# Using Sleuth Kit to get file slack for a specific file
import subprocess

# Get file details
result = subprocess.run(
    ['istat', '-o', '2048', '/cases/case-2024-001/images/evidence.dd', '14523'],
    capture_output=True, text=True
)
print(result.stdout)

# The output shows data runs - the last cluster may contain slack data
# Calculate slack size: (allocated_size - file_size) bytes
PYEOF

# Search for file signatures in slack space (embedded files)
foremost -t jpg,pdf,zip -i /cases/case-2024-001/ntfs/slack_space.raw \
   -o /cases/case-2024-001/carved/slack_carved/

# Use bulk_extractor to find structured data in slack
bulk_extractor -o /cases/case-2024-001/analysis/bulk_extract/ \
   /cases/case-2024-001/ntfs/slack_space.raw
ステップ 4:USN Change Journal の解析
# Parse USN Journal with MFTECmd
MFTECmd.exe -f "C:\cases\ntfs\UsnJrnl_J" --csv "C:\cases\analysis\" --csvf usn_journal.csv

# Python USN Journal parsing
pip install pyusn

python3 << 'PYEOF'
import struct
import csv
from datetime import datetime, timedelta

def parse_usn_record(data, offset):
    """Parse a single USN_RECORD_V2."""
    if offset + 8 > len(data):
        return None, offset

    record_len = struct.unpack_from('<I', data, offset)[0]
    if record_len < 56 or record_len > 65536 or offset + record_len > len(data):
        return None, offset + 8

    major_ver = struct.unpack_from('<H', data, offset + 4)[0]
    if major_ver != 2:
        return None, offset + record_len

    mft_ref = struct.unpack_from('<Q', data, offset + 8)[0] & 0xFFFFFFFFFFFF
    parent_ref = struct.unpack_from('<Q', data, offset + 16)[0] & 0xFFFFFFFFFFFF
    usn = struct.unpack_from('<Q', data, offset + 24)[0]
    timestamp = struct.unpack_from('<Q', data, offset + 32)[0]
    reason = struct.unpack_from('<I', data, offset + 40)[0]
    source_info = struct.unpack_from('<I', data, offset + 44)[0]
    security_id = struct.unpack_from('<I', data, offset + 48)[0]
    file_attrs = struct.unpack_from('<I', data, offset + 52)[0]
    filename_len = struct.unpack_from('<H', data, offset + 56)[0]
    filename_off = struct.unpack_from('<H', data, offset + 58)[0]

    name = data[offset + filename_off:offset + filename_off + filename_len].decode('utf-16-le', errors='ignore')

    # Convert Windows FILETIME to datetime
    ts = datetime(1601, 1, 1) + timedelta(microseconds=timestamp // 10)

    # Decode reason flags
    reasons = []
    reason_flags = {
        0x01: 'DATA_OVERWRITE', 0x02: 'DATA_EXTEND', 0x04: 'DATA_TRUNCATION',
        0x10: 'NAMED_DATA_OVERWRITE', 0x20: 'NAMED_DATA_EXTEND',
        0x100: 'FILE_CREATE', 0x200: 'FILE_DELETE', 0x400: 'EA_CHANGE',
        0x800: 'SECURITY_CHANGE', 0x1000: 'RENAME_OLD_NAME', 0x2000: 'RENAME_NEW_NAME',
        0x4000: 'INDEXABLE_CHANGE', 0x8000: 'BASIC_INFO_CHANGE',
        0x10000: 'HARD_LINK_CHANGE', 0x20000: 'COMPRESSION_CHANGE',
        0x40000: 'ENCRYPTION_CHANGE', 0x80000: 'OBJECT_ID_CHANGE',
        0x100000: 'REPARSE_POINT_CHANGE', 0x200000: 'STREAM_CHANGE',
        0x80000000: 'CLOSE'
    }
    for flag, desc in reason_flags.items():
        if reason & flag:
            reasons.append(desc)

    record = {
        'timestamp': ts.strftime('%Y-%m-%d %H:%M:%S'),
        'filename': name,
        'mft_entry': mft_ref,
        'parent_entry': parent_ref,
        'reasons': '|'.join(reasons),
        'usn': usn
    }

    return record, offset + record_len

# Parse the journal
with open('/cases/case-2024-001/ntfs/UsnJrnl_J', 'rb') as f:
    data = f.read()

records = []
offset = 0
while offset < len(data) - 8:
    record, offset = parse_usn_record(data, offset)
    if record:
        records.append(record)
    else:
        offset += 8  # Skip zeros

# Filter for deletion events
deletions = [r for r in records if 'FILE_DELETE' in r['reasons']]
creations = [r for r in records if 'FILE_CREATE' in r['reasons']]
renames = [r for r in records if 'RENAME_NEW_NAME' in r['reasons']]

print(f"Total USN records: {len(records)}")
print(f"File creations: {len(creations)}")
print(f"File deletions: {len(deletions)}")
print(f"File renames: {len(renames)}")

print("\n=== RECENT DELETIONS ===")
for r in deletions[-20:]:
    print(f"  [{r['timestamp']}] DELETED: {r['filename']} (MFT#{r['mft_entry']})")

# Write full journal to CSV
with open('/cases/case-2024-001/analysis/usn_journal.csv', 'w', newline='') as f:
    writer = csv.DictWriter(f, fieldnames=['timestamp', 'filename', 'mft_entry', 'parent_entry', 'reasons', 'usn'])
    writer.writeheader()
    writer.writerows(records)
PYEOF
ステップ 5:Alternate Data Streams の検出と分析
# List all Alternate Data Streams in the image
find /mnt/evidence -exec getfattr -d {} \; 2>/dev/null | grep -i "ads\|zone\|stream"

# Using Sleuth Kit to find ADS
fls -r -o 2048 /cases/case-2024-001/images/evidence.dd | grep ":" | \
   tee /cases/case-2024-001/analysis/ads_list.txt

# Extract specific ADS content
# Format: icat image inode:ads_name
icat -o 2048 /cases/case-2024-001/images/evidence.dd 14523:hidden_stream \
   > /cases/case-2024-001/analysis/extracted_ads.bin

# Check Zone.Identifier streams (download origin tracking)
fls -r -o 2048 /cases/case-2024-001/images/evidence.dd | grep "Zone.Identifier" | \
   while read line; do
       inode=$(echo "$line" | awk '{print $2}' | tr -d ':')
       echo "=== $line ==="
       icat -o 2048 /cases/case-2024-001/images/evidence.dd "${inode}:Zone.Identifier" 2>/dev/null
       echo ""
   done > /cases/case-2024-001/analysis/zone_identifiers.txt

# Zone.Identifier content reveals:
# [ZoneTransfer]
# ZoneId=3          (3 = Internet, indicating file was downloaded)
# ReferrerUrl=https://malicious-site.com/payload.exe
# HostUrl=https://cdn.malicious-site.com/payload.exe

主な概念

概念説明
ファイルスラックファイルの末尾とクラスタ境界の間にある未使用領域で、残存データが含まれています
RAM スラックファイルの末尾からセクタ境界までのスラック領域の一部(歴史的には RAM の内容が書き込まれていました)
MFT($MFT)Master File Table。すべてのファイルのエントリを含む NTFS メタデータデータベースです
USN Journal($UsnJrnl)NTFS 上のすべてのファイル/ディレクトリの変更を記録する変更ジャーナルです
Alternate Data Streamsファイルごとに複数のデータストリームを許可する NTFS の機能です(隠しストレージ)
$STANDARD_INFORMATIONユーザーモードアプリケーションが変更可能なタイムスタンプを含む MFT 属性です
$FILE_NAMEカーネルのみが変更可能なタイムスタンプを含む MFT 属性です
タイムスタンプ偽装検出を回避するためにファイルのタイムスタンプを変更する、アンチフォレンジック技術です

ツールとシステム

ツール用途
MFTECmdCSV 出力に対応した Eric Zimmerman の MFT および USN Journal 解析ツールです
MFTExplorerMFT 分析用の対話型 GUI ツールです
analyzeMFTCSV/JSON 出力に対応した Python MFT パーサーです
The Sleuth Kitファイルシステムフォレンジックツールキットです(fls、icat、blkls、istat)
bulk_extractorスラック領域を含む生データから特徴を抽出します
NTFS Log Tracker$LogFile のトランザクションレコードを解析するツールです
streams.exeNTFS Alternate Data Streams を一覧表示する Sysinternals ツールです
PlasoMFT と USN Journal を解析するスーパータイムラインツールです

一般的なシナリオ

シナリオ 1:タイムスタンプ偽装によるアンチフォレンジックの検出 MFT エントリの $STANDARD_INFORMATION タイムスタンプと $FILE_NAME タイムスタンプを比較し、$SI のタイムスタンプが $FN のタイムスタンプより古いファイル(通常の操作では発生し得ません)にフラグを付けます。タイムスタンプ偽装されたファイルを意図的な改ざんの証拠として特定し、他のタイムライン上の証拠と照合します。

シナリオ 2:Alternate Data Streams 内の隠しデータ 標準の Zone.Identifier 以外の ADS がファイルに付加されていないかスキャンし、分析用に ADS の内容を抽出します。ADS に保存された隠し実行ファイルやドキュメントがないか確認し、ADS の作成時刻をユーザーアクティビティのタイムラインと照合して、証拠として所見を記録します。

シナリオ 3:MFT からの削除済みファイルの再構築 MFT を解析して非アクティブ(削除済み)エントリを探し、削除済みファイルのファイル名、サイズ、タイムスタンプを抽出します。データクラスターが上書きされていない場合は icat を使ってファイルの内容を復元し、削除された証拠ファイルの一覧を作成して、USN Journal の削除イベントと照合します。

シナリオ 4:USN Journal からのファイルアクティビティの再構築 調査対象期間の USN Change Journal を解析し、ファイルの作成、変更、名前変更、削除イベントを特定します。ファイル操作の順序を再構築し、データの集約を示す証拠(作成、コピー、圧縮、削除のパターン)を検出して、アンチフォレンジック目的のファイル消去を特定します。

出力形式

File System Artifact Analysis:
  Volume: NTFS (Partition 2, 465 GB)
  Cluster Size: 4096 bytes

  MFT Analysis:
    Total Entries: 456,789
    Active Files: 234,567
    Deleted Entries: 12,345 (8,901 with recoverable metadata)
    Timestomped Files: 23 (SI/FN mismatch detected)

  USN Journal:
    Records Parsed: 2,345,678
    Date Range: 2024-01-01 to 2024-01-20
    File Creations: 45,678
    File Deletions: 23,456
    File Renames: 12,345

  Alternate Data Streams:
    Total ADS Found: 1,234
    Zone.Identifier: 890 (downloaded files)
    Custom/Suspicious ADS: 5 (hidden data detected)

  Slack Space:
    Total Slack: 12.3 GB
    Keyword Hits: 45 (passwords, credit cards)
    Carved Files: 23 from slack space

  Suspicious Findings:
    - 23 files with timestomped timestamps
    - 5 files with hidden ADS containing data
    - USN shows mass deletion on 2024-01-18 (anti-forensics)
    - Slack space contains residual email fragments

  Reports: /cases/case-2024-001/analysis/

コメント