Communitygithub.com

Windows LNKファイル解析による証拠抽出

Windows LNKショートカットファイルを解析し、ターゲットパス、MACタイムスタンプなどを抽出します。

Windows LNKファイル解析による証拠抽出 とは?

このスキルは、Windows LNKファイル(ショートカット)を解析して、ファイルアクセス履歴の復元、リムーバブルメディアやネットワーク共有の追跡、フォレンジック調査における証拠収集を行うための実践的な手順を提供します。LECmdやLnkParse3などのツールを用いて、ターゲットファイルのパス、作成・変更・アクセス日時、ボリュームシリアル番号、マシンID、MACアドレスなどの豊富なメタデータを抽出できます。抽出結果はCSVに出力し、USBメモリからのデータ持ち出しやスタートアップフォルダの不正なショートカット(永続化)、ネットワーク共有への不正アクセスなど、様々な調査シナリオに活用できます。このスキルは、Claude CodeやCursor、CodexなどのAIエージェント環境で、フォレンジックイメージから直接LNKファイルを収集・解析する一連のワークフローを実行可能にします。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/analyzing-windows-lnk-files-for-artifacts

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Windows LNKファイル解析による証拠抽出 は何をしますか?

使用タイミング

  • Windowsショートカットファイルからユーザーのファイルアクセス履歴を復元する場合
  • アクセスされたファイル、ネットワーク共有、リムーバブルメディアを追跡する場合
  • 特定のドキュメントをユーザーが開いたことを証明する調査時
  • ファイルアクセスを他のタイムライン証拠と関連付ける場合
  • リモートシステムやUSBデバイス上のアクセスされたパスを特定する場合

前提条件

  • フォレンジックイメージからLNKファイルへのアクセス権(Recent、Desktop、Quick Launch)
  • LECmd(Eric Zimmerman)、python-lnk、またはLnkParser(解析ツール)
  • LNKファイル構造(Shell Link Binary形式)に関する理解
  • Windowsシステム上のLNKファイル保存場所に関する知識
  • 解析ツールがインストールされたフォレンジックワークステーション

ワークフロー

ステップ1: フォレンジックイメージからLNKファイルを収集

# フォレンジックイメージをマウント
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence

mkdir -p /cases/case-2024-001/lnk/{recent,desktop,startup,custom}

# RecentアイテムのLNKファイルをコピー(一次ソース)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/*.lnk \
   /cases/case-2024-001/lnk/recent/ 2>/dev/null

# 自動保存先(ジャンプリスト)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/AutomaticDestinations/*.automaticDestinations-ms \
   /cases/case-2024-001/lnk/recent/ 2>/dev/null

# カスタム保存先(ピン留めされたジャンプリストアイテム)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/CustomDestinations/*.customDestinations-ms \
   /cases/case-2024-001/lnk/custom/ 2>/dev/null

