digital forensics

Analyzing Windows Shellbag Artifacts

Analyze Windows Shellbag registry artifacts to reconstruct folder browsing activity, detect access to removable media and network shares, and establish user interaction with directories even after deletion using SBECmd and ShellBags Explorer.

bagmrudfirfolder-accessnetwork-sharesremovable-mediasbecmdshellbagsshellbags-explorer
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Shellbags are Windows registry artifacts that track how users interact with folders through Windows Explorer, storing view settings such as icon size, window position, sort order, and view mode. From a forensic perspective, Shellbags provide definitive evidence of folder access -- even folders that no longer exist on the system. When a user browses to a folder via Windows Explorer, the Open/Save dialog, or the Control Panel, a Shellbag entry is created or updated in the user's registry hive. These entries persist after folder deletion, drive disconnection, and even across user profile resets, making them invaluable for proving that a user navigated to specific directories on local drives, USB devices, network shares, or zip archives.

When to Use

  • When investigating security incidents that require analyzing windows shellbag artifacts
  • When building detection rules or threat hunting queries for this domain
  • When SOC analysts need structured procedures for this analysis type
  • When validating security monitoring coverage for related attack techniques

Prerequisites

  • Familiarity with digital forensics concepts and tools
  • Access to a test or lab environment for safe execution
  • Python 3.8+ with required dependencies installed
  • Appropriate authorization for any testing activities

Registry Locations

Windows 7/8/10/11

Hive Key Path Stores
NTUSER.DAT Software\Microsoft\Windows\Shell\BagMRU Folder hierarchy tree
NTUSER.DAT Software\Microsoft\Windows\Shell\Bags View settings per folder
UsrClass.dat Local Settings\Software\Microsoft\Windows\Shell\BagMRU Desktop/Explorer shell
UsrClass.dat Local Settings\Software\Microsoft\Windows\Shell\Bags Additional view settings

BagMRU Structure

The BagMRU key contains a hierarchical tree of numbered subkeys representing the directory structure. Each subkey value contains a Shell Item (SHITEMID) binary blob encoding the folder identity:

  • Root (BagMRU): Desktop namespace root
  • BagMRU\0: Typically "My Computer"
  • BagMRU\0\0: First drive (e.g., C:)
  • BagMRU\0\0\0: First subfolder on C:

Each Shell Item contains:

  • Item type (folder, drive, network, zip, control panel)
  • Short name (8.3 format)
  • Long name (Unicode)
  • Creation/modification timestamps
  • MFT entry/sequence for NTFS folders

Analysis with EZ Tools

SBECmd (Command Line)

# Parse shellbags from a directory of registry hives
SBECmd.exe -d "C:\Evidence\Registry" --csv C:\Output --csvf shellbags.csv
 
# Parse from a live system (requires admin)
SBECmd.exe --live --csv C:\Output --csvf live_shellbags.csv
 
# Key output columns:
# AbsolutePath - Full reconstructed path
# CreatedOn - When the folder was first browsed
# ModifiedOn - When view settings were last changed
# AccessedOn - Last access timestamp
# ShellType - Type of shell item (Directory, Drive, Network, etc.)
# Value - Raw shell item data

ShellBags Explorer (GUI)

# Launch GUI tool for interactive analysis
ShellBagsExplorer.exe
 
# Load registry hives: File > Load Hive
# Navigate the tree structure to see folder hierarchy
# Right-click entries for detailed shell item properties

Forensic Investigation Scenarios

Proving USB Device Browsing

Shellbag Path: My Computer\E:\Confidential\Project_Files
ShellType: Directory (on removable volume)
CreatedOn: 2025-03-15 09:30:00 UTC
 
This proves the user navigated to E:\Confidential\Project_Files
via Windows Explorer, even if the USB drive is no longer connected.
The volume letter E: and directory timestamps can be correlated
with USBSTOR and MountPoints2 registry entries.

Detecting Network Share Access

Shellbag Path: \\FileServer01\Finance\Q4_Reports
ShellType: Network Location
AccessedOn: 2025-02-20 14:15:00 UTC
 
This proves the user browsed to a network share, even if
the share has been decommissioned or access revoked.

Identifying Deleted Folder Knowledge

Shellbag Path: C:\Users\suspect\Documents\Exfiltration_Staging
ShellType: Directory
CreatedOn: 2025-01-10 08:00:00 UTC
 
Even though C:\Users\suspect\Documents\Exfiltration_Staging
no longer exists, the Shellbag entry proves the user
created and navigated to this folder.

Limitations

  • Shellbags only record folder-level interactions, not individual file access
  • Only created through Windows Explorer shell and Open/Save dialogs
  • Command-line access (cmd, PowerShell) does not generate Shellbag entries
  • Programmatic file access via APIs does not generate Shellbag entries
  • Timestamps may reflect view setting changes, not necessarily folder access
  • Windows may batch-update Shellbag entries during Explorer shutdown

References

Example Output

$ SBECmd.exe -d "C:\Evidence\Users\jsmith" --csv /analysis/shellbag_output
 
SBECmd v2.1.0 - ShellBags Explorer (Command Line)
====================================================
Processing hives for user: jsmith
  NTUSER.DAT:  C:\Evidence\Users\jsmith\NTUSER.DAT
  UsrClass.dat: C:\Evidence\Users\jsmith\AppData\Local\Microsoft\Windows\UsrClass.dat
 
[+] NTUSER.DAT shellbag entries:   456
[+] UsrClass.dat shellbag entries: 1,234
[+] Total shellbag entries:        1,690
 
--- Folder Access Timeline (Incident Window) ---
Last Accessed (UTC)     | Folder Path                                             | Type        | Access Count
------------------------|---------------------------------------------------------|-------------|-------------
2024-01-15 14:34:05     | C:\Users\jsmith\Downloads                               | File System | 45
2024-01-15 14:36:25     | C:\ProgramData\Updates                                  | File System | 3
2024-01-15 15:05:00     | \\FILESERV01\Finance                                    | Network     | 2
2024-01-15 15:12:30     | \\FILESERV01\Finance\Q4_Reports                          | Network     | 1
2024-01-15 15:30:00     | E:\                                                     | Removable   | 4
2024-01-15 15:30:45     | E:\Backup                                               | Removable   | 3
2024-01-15 15:31:20     | E:\Backup\Corporate_Data                                | Removable   | 2
2024-01-15 16:12:45     | \\FILESERV01\HR\Employees                                | Network     | 1
2024-01-15 16:15:00     | \\FILESERV01\HR\Employees\Records_2024                   | Network     | 1
2024-01-16 02:35:00     | C:\Windows\Temp                                         | File System | 5
2024-01-17 02:44:00     | C:\ProgramData\svc                                     | File System | 2
2024-01-18 01:10:00     | C:\Users\jsmith\AppData\Local\Temp                      | File System | 8
 
--- Network Share Access ---
  \\FILESERV01\Finance             First: 2023-09-10  Last: 2024-01-15
  \\FILESERV01\Finance\Q4_Reports  First: 2024-01-15  Last: 2024-01-15  (NEW)
  \\FILESERV01\HR\Employees        First: 2024-01-15  Last: 2024-01-15  (NEW)
  \\DC01\SYSVOL                    First: 2023-03-15  Last: 2024-01-16  (anomalous access time)
 
--- Removable Device Access ---
  E:\ (USB Drive)
    Volume Name:    BACKUP_DRIVE
    First Accessed: 2024-01-15 15:30:00 UTC
    Last Accessed:  2024-01-15 15:45:22 UTC
    Folders Browsed: 3 (E:\, E:\Backup, E:\Backup\Corporate_Data)
 
--- Deleted/No Longer Existing Paths ---
  C:\ProgramData\Updates\                (folder deleted, shellbag persists)
  C:\ProgramData\svc\                    (folder deleted, shellbag persists)
  C:\Windows\Temp\tools\                 (folder deleted, shellbag persists)
 
Summary:
  Total unique folders accessed:  1,690
  Network shares accessed:        4 (2 newly accessed during incident)
  Removable media:                1 USB device (data staging suspected)
  Deleted folder evidence:        3 paths (anti-forensics indicator)
  CSV exported to:                /analysis/shellbag_output/
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md2.1 KB

API Reference: Windows ShellBag Forensics

SBECmd (Eric Zimmerman)

Syntax

SBECmd.exe -d <registry_dir>              # Process directory of hives
SBECmd.exe --hive <NTUSER.DAT>            # Single hive
SBECmd.exe -d <dir> --csv <output_dir>    # CSV export
SBECmd.exe -d <dir> -l                    # Live system registry

Output Fields

Field Description
AbsolutePath Full reconstructed folder path
CreatedOn Folder creation timestamp
ModifiedOn Folder modification timestamp
AccessedOn Folder access timestamp
MFTEntryNumber NTFS MFT reference
ShellType Folder, network, zip, etc.

ShellBags Explorer (GUI)

Features

  • Tree view of folder access history
  • Timeline view of access patterns
  • Filtering by date range
  • Export to CSV/JSON

Registry Paths

NTUSER.DAT

Software\Microsoft\Windows\Shell\BagMRU
Software\Microsoft\Windows\Shell\Bags
Software\Microsoft\Windows\ShellNoRoam\BagMRU

UsrClass.dat

Local Settings\Software\Microsoft\Windows\Shell\BagMRU
Local Settings\Software\Microsoft\Windows\Shell\Bags

regipy (Python)

Installation

pip install regipy

Usage

from regipy.registry import RegistryHive
 
hive = RegistryHive("NTUSER.DAT")
key = hive.get_key("Software\Microsoft\Windows\Shell\BagMRU")
for value in key.iter_values():
    print(value.name, type(value.value))

Shell Item Types

Type Byte Description
0x1F Root folder (GUID - Desktop, My Computer)
0x2F Volume (drive letter)
0x31 File entry (directory)
0x32 File entry (file)
0x41 Network location
0x42 Compressed folder
0x46 Network share (UNC path)
0x71 Control Panel item

Forensic Value

Artifact Intelligence
Network paths Remote share access (lateral movement)
USB paths Removable media (data exfiltration)
Deleted folders Evidence of anti-forensics awareness
Temp directories Staging areas for tools/malware
AppData paths Persistence mechanism locations
Recycle Bin Awareness of deleted content
standards.md0.6 KB

Standards - Shellbag Forensics

Standards

  • NIST SP 800-86: Guide to Integrating Forensic Techniques
  • SWGDE Best Practices for Computer Forensics

Tools

  • SBECmd (Eric Zimmerman): Command-line shellbag parser
  • ShellBags Explorer (Eric Zimmerman): GUI shellbag viewer
  • Registry Explorer (Eric Zimmerman): Registry hive analysis

Registry Locations

  • NTUSER.DAT: Software\Microsoft\Windows\Shell\BagMRU and Bags
  • UsrClass.dat: Local Settings\Software\Microsoft\Windows\Shell\BagMRU and Bags

MITRE ATT&CK

  • T1083 - File and Directory Discovery
  • T1005 - Data from Local System
workflows.md0.3 KB

Workflows - Shellbag Analysis

Workflow 1: Folder Access Investigation

Extract NTUSER.DAT and UsrClass.dat from evidence
    |
Parse with SBECmd to CSV
    |
Open in Timeline Explorer
    |
Filter by path patterns (USB drives, network shares)
    |
Correlate with MFT and LNK file timestamps
    |
Document folder access timeline

Scripts 2

agent.py6.0 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Windows ShellBag artifact analysis agent.

Parses ShellBag registry artifacts to reconstruct folder access history,
directory browsing patterns, and evidence of accessed network shares.
"""

import os
import sys
import json
import struct
import hashlib
import datetime
from collections import defaultdict

try:
    import Registry
    HAS_REGISTRY = True
except ImportError:
    try:
        from regipy.registry import RegistryHive
        HAS_REGIPY = True
        HAS_REGISTRY = False
    except ImportError:
        HAS_REGISTRY = False
        HAS_REGIPY = False


SHELLBAG_PATHS = {
    'ntuser': [
        r'Software\Microsoft\Windows\Shell\BagMRU',
        r'Software\Microsoft\Windows\Shell\Bags',
        r'Software\Microsoft\Windows\ShellNoRoam\BagMRU',
        r'Software\Microsoft\Windows\ShellNoRoam\Bags',
    ],
    'usrclass': [
        r'Local Settings\Software\Microsoft\Windows\Shell\BagMRU',
        r'Local Settings\Software\Microsoft\Windows\Shell\Bags',
    ],
}


def filetime_to_datetime(filetime):
    if not filetime or filetime == 0:
        return None
    try:
        epoch = datetime.datetime(1601, 1, 1)
        delta = datetime.timedelta(microseconds=filetime // 10)
        return (epoch + delta).isoformat() + 'Z'
    except (OverflowError, OSError):
        return None


def parse_shell_item(data):
    if len(data) < 2:
        return None
    item_size = struct.unpack_from('<H', data, 0)[0]
    if item_size < 2 or item_size > len(data):
        return None
    item_type = data[2] if len(data) > 2 else 0
    result = {'size': item_size, 'type': hex(item_type)}

    if item_type == 0x1F:
        result['class'] = 'Root Folder (GUID)'
        if len(data) >= 18:
            guid = data[4:20].hex()
            result['guid'] = guid
    elif item_type in (0x31, 0x32, 0x35):
        result['class'] = 'File Entry'
        if len(data) > 14:
            file_size = struct.unpack_from('<I', data, 4)[0]
            result['file_size'] = file_size
            name_offset = 14
            if name_offset < len(data):
                name_end = data.find(b'\x00', name_offset)
                if name_end > name_offset:
                    result['short_name'] = data[name_offset:name_end].decode('ascii', errors='replace')
    elif item_type in (0x41, 0x42, 0x46, 0x47):
        result['class'] = 'Network Location'
        if len(data) > 5:
            name_start = 5
            name_end = data.find(b'\x00', name_start)
            if name_end > name_start:
                result['network_path'] = data[name_start:name_end].decode('ascii', errors='replace')
    elif item_type == 0x71:
        result['class'] = 'Control Panel'
    else:
        result['class'] = 'Unknown'

    return result


def parse_bagmru_value(data):
    items = []
    offset = 0
    while offset < len(data) - 2:
        item_size = struct.unpack_from('<H', data, offset)[0]
        if item_size == 0:
            break
        item_data = data[offset:offset + item_size]
        parsed = parse_shell_item(item_data)
        if parsed:
            items.append(parsed)
        offset += item_size
    return items


def analyze_shellbags_regipy(hive_path):
    if not HAS_REGIPY:
        return []
    hive = RegistryHive(hive_path)
    results = []
    for path_group in SHELLBAG_PATHS.values():
        for reg_path in path_group:
            try:
                key = hive.get_key(reg_path)
                if key:
                    for value in key.iter_values():
                        if isinstance(value.value, bytes):
                            items = parse_bagmru_value(value.value)
                            for item in items:
                                item['registry_path'] = reg_path
                                item['value_name'] = value.name
                                results.append(item)
            except Exception:
                continue
    return results


def detect_suspicious_paths(shellbag_entries):
    findings = []
    suspicious_indicators = [
        ('\\', 'UNC path access (network share)'),
        ('temp', 'Temp directory access'),
        ('appdata', 'AppData directory (persistence location)'),
        ('recycle', 'Recycle Bin access'),
        ('usb', 'USB device path'),
        ('removable', 'Removable media'),
        ('.tor', 'Tor browser directory'),
        ('sysinternals', 'Sysinternals tools directory'),
        ('mimikatz', 'Mimikatz tool directory'),
        ('powershell', 'PowerShell directory'),
    ]
    for entry in shellbag_entries:
        path = (entry.get('short_name', '') + ' ' + entry.get('network_path', '')).lower()
        for pattern, description in suspicious_indicators:
            if pattern in path:
                findings.append({
                    'type': 'suspicious_path',
                    'path': entry.get('short_name', entry.get('network_path', '')),
                    'indicator': description,
                    'severity': 'HIGH' if 'mimikatz' in pattern else 'MEDIUM',
                })
                break
    return findings


if __name__ == '__main__':
    print('=' * 60)
    print('Windows ShellBag Artifact Analysis Agent')
    print('Registry parsing, folder history, network share detection')
    print('=' * 60)

    target = sys.argv[1] if len(sys.argv) > 1 else None
    if not target or not os.path.exists(target):
        print('\n[DEMO] Usage: python agent.py <NTUSER.DAT|UsrClass.dat>')
        print(f'  regipy available: {HAS_REGIPY if not HAS_REGISTRY else False}')
        print(f'  python-registry available: {HAS_REGISTRY}')
        sys.exit(0)

    print(f'\n[*] Analyzing: {target}')
    entries = analyze_shellbags_regipy(target)
    print(f'[*] ShellBag entries: {len(entries)}')

    print('\n--- Folder Access History ---')
    for e in entries[:20]:
        name = e.get('short_name', e.get('network_path', e.get('guid', '?')))
        print(f'  [{e["class"]:20s}] {name}')

    findings = detect_suspicious_paths(entries)
    print(f'\n--- Suspicious Paths ({len(findings)}) ---')
    for f in findings[:10]:
        print(f'  [{f["severity"]}] {f["indicator"]}: {f["path"]}')
process.py1.5 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Shellbag Forensic Analyzer - Parses SBECmd CSV output for investigation."""
import csv, json, os, sys
from datetime import datetime
from collections import defaultdict

def analyze_shellbags(csv_path: str, output_dir: str) -> str:
    os.makedirs(output_dir, exist_ok=True)
    entries = []
    usb_access = []
    network_access = []
    with open(csv_path, "r", encoding="utf-8-sig") as f:
        for row in csv.DictReader(f):
            entries.append(row)
            path = row.get("AbsolutePath", "")
            if any(d in path for d in ["E:\\", "F:\\", "G:\\", "H:\\"]):
                usb_access.append(row)
            if path.startswith("\\\\"):
                network_access.append(row)
    report = {
        "analysis_timestamp": datetime.now().isoformat(),
        "total_entries": len(entries),
        "usb_access_entries": len(usb_access),
        "network_access_entries": len(network_access),
        "usb_paths": [r.get("AbsolutePath", "") for r in usb_access],
        "network_paths": [r.get("AbsolutePath", "") for r in network_access],
    }
    report_path = os.path.join(output_dir, "shellbag_analysis.json")
    with open(report_path, "w") as f:
        json.dump(report, f, indent=2)
    print(f"[*] Total entries: {len(entries)}, USB: {len(usb_access)}, Network: {len(network_access)}")
    return report_path

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: python process.py <shellbag_csv> <output_dir>")
        sys.exit(1)
    analyze_shellbags(sys.argv[1], sys.argv[2])

Assets 1

template.mdtext/markdown · 0.4 KB
Keep exploring