<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: analyzing-shellbag-artifacts
description: >-
  Windows Shellbag forensic analysis for directory browsing evidence including
  NTUSER.DAT and UsrClass.dat parsing, folder access timeline reconstruction,
  network share enumeration, removable device path evidence, and ZIP archive
  browsing detection using SBECmd, ShellBags Explorer, and python-registry.
domain: cybersecurity
subdomain: digital-forensics
tags:
  - shellbags
  - windows-forensics
  - ntuser-dat
  - usrclass-dat
  - directory-browsing
  - folder-access
  - network-shares
version: "1.0"
author: defconxt
license: AGPL-3.0
compatibility: Designed for Claude Code, GitHub Copilot, OpenAI Codex, Cursor, Gemini CLI, and any agentskills.io-compatible agent.
metadata:
  mitre-attack: ["T1083", "T1135"]
  nist-csf: ["RS.AN-3"]
  frameworks: ["NIST SP 800-86"]
---

# Analyzing Shellbag Artifacts

## Overview

Windows Shellbags record folder browsing activity in the Registry, preserving
evidence of directory access even after folders are deleted. Shellbags persist
window positions, view preferences, and folder paths for every directory a user
has opened in Windows Explorer. They provide evidence of folder access on local
drives, network shares, removable devices, and ZIP archive contents.

## Prerequisites

- SBECmd (Eric Zimmerman) for automated parsing
- ShellBags Explorer (GUI) for visual analysis
- Python 3.10+ with `python-registry`
- NTUSER.DAT and UsrClass.dat from forensic image

```bash
pip install python-registry
```

## Key Concepts

### Shellbag Registry Locations

**NTUSER.DAT (per-user):**
```
HKCU\Software\Microsoft\Windows\Shell\BagMRU     — Folder tree structure
HKCU\Software\Microsoft\Windows\Shell\Bags        — View settings per folder
```

**UsrClass.dat (per-user, more complete):**
```
HKCU\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\BagMRU
HKCU\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\Bags
```

### BagMRU Tree Structure

BagMRU stores a tree of shell item lists where each node represents a
folder and each subkey represents a child folder:

```
BagMRU\
├── 0\              → Desktop (or My Computer)
│   ├── 0\          → C: drive
│   │   ├── 0\      → C:\Users
│   │   │   └── 0\  → C:\Users\admin
│   │   └── 1\      → C:\Windows
│   ├── 1\          → D: drive
│   └── 2\          → Network location
└── 1\              → Control Panel
```

Each value (0, 1, 2...) contains a binary shell item ID list that encodes
the folder name, timestamps, and type (drive, folder, network, zip, etc.).

### Shell Item Types

| Type | Byte Indicator | Description |
|------|---------------|-------------|
| `0x1F` | Root folder | Desktop, My Computer, Control Panel |
| `0x23` | Drive | C:\, D:\, USB drives |
| `0x25` | Drive | Full drive path |
| `0x2F` | Drive | Volume |
| `0x31` | Folder | Directory entry |
| `0x32` | File | File entry in folder |
| `0x35` | Folder | Directory (Unicode) |
| `0x41` | Network | Network share root |
| `0x42` | Network | Network share |
| `0x46` | Network | Network domain/workgroup |
| `0x47` | Network | Network server |
| `0xC3` | Network | Network location |

### Forensic Value

```
Shellbags prove:
├── User browsed specific folders (even if deleted)
├── User accessed network shares (\\server\share)
├── User opened removable media (E:\, F:\)
├── User browsed inside ZIP/CAB archives
├── Folder access timestamps (created, modified, accessed)
├── Window position and view preferences
└── Evidence persists across reboots and folder deletion
```

## Workflow

### Step 1: Extract Registry Hives

```bash
# From mounted forensic image
cp /mnt/evidence/Users/<user>/NTUSER.DAT ./NTUSER.DAT
cp "/mnt/evidence/Users/<user>/AppData/Local/Microsoft/Windows/UsrClass.dat" ./UsrClass.dat
```

### Step 2: Parse with SBECmd

```bash
# Parse NTUSER.DAT shellbags
SBECmd.exe -d . --csv . --csvf shellbags.csv

# Parse specific hive
SBECmd.exe --hive UsrClass.dat --csv . --csvf usrclass_shellbags.csv

# Live system (requires admin)
SBECmd.exe -l --csv . --csvf live_shellbags.csv
```

### Step 3: Python Shellbag Parser

```python
import struct
from Registry import Registry
from datetime import datetime


def parse_shellbags(hive_path: str) -> list[dict]:
    """Parse Shellbag entries from Registry hive."""
    reg = Registry.Registry(hive_path)
    entries = []

    # Try both possible paths
    bag_paths = [
        "Software\\Microsoft\\Windows\\Shell\\BagMRU",
        "Local Settings\\Software\\Microsoft\\Windows\\Shell\\BagMRU",
    ]

    for base_path in bag_paths:
        try:
            root = reg.open(base_path)
            _walk_bagmru(root, "", entries)
        except Exception:
            continue
    return entries


def _walk_bagmru(key, parent_path: str, entries: list) -> None:
    """Recursively walk BagMRU tree."""
    for val in key.values():
        if not val.name().isdigit():
            continue
        raw = val.value()
        if not isinstance(raw, bytes) or len(raw) < 4:
            continue
        item = _parse_shell_item(raw)
        if item:
            full_path = f"{parent_path}\\{item['name']}" if parent_path else item["name"]
            item["full_path"] = full_path
            item["last_write"] = key.timestamp().isoformat()
            entries.append(item)

            # Recurse into subkey
            try:
                subkey = key.subkey(val.name())
                _walk_bagmru(subkey, full_path, entries)
            except Exception:
                pass


def _parse_shell_item(data: bytes) -> dict | None:
    """Parse a shell item ID list entry."""
    if len(data) < 4:
        return None
    size = struct.unpack_from("<H", data, 0)[0]
    if size < 4:
        return None
    item_type = data[2]

    result = {"type_byte": f"0x{item_type:02X}", "size": size}

    if item_type in (0x31, 0x32, 0x35):  # Folder or file
        # Try to extract name (simplified — real parsing is complex)
        try:
            # Short name at offset 14 (8.3 format)
            short_end = data.index(b"\x00", 14)
            result["name"] = data[14:short_end].decode("ascii", errors="replace")
            result["item_type"] = "folder" if item_type in (0x31, 0x35) else "file"
        except (ValueError, UnicodeDecodeError):
            result["name"] = f"item_0x{item_type:02X}"
    elif item_type in (0x23, 0x25, 0x2F):  # Drive
        try:
            result["name"] = data[3:6].decode("ascii", errors="replace")
            result["item_type"] = "drive"
        except UnicodeDecodeError:
            result["name"] = "drive"
    elif item_type in (0x41, 0x42, 0xC3):  # Network
        try:
            end = data.index(b"\x00", 5)
            result["name"] = data[5:end].decode("ascii", errors="replace")
            result["item_type"] = "network_share"
        except (ValueError, UnicodeDecodeError):
            result["name"] = "network"
    elif item_type == 0x1F:  # Root folder
        result["name"] = "Root Folder"
        result["item_type"] = "root"
    else:
        result["name"] = f"unknown_0x{item_type:02X}"
        result["item_type"] = "unknown"

    return result
```

### Step 4: Identify Evidence Patterns

```python
def find_network_shares(entries: list[dict]) -> list[dict]:
    """Find evidence of network share access."""
    return [e for e in entries if e.get("item_type") == "network_share"]

def find_removable_media(entries: list[dict]) -> list[dict]:
    """Find evidence of removable media browsing."""
    return [e for e in entries
            if e.get("item_type") == "drive"
            and e.get("name", "")[:1] not in ("C", "")]

def find_deleted_folder_evidence(entries: list[dict]) -> list[dict]:
    """Shellbags for folders that may no longer exist."""
    import os
    return [e for e in entries
            if e.get("full_path") and not os.path.exists(e["full_path"])]
```

## Detection

```yaml
title: Shellbag Artifacts Detection
id: 7b03f420-e3c1-4384-8bdb-1f4d6ae7e374
status: experimental
description: Detects suspicious activity related to analyzing shellbag artifacts techniques in digital forensics context
logsource:
  category: process_creation
  product: windows
detection:
  selection:
    CommandLine: "*analyzing*shellbag*"
  condition: selection
level: medium
tags:
  - attack.t1083
  - attack.t1135
  - attack.collection
falsepositives:
  - Forensic investigation tools used by authorized incident response team
```

## Verification

- [ ] Both NTUSER.DAT and UsrClass.dat extracted and parsed
- [ ] BagMRU tree walked completely with full path reconstruction
- [ ] Network share paths identified (\\server\share evidence)
- [ ] Removable media paths identified (USB drive letter evidence)
- [ ] Folder access timestamps extracted and correlated with timeline
- [ ] Deleted folder evidence identified (shellbag exists but folder gone)
- [ ] ZIP/CAB archive browsing evidence documented

## References

- [SBECmd — Eric Zimmerman](https://ericzimmerman.github.io/)
- [ShellBags Explorer](https://ericzimmerman.github.io/)
- [SANS Shellbag Forensics](https://www.sans.org/blog/computer-forensic-artifact-shellbags/)
- [Shellbag Format — libfwsi](https://github.com/libyal/libfwsi)
- [MITRE T1083 — File and Directory Discovery](https://attack.mitre.org/techniques/T1083/)