# デスクトップショートカット
cp /mnt/evidence/Users/*/Desktop/*.lnk /cases/case-2024-001/lnk/desktop/ 2>/dev/null

# スタートアップフォルダのショートカット(永続化)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Start\ Menu/Programs/Startup/*.lnk \
   /cases/case-2024-001/lnk/startup/ 2>/dev/null
cp "/mnt/evidence/ProgramData/Microsoft/Windows/Start Menu/Programs/Startup"/*.lnk \
   /cases/case-2024-001/lnk/startup/ 2>/dev/null

# システム上のすべてのLNKファイルを検索
find /mnt/evidence/ -name "*.lnk" -type f 2>/dev/null > /cases/case-2024-001/lnk/all_lnk_locations.txt

# カウントとハッシュ化
ls /cases/case-2024-001/lnk/recent/ | wc -l
sha256sum /cases/case-2024-001/lnk/recent/*.lnk > /cases/case-2024-001/lnk/lnk_hashes.txt 2>/dev/null

ステップ2: LECmdでLNKファイルを解析

# Eric ZimmermanのLECmdを使用(WindowsまたはMono経由)
# ディレクトリ内のすべてのLNKファイルを処理
LECmd.exe -d "C:\cases\lnk\recent" --csv "C:\cases\analysis" --csvf lnk_analysis.csv

# 単一のLNKファイルを冗長出力で処理
LECmd.exe -f "C:\cases\lnk\recent\document.pdf.lnk"

# ジャンプリストファイルを処理
JLECmd.exe -d "C:\cases\lnk\recent" --csv "C:\cases\analysis" --csvf jumplist_analysis.csv

# 出力に含まれる情報:
# - ソースファイルパス
# - ターゲットパス(アクセスされたファイル)
# - ターゲットの作成、変更、アクセスタイムスタンプ
# - LNKの作成、変更タイムスタンプ
# - 作業ディレクトリ
# - コマンドライン引数
# - ボリュームシリアル番号とラベル
# - ドライブタイプ(固定、リムーバブル、ネットワーク)
# - マシンID(NetBIOS名)
# - MACアドレス(トラッカーデータベースから)
# - ターゲットファイルのサイズ

ステップ3: PythonでLNKファイルを解析

pip install LnkParse3

python3 << 'PYEOF'
import LnkParse3
import os, json, csv
from datetime import datetime

lnk_dir = '/cases/case-2024-001/lnk/recent/'
results = []

for filename in sorted(os.listdir(lnk_dir)):
    if not filename.lower().endswith('.lnk'):
        continue

    filepath = os.path.join(lnk_dir, filename)
    try:
        with open(filepath, 'rb') as f:
            lnk = LnkParse3.lnk_file(f)
            info = lnk.get_json()

            parsed = {
                'lnk_file': filename,
                'target_path': '',
                'working_dir': '',
                'arguments': '',
                'target_created': '',
                'target_modified': '',
                'target_accessed': '',
                'file_size': '',
                'drive_type': '',
                'volume_serial': '',
                'volume_label': '',
                'machine_id': '',
                'mac_address': '',
            }

            # ヘッダーのタイムスタンプを抽出
            header = info.get('header', {})
            parsed['target_created'] = str(header.get('creation_time', ''))
            parsed['target_modified'] = str(header.get('modified_time', ''))
            parsed['target_accessed'] = str(header.get('accessed_time', ''))
            parsed['file_size'] = str(header.get('file_size', ''))

            # リンク情報を抽出
            link_info = info.get('link_info', {})
            if link_info:
                local_path = link_info.get('local_base_path', '')
                network_path = link_info.get('common_network_relative_link', {}).get('net_name', '')
                parsed['target_path'] = local_path or network_path

                vol_info = link_info.get('volume_id', {})
                if vol_info:
                    parsed['drive_type'] = str(vol_info.get('drive_type', ''))
                    parsed['volume_serial'] = str(vol_info.get('drive_serial_number', ''))
                    parsed['volume_label'] = str(vol_info.get('volume_label', ''))

            # 文字列データを抽出
            string_data = info.get('string_data', {})
            parsed['working_dir'] = str(string_data.get('working_dir', ''))
            parsed['arguments'] = str(string_data.get('command_line_arguments', ''))

            # トラッカーデータ(マシンIDとMAC)を抽出
            extra = info.get('extra', {})
            tracker = extra.get('DISTRIBUTED_LINK_TRACKER_BLOCK', {})
            if tracker:
                parsed['machine_id'] = str(tracker.get('machine_id', ''))
                parsed['mac_address'] = str(tracker.get('mac_address', ''))

            results.append(parsed)

            # サマリーを表示
            print(f"\n{filename}")
            print(f"  ターゲット: {parsed['target_path']}")
            print(f"  更新日時: {parsed['target_modified']}")
            print(f"  ドライブ: {parsed['drive_type']} (シリアル: {parsed['volume_serial']})")
            if parsed['machine_id']:
                print(f"  マシン: {parsed['machine_id']}")

    except Exception as e:
        print(f"  解析エラー {filename}: {e}")

# 結果をCSVに出力
with open('/cases/case-2024-001/analysis/lnk_analysis.csv', 'w', newline='') as f:
    writer = csv.DictWriter(f, fieldnames=results[0].keys() if results else [])
    writer.writeheader()
    writer.writerows(results)

print(f"\n\n解析されたLNKファイルの総数: {len(results)}")
PYEOF

ステップ4: 調査価値の分析

# リムーバブルメディアからアクセスされたファイルを特定
python3 << 'PYEOF'
import csv

with open('/cases/case-2024-001/analysis/lnk_analysis.csv') as f:
    reader = csv.DictReader(f)

    print("=== リムーバブルメディアからアクセスされたファイル ===\n")
    removable = []
    network = []

    for row in reader:
        if 'DRIVE_REMOVABLE' in row.get('drive_type', '').upper() or \
           'removable' in row.get('drive_type', '').lower():
            removable.append(row)
            print(f"  {row['target_modified']} | {row['target_path']} | ボリューム: {row['volume_serial']}")

        if 'network' in row.get('drive_type', '').lower() or \
           row.get('target_path', '').startswith('\\\\'):
            network.append(row)

    print(f"\n=== ネットワーク共有からアクセスされたファイル ===\n")
    for row in network:
        print(f"  {row['target_modified']} | {row['target_path']}")

    print(f"\nリムーバブルメディアのファイル: {len(removable)}")
    print(f"ネットワーク共有のファイル: {len(network)}")

    # ユニークなマシンを確認(トラッカーデータ)
    machines = set()
    for row in [*removable, *network]:
        if row.get('machine_id'):
            machines.add(row['machine_id'])
    if machines:
        print(f"\n検出されたマシンID: {machines}")
PYEOF

# スタートアップフォルダのLNKファイル(永続化)を確認
echo "=== スタートアップフォルダのショートカット(永続化) ===" > /cases/case-2024-001/analysis/startup_persistence.txt
for lnk in /cases/case-2024-001/lnk/startup/*.lnk; do
    python3 -c "
import LnkParse3
with open('$lnk', 'rb') as f:
    lnk = LnkParse3.lnk_file(f)
    info = lnk.get_json()
    target = info.get('link_info', {}).get('local_base_path', 'Unknown')
    args = info.get('string_data', {}).get('command_line_arguments', '')
    print(f'  \$(basename $lnk): {target} {args}')
" >> /cases/case-2024-001/analysis/startup_persistence.txt 2>/dev/null
done

主要概念

概念説明
Shell Link (.lnk)ターゲットパス、タイムスタンプ、メタデータを含むWindowsショートカットファイル形式
ターゲットタイムスタンプショートカットが指すファイルの作成、変更、アクセス時刻
ボリュームシリアル番号ターゲットファイルが存在するドライブボリュームの一意の識別子
マシンID分散リンクトラッキングサービスによって埋め込まれたNetBIOS名
MACアドレスLNKファイルを作成したマシンのネットワークアダプタMAC
ジャンプリストアプリケーションごとの最近開いたファイルとピン留めされたファイルのリスト(埋め込みLNKデータを含む)
自動保存先最近開いたファイルのシステム管理ジャンプリストエントリ
カスタム保存先ユーザーがピン留めしたジャンプリストアイテム(手動削除まで保持)

ツールとシステム

ツール目的
LECmdEric ZimmermanのコマンドラインLNKファイルパーサー(CSV/JSON出力)
JLECmdEric Zimmermanのジャンプリストパーサー
LnkParse3プログラムによるLNKファイル解析のためのPythonライブラリ
lnk_parser代替Python LNK解析ツール
AutopsyLNKファイル解析モジュールを備えたフォレンジックプラットフォーム
KAPELNKおよびジャンプリストアーティファクトの自動収集ツール
PlasoLNKファイルパーサーを搭載したタイムラインツール(スーパータイムライン作成用)
LNK ExplorerインタラクティブなLNKファイル調査用GUIツール

一般的なシナリオ

シナリオ1: USBドライブ経由のデータ持ち出し RecentフォルダのLNKファイルを解析し、リムーバブルドライブ上のターゲットを特定。ボリュームシリアル番号をUSBSTORレジストリエントリと照合。USBデバイスからアクセスされたファイルのリストを構築。リムーバブルドライブから開かれたドキュメントを特定。ファイルコピータイムスタンプと関連付け。

シナリオ2: スタートアップショートカットによるマルウェア永続化 スタートアップフォルダのLNKファイルを調査し、悪意のあるターゲットを確認。ターゲットパスと引数にエンコードされたコマンドや不審な実行ファイルがないか確認。ターゲットファイルが存在するか確認し、調査。作成タイムスタンプを初期侵害時刻と関連付け。

シナリオ3: ネットワーク共有アクセス調査 ネットワークパス(UNCターゲット)を持つLNKファイルをフィルタリング。どのネットワーク共有がいつアクセスされたかを特定。マシンIDを既知の企業システムと照合。通常業務外の機密ファイルサーバーへのアクセスがないか確認。コンプライアンス調査のためのアクセス・タイムラインを構築。

シナリオ4: 法的手続きのためのドキュメントアクセス・タイムライン Recentフォルダの全LNKファイルを抽出。ユーザーがアクセスしたドキュメントの時系列リストを作成。事件に関連する特定のファイルを特定。ファイルが開かれた時刻を示すターゲットタイムスタンプを提示。メールやコミュニケーションのタイムラインと関連付け。

出力形式

LNKファイル解析サマリー:
  ユーザープロファイル: suspect_user
  総LNKファイル数: 234 (Recent: 198, Desktop: 23, Startup: 5, その他: 8)

  ファイルアクセス統計:
    ローカルドライブ (C:):    156 ファイル
    リムーバブルメディア:     23 ファイル (3 ユニークボリュームシリアル)
    ネットワーク共有:      15 ファイル (\server01, \fileserver)
    その他ドライブ:        4 ファイル

  検出されたマシンID: DESKTOP-ABC123, LAPTOP-XYZ789
  MACアドレス: AA:BB:CC:DD:EE:FF, 11:22:33:44:55:66

  リムーバブルメディアアクセス:
    ボリュームシリアル 1234-ABCD:
      2024-01-15 14:32 - E:\Confidential\financial_report.xlsx
      2024-01-15 14:45 - E:\Confidential\customer_database.csv
      2024-01-15 15:00 - E:\Projects\source_code.zip

  スタートアップ永続化:
    updater.lnk -> C:\ProgramData\svc\updater.exe (不審)
    OneDrive.lnk -> C:\Users\...\OneDrive.exe (正当)

  タイムライン: /cases/case-2024-001/analysis/lnk_analysis.csv

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

abusing-dpapi-for-credential-access

Extract and decrypt Windows DPAPI-protected secrets (Credential Manager, browser logins/cookies, Wi-Fi credentials, KeePass keys) online or offline using SharpDPAPI, SharpChrome, Mimikatz, or Impacket

abusing-shadow-credentials-for-privesc

Take over Active Directory accounts by writing attacker-controlled public keys to msDS-KeyCredentialLink (Shadow Credentials) with pyWhisker, Whisker, or Certipy, then authenticate via PKINIT to recover the target

achieving-cmmc-level-2-compliance

>-

acquiring-disk-image-with-dd-and-dcfldd

Create forensically sound bit-for-bit disk images with dd or dcfldd on a Linux forensic workstation, preserving evidence integrity through hash verification (MD5/SHA) during acquisition. Use when imaging a suspect drive, USB device, or memory card for investigation, preserving volatile disk evidence during incident response, or producing a verified copy for legal or law-enforcement proceedings before any destructive analysis.

analyzing-active-directory-acl-abuse

Detect dangerous ACL misconfigurations in Active Directory using ldap3

analyzing-android-malware-with-apktool

Perform static analysis of Android APK malware using apktool for resource decompilation, jadx for Java source recovery, and androguard for manifest inspection, dangerous permission-combination detection, and identification of obfuscated code, dynamic code loading, and reflection-based API calls. Use to statically triage a suspicious APK without executing it or to build mobile malware detection rules.

analyzing-api-gateway-access-logs

Parses API Gateway access logs (AWS API Gateway, Kong, Nginx) to detect

analyzing-apt-group-with-mitre-navigator

Query ATT&CK data with attackcti, mitreattack-python, and stix2, then build MITRE ATT&CK Navigator layers and multi-layer heatmap overlays mapping one or more APT groups

analyzing-azure-activity-logs-for-threats

Queries Azure Monitor activity logs and sign-in logs via azure-monitor-query

analyzing-bootkit-and-rootkit-samples

Analyzes bootkit and advanced rootkit malware infecting the Master

analyzing-browser-forensics-with-hindsight

Parse Chromium-based browser databases with Hindsight to extract and correlate browsing history, downloads, cookies, cached content, autofill data, saved passwords, and extensions from Chrome, Edge, Brave, Opera, and Vivaldi into a unified timeline (XLSX, JSON, or SQLite output). Use during incident response, insider-threat investigations, or criminal cases when you need to reconstruct a user

analyzing-campaign-attribution-evidence

Systematically evaluate cyber-campaign evidence to attribute an operation to a threat actor, using the Diamond Model and Analysis of Competing Hypotheses (ACH) to weigh infrastructure overlaps, TTP consistency, malware code similarity, and timing/language artifacts into confidence-weighted attribution assessments. Use when an incident investigation needs a defensible attribution confidence level.

analyzing-certificate-transparency-for-phishing

Monitor Certificate Transparency logs using crt.sh and Certstream to

analyzing-cloud-storage-access-patterns

Detect abnormal access in AWS S3, GCS, and Azure Blob Storage by analyzing CloudTrail Data Events, GCS audit logs, and Azure Storage Analytics for after-hours bulk downloads, new-IP access, and API-call spikes (e.g. GetObject) via statistical baselines and time-series anomaly detection. Use when investigating suspected cloud data exfiltration or building related detection rules.

analyzing-cobalt-strike-beacon-configuration

Extract and analyze Cobalt Strike beacon configuration from PE files

analyzing-cobaltstrike-malleable-c2-profiles

Parse and analyze Cobalt Strike Malleable C2 profiles with dissect.cobaltstrike (profiles and beacon-payload configs) and pyMalleableC2 (AST parsing) to extract HTTP/DNS transforms, URIs, headers, sleep/jitter, and injection behavior, then generate network detection signatures. Use when reverse-engineering a captured malleable profile or building detections against Cobalt Strike Beacon traffic.

analyzing-command-and-control-communication

Analyzes malware C2 communication over HTTP, HTTPS, DNS, and custom

analyzing-cyber-kill-chain

Analyzes intrusion activity against the Lockheed Martin Cyber Kill Chain

analyzing-disk-image-with-autopsy

Perform comprehensive forensic analysis of raw (dd), E01, or AFF disk images with Autopsy and The Sleuth Kit, recovering deleted files, examining metadata and embedded artifacts, keyword searching, and building investigation timelines with visual reports. Use for structured analysis of a forensic disk image or when stakeholders need visual reports from evidence.

analyzing-dns-logs-for-exfiltration

Analyzes DNS query logs to detect data exfiltration via DNS tunneling,

関連スキル