L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Productivité · SKILL.md

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

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

检查文件系统松弛空间(slack space)、MFT 条目、USN 日志和备用数据流,以恢复 NTFS 卷上的隐藏数据并重建文件活动。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: analyzing-slack-space-and-file-system-artifacts description: 检查文件系统松弛空间(slack space)、MFT 条目、USN 日志和备用数据流,以恢复 NTFS 卷上的隐藏数据并重建文件活动。 domain: cybersecurity subdomain: digital-forensics tags: [forensics, slack-space, ntfs, mft, usn-journal, alternate-data-streams, file-system-analysis] version: "1.0" author: mahipal license: Apache-2.0

分析松弛空间和文件系统制品

适用场景

  • 在文件系统松弛空间中搜索隐藏或残留数据
  • 分析 NTFS 主文件表(MFT)条目以获取已删除文件的元数据
  • 从 USN 变更日志重建文件操作
  • 检测用于隐藏数据或恶意软件的备用数据流(ADS)
  • 在深度取证分析中检查标准文件恢复以外的内容

前置条件

  • 含 NTFS 文件系统的取证磁盘镜像
  • The Sleuth Kit(TSK)工具集:istat、icat、fls、blkls、blkstat
  • MFTECmd(Eric Zimmerman)用于 MFT 解析
  • MFTExplorer 用于交互式 MFT 分析
  • 熟悉 NTFS 结构(MFT、$UsnJrnl、$LogFile、ADS)
  • Python 及 analyzeMFT 或 mft 库用于自动化解析

工作流程

步骤 1:识别并提取 NTFS 文件系统制品

# 确定分区布局
mmls /cases/case-2024-001/images/evidence.dd

# 提取关键 NTFS 系统文件
# $MFT - 主文件表
icat -o 2048 /cases/case-2024-001/images/evidence.dd 0 > /cases/case-2024-001/ntfs/MFT

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

# $LogFile - 事务日志
icat -o 2048 /cases/case-2024-001/images/evidence.dd 2 > /cases/case-2024-001/ntfs/LogFile

# 从卷中提取所有松弛空间
blkls -s -o 2048 /cases/case-2024-001/images/evidence.dd > /cases/case-2024-001/ntfs/slack_space.raw

# 获取文件系统信息
fsstat -o 2048 /cases/case-2024-001/images/evidence.dd | tee /cases/case-2024-001/ntfs/fs_info.txt

步骤 2:分析主文件表(MFT)

# 使用 MFTECmd(Eric Zimmerman)解析 MFT
MFTECmd.exe -f "C:\cases\ntfs\MFT" --csv "C:\cases\analysis\" --csvf mft_analysis.csv

# 使用 analyzeMFT(Python)解析
pip install analyzeMFT

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

# 使用 Python 自定义 MFT 分析
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()

    # 标记已删除文件以供恢复
    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
        })

    # 检测时间戳篡改(MFT 修改时间 != $SI 修改时间)
    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 天差异
            suspicious_files.append({
                'filename': filename,
                'si_modified': str(si_modified),
                'fn_modified': str(fn_modified),
                'delta': str(si_modified - fn_modified)
            })

print(f"=== 已删除文件(可恢复元数据)===")
print(f"总计: {len(deleted_files)}")
for f in deleted_files[:20]:
    print(f"  [{f['modified']}] {f['filename']} ({f['size']} 字节)")

print(f"\n=== 潜在时间戳篡改 ===")
print(f"可疑文件总计: {len(suspicious_files)}")
for f in suspicious_files[:10]:
    print(f"  {f['filename']}: $SI={f['si_modified']}, $FN={f['fn_modified']} (差值: {f['delta']})")
PYEOF

步骤 3:分析松弛空间中的隐藏数据

# 从松弛空间提取字符串
strings -a /cases/case-2024-001/ntfs/slack_space.raw > /cases/case-2024-001/analysis/slack_strings.txt

# 在松弛空间中搜索特定模式
grep -iab "password\|secret\|confidential\|credit.card\|ssn" \
   /cases/case-2024-001/ntfs/slack_space.raw > /cases/case-2024-001/analysis/slack_keywords.txt

# 分析单个文件的松弛空间
python3 << 'PYEOF'
import struct

# 文件松弛空间由以下部分组成:
# 1. RAM 松弛:文件末尾到下一扇区边界之间的字节(历史上填充 RAM 内容或零)
# 2. 驱动器松弛:文件最后扇区之后,簇中剩余的扇区

# 分析特定 MFT 条目的松弛空间
# 使用 Sleuth Kit 获取特定文件的松弛空间
import subprocess

# 获取文件详情
result = subprocess.run(
    ['istat', '-o', '2048', '/cases/case-2024-001/images/evidence.dd', '14523'],
    capture_output=True, text=True
)
print(result.stdout)

# 输出显示数据运行 - 最后一个簇可能包含松弛数据
# 计算松弛大小:(已分配大小 - 文件大小) 字节
PYEOF

# 在松弛空间中搜索文件签名(嵌入文件)
foremost -t jpg,pdf,zip -i /cases/case-2024-001/ntfs/slack_space.raw \
   -o /cases/case-2024-001/carved/slack_carved/

# 使用 bulk_extractor 在松弛空间中查找结构化数据
bulk_extractor -o /cases/case-2024-001/analysis/bulk_extract/ \
   /cases/case-2024-001/ntfs/slack_space.raw

步骤 4:解析 USN 变更日志

# 使用 MFTECmd 解析 USN 日志
MFTECmd.exe -f "C:\cases\ntfs\UsnJrnl_J" --csv "C:\cases\analysis\" --csvf usn_journal.csv

# Python USN 日志解析
pip install pyusn

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

def parse_usn_record(data, offset):
    """解析单个 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')

    # 将 Windows FILETIME 转换为 datetime
    ts = datetime(1601, 1, 1) + timedelta(microseconds=timestamp // 10)

    # 解码原因标志
    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

# 解析日志
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  # 跳过零字节

# 过滤删除事件
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"USN 记录总数: {len(records)}")
print(f"文件创建: {len(creations)}")
print(f"文件删除: {len(deletions)}")
print(f"文件重命名: {len(renames)}")

print("\n=== 最近删除 ===")
for r in deletions[-20:]:
    print(f"  [{r['timestamp']}] 已删除: {r['filename']} (MFT#{r['mft_entry']})")

# 将完整日志写入 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:检测和分析备用数据流

# 列出镜像中所有备用数据流
find /mnt/evidence -exec getfattr -d {} \; 2>/dev/null | grep -i "ads\|zone\|stream"

# 使用 Sleuth Kit 查找 ADS
fls -r -o 2048 /cases/case-2024-001/images/evidence.dd | grep ":" | \
   tee /cases/case-2024-001/analysis/ads_list.txt

# 提取特定 ADS 内容
# 格式:icat 镜像 inode:ads名称
icat -o 2048 /cases/case-2024-001/images/evidence.dd 14523:hidden_stream \
   > /cases/case-2024-001/analysis/extracted_ads.bin

# 检查 Zone.Identifier 数据流(下载来源追踪)
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 内容揭示:
# [ZoneTransfer]
# ZoneId=3          (3 = Internet,表示文件已下载)
# ReferrerUrl=https://malicious-site.com/payload.exe
# HostUrl=https://cdn.malicious-site.com/payload.exe

核心概念

概念描述
文件松弛空间(File slack)文件末尾与簇边界之间包含残留数据的未使用空间
RAM 松弛(RAM slack)从文件末尾到扇区边界的松弛空间部分(历史上填充 RAM 内容)
MFT($MFT)主文件表——每个文件都有条目的 NTFS 元数据数据库
USN 日志($UsnJrnl)记录 NTFS 上所有文件/目录修改的变更日志
备用数据流(Alternate Data Streams)NTFS 功能,允许每个文件有多个数据流(用于隐藏存储)
$STANDARD_INFORMATIONMFT 属性,包含用户态应用程序可修改的时间戳
$FILE_NAMEMFT 属性,包含仅内核可修改的时间戳
时间戳篡改(Timestomping)修改文件时间戳以逃避检测的反取证技术

工具与系统

工具用途
MFTECmdEric Zimmerman 的 MFT 和 USN 日志解析器,支持 CSV 输出
MFTExplorer用于 MFT 分析的交互式 GUI 工具
analyzeMFT支持 CSV/JSON 输出的 Python MFT 解析器
The Sleuth Kit文件系统取证工具集(fls、icat、blkls、istat)
bulk_extractor从原始数据(包括松弛空间)中提取特征
NTFS Log Tracker用于解析 $LogFile 事务记录的工具
streams.exe用于列出 NTFS 备用数据流的 Sysinternals 工具
Plaso解析 MFT 和 USN 日志的超级时间线工具

常见场景

场景 1:通过时间戳篡改检测反取证 将 MFT 条目中的 $STANDARD_INFORMATION 时间戳与 $FILE_NAME 时间戳进行比较,标记 $SI 时间戳早于 $FN 时间戳的文件(正常操作中不可能发生),将时间戳被篡改的文件识别为故意操纵的证据,与其他时间线证据相关联。

场景 2:备用数据流中的隐藏数据 扫描附加到文件上超出标准 Zone.Identifier 的 ADS,提取 ADS 内容进行分析,检查存储在 ADS 中的隐藏可执行文件或文档,将 ADS 创建与用户活动时间线相关联,记录调查结果作为证据。

场景 3:从 MFT 重建已删除文件 解析 MFT 中的非活动(已删除)条目,提取已删除文件的文件名、大小和时间戳,如果数据簇未被覆盖则使用 icat 恢复文件内容,建立已删除证据文件列表,与 USN 日志删除事件相关联。

场景 4:从 USN 日志重建文件活动 解析调查时段的 USN 变更日志,识别文件创建、修改、重命名和删除事件,重建文件操作序列,检测数据暂存证据(创建、复制、压缩、删除模式),识别反取证文件擦除。

输出格式

文件系统制品分析:
  卷: NTFS(分区 2,465 GB)
  簇大小: 4096 字节

  MFT 分析:
    条目总数: 456,789
    活动文件: 234,567
    已删除条目: 12,345(8,901 个含可恢复元数据)
    时间戳被篡改文件: 23(检测到 SI/FN 不匹配)

  USN 日志:
    已解析记录: 2,345,678
    日期范围: 2024-01-01 至 2024-01-20
    文件创建: 45,678
    文件删除: 23,456
    文件重命名: 12,345

  备用数据流:
    发现 ADS 总数: 1,234
    Zone.Identifier: 890(已下载文件)
    自定义/可疑 ADS: 5(检测到隐藏数据)

  松弛空间:
    总松弛空间: 12.3 GB
    关键词命中: 45(密码、信用卡)
    从松弛空间雕刻文件: 23

  可疑发现:
    - 23 个文件含被篡改的时间戳
    - 5 个文件含隐藏 ADS 数据
    - USN 显示 2024-01-18 存在大量删除(反取证)
    - 松弛空间含残留邮件片段

  报告: /cases/case-2024-001/analysis/
Skills enregistrées