USB & External Device Forensics - SOC Analyst Cheatsheet
Practical Guide for USB Device Investigation & Data Exfiltration
Quick Reference: USB Artifacts Matrix
USBSTOR
Device identity
SYSTEM hive
Persistent
Vendor, product, serial
MountPoints2
User attribution
NTUSER.DAT
Persistent
Which user accessed device
Timestamps
Connection times
SYSTEM hive, setupapi.dev.log
Medium
First/last connect, removal
Volume Serial Number
Device-to-file linking
Event 1006, EMDMgmt
Medium
Critical for LNK correlation
Drive Letters
Mount points
MountedDevices
Last only
Historical not available
Investigation Priority Matrix
CRITICAL
USBSTOR + USB
Device identification
Vendor, product, serial number
CRITICAL
Volume Serial Number
File access correlation
Links USB to LNK files
CRITICAL
MountPoints2
User attribution
Which user accessed USB
HIGH
Connection Timestamps
Timeline construction
First/last connection times
MEDIUM
Drive Letters
Current mapping
Drive letter assignments
Core Investigation Questions
Primary Questions:
What devices connected? (USBSTOR - Device identification)
When did they connect? (Timestamps - Timeline)
Who accessed them? (MountPoints2 - User attribution)
What files were accessed? (VSN + LNK files - File correlation)
The Critical Link:
Volume Serial Number (VSN) is the KEY to linking USB devices to file access via LNK files!
Understanding USB Forensics Components
Key Concept: Multiple Serial Numbers
DO NOT CONFUSE:
USB Unique Serial
Device firmware serial
USBSTOR key
Identifies physical USB device
Volume Serial Number (VSN)
File system serial
Event 1006, EMDMgmt, LNK files
Links device to files accessed
Printed Serial
Label on device
Physical device
May not match internal serial
Critical Understanding:
USB Device connects β Assigned VSN (if formatted)
Files accessed from USB β LNK files created with VSN embedded
VSN in LNK file = VSN from USB device = PROOF of file accessSOC Investigation Workflows
Workflow 1: Data Exfiltration Investigation (CRITICAL)
Scenario: Suspected data theft via USB drive
Investigation Steps (Priority Order):
Step 1: Identify ALL USB Devices Connected
Registry Location: SYSTEM\CurrentControlSet\Enum\USBSTOR
PowerShell - Enumerate USB Devices:
<#
.SYNOPSIS
Enumerate all USB storage devices ever connected
#>
Write-Host "[+] Enumerating USB Storage Devices..." -ForegroundColor Cyan
$usbStorPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR"
if (Test-Path $usbStorPath) {
Get-ChildItem $usbStorPath | ForEach-Object {
$deviceKey = $_
$deviceInfo = $_.PSChildName
# Parse device info: Disk&Ven_XXX&Prod_YYY&Rev_ZZZ
if ($deviceInfo -match "Disk&Ven_(.+)&Prod_(.+)&Rev_(.+)") {
$vendor = $matches[1].Trim("_")
$product = $matches[2].Trim("_")
$revision = $matches[3].Trim("_")
Write-Host "`n--- Device: $vendor $product ---" -ForegroundColor Yellow
Write-Host " Revision: $revision" -ForegroundColor Gray
# Get serial number(s)
Get-ChildItem $deviceKey.PSPath | ForEach-Object {
$serial = $_.PSChildName
$props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
# Check for Windows-generated serial (has & in 2nd position)
if ($serial.Length -ge 2 -and $serial[1] -eq '&') {
$serialType = "Windows-Generated (No Unique Serial)"
} else {
$serialType = "Device Unique Serial"
}
Write-Host "`n Serial Number: $serial" -ForegroundColor Cyan
Write-Host " Type: $serialType" -ForegroundColor $(if ($serialType -like "*Windows*") { "Yellow" } else { "Green" })
if ($props.FriendlyName) {
Write-Host " Friendly Name: $($props.FriendlyName)" -ForegroundColor White
}
# Get ParentIdPrefix (links to SCSI)
if ($props.ParentIdPrefix) {
Write-Host " ParentIdPrefix: $($props.ParentIdPrefix)" -ForegroundColor Gray
}
}
}
}
} else {
Write-Host "[!] USBSTOR key not found" -ForegroundColor Red
}Key USBSTOR Fields:
Vendor - Manufacturer (Kingston, SanDisk, etc.)
Product - Model name
Version/Revision - Firmware version
Serial Number - Device identifier
FriendlyName - Windows display name
ParentIdPrefix - Links USBSTOR to SCSI key
Red Flags:
β Unknown vendors (unrecognised brands)
β Multiple similar devices (many USBs in short time)
β Recently connected devices during incident window
β Windows-generated serials (& in 2nd position = device lacks unique serial)
Step 2: Extract Connection Timestamps (First/Last Connection)
Three Sources for Timestamps:
A. SYSTEM Registry Properties Keys (Most Reliable)
Location:
SYSTEM\CurrentControlSet\Enum\USBSTOR\{Device}\{Serial}\Properties\{83da6326-97a6-4088-9453-a19231573b29}\####
Where #### is:
0064 - First Install (Windows 7+)
0066 - Last Connected (Windows 8+)
0067 - Last Removal (Windows 8+)PowerShell - Extract Timestamps:
<#
.SYNOPSIS
Extract USB connection timestamps from SYSTEM registry
#>
function Convert-FileTimeToDateTime {
param([byte[]]$FileTimeBytes)
if ($FileTimeBytes.Length -ge 8) {
try {
$fileTime = [BitConverter]::ToInt64($FileTimeBytes, 0)
return [DateTime]::FromFileTime($fileTime)
} catch {
return "Unable to parse"
}
}
return "Invalid data"
}
Write-Host "[+] Extracting USB Connection Timestamps..." -ForegroundColor Cyan
$usbStorPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR"
Get-ChildItem $usbStorPath | ForEach-Object {
$deviceKey = $_
Get-ChildItem $deviceKey.PSPath | ForEach-Object {
$serialKey = $_
$serial = $_.PSChildName
# Properties key
$propsPath = Join-Path $serialKey.PSPath "Properties\{83da6326-97a6-4088-9453-a19231573b29}"
if (Test-Path $propsPath) {
Write-Host "`n--- Serial: $serial ---" -ForegroundColor Yellow
# First Install (0064)
$firstInstall = Get-ItemProperty "$propsPath\0064" -Name "(default)" -ErrorAction SilentlyContinue
if ($firstInstall) {
$time = Convert-FileTimeToDateTime $firstInstall.'(default)'
Write-Host " First Install: $time" -ForegroundColor Green
}
# Last Connected (0066)
$lastConnected = Get-ItemProperty "$propsPath\0066" -Name "(default)" -ErrorAction SilentlyContinue
if ($lastConnected) {
$time = Convert-FileTimeToDateTime $lastConnected.'(default)'
Write-Host " Last Connected: $time" -ForegroundColor Cyan
}
# Last Removal (0067)
$lastRemoval = Get-ItemProperty "$propsPath\0067" -Name "(default)" -ErrorAction SilentlyContinue
if ($lastRemoval) {
$time = Convert-FileTimeToDateTime $lastRemoval.'(default)'
Write-Host " Last Removal: $time" -ForegroundColor Yellow
}
}
}
}B. setupapi.dev.log (First Connection - LOCAL TIMEZONE!)
Location: C:\Windows\inf\setupapi.dev.log
CRITICAL: Timestamps in LOCAL TIMEZONE (not UTC like most forensic artifacts!)
PowerShell - Parse setupapi.dev.log:
<#
.SYNOPSIS
Parse setupapi.dev.log for USB connections
#>
param(
[string]$LogPath = "C:\Windows\inf\setupapi.dev.log",
[string]$SearchSerial = "" # Optional: search for specific serial
)
Write-Host "[+] Parsing setupapi.dev.log..." -ForegroundColor Cyan
Write-Host "[!] WARNING: Timestamps are in LOCAL TIMEZONE" -ForegroundColor Yellow
if (Test-Path $LogPath) {
$content = Get-Content $LogPath
$usbEntries = @()
$currentEntry = $null
foreach ($line in $content) {
# Look for USB device installation start
if ($line -match ">>> \[Device Install.*?\- (.+?)\]" -or $line -match "Device Install.*?USB") {
if ($currentEntry) {
$usbEntries += $currentEntry
}
$currentEntry = @{
Lines = @($line)
Timestamp = $null
Serial = $null
}
}
if ($currentEntry) {
$currentEntry.Lines += $line
# Extract timestamp (format: >>> Section start 2024/11/30 14:23:45.123)
if ($line -match ">>>.*?(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}\.\d{3})") {
$currentEntry.Timestamp = $matches[1]
}
# Extract serial number
if ($line -match "Device Serial Number = (.+)") {
$currentEntry.Serial = $matches[1].Trim()
}
}
}
if ($currentEntry) {
$usbEntries += $currentEntry
}
# Display results
if ($SearchSerial) {
$filtered = $usbEntries | Where-Object { $_.Serial -like "*$SearchSerial*" }
Write-Host "`n[*] Entries matching '$SearchSerial':" -ForegroundColor Yellow
$filtered | ForEach-Object {
Write-Host " Timestamp: $($_.Timestamp) (LOCAL TIME)" -ForegroundColor Cyan
Write-Host " Serial: $($_.Serial)" -ForegroundColor White
}
} else {
Write-Host "`n[*] Found $($usbEntries.Count) USB device entries" -ForegroundColor Yellow
Write-Host "[*] Recent entries:" -ForegroundColor Yellow
$usbEntries | Select-Object -Last 10 | ForEach-Object {
Write-Host "`n Timestamp: $($_.Timestamp) (LOCAL TIME)" -ForegroundColor Cyan
Write-Host " Serial: $($_.Serial)" -ForegroundColor White
}
}
} else {
Write-Host "[!] setupapi.dev.log not found" -ForegroundColor Red
}C. Event ID 1006 (Connection/Disconnection Events)
Location: Microsoft-Windows-Partition/Diagnostic.evtx
Event ID 1006: Logged for each USB connect/disconnect
Caveat: Log cleared during major OS updates
PowerShell - Parse Event 1006:
<#
.SYNOPSIS
Parse Event 1006 for USB connections
#>
param(
[string]$EventLog = "C:\Windows\System32\winevt\Logs\Microsoft-Windows-Partition%4Diagnostic.evtx",
[int]$Days = 30
)
Write-Host "[+] Parsing Partition Diagnostic Events..." -ForegroundColor Cyan
if (Test-Path $EventLog) {
$startTime = (Get-Date).AddDays(-$Days)
$events = Get-WinEvent -Path $EventLog -FilterXPath "*[System[EventID=1006]]" -ErrorAction SilentlyContinue
if ($events) {
Write-Host "[*] Found $($events.Count) partition events" -ForegroundColor Yellow
$events | Sort-Object TimeCreated -Descending | ForEach-Object {
$xml = [xml]$_.ToXml()
Write-Host "`n--- Event: $($_.TimeCreated) ---" -ForegroundColor Yellow
Write-Host "Event Data:" -ForegroundColor Gray
$xml.Event.EventData.Data | ForEach-Object {
Write-Host " $($_.Name): $($_.'#text')" -ForegroundColor Cyan
}
}
} else {
Write-Host "[!] No Event 1006 entries found" -ForegroundColor Red
}
} else {
Write-Host "[!] Partition Diagnostic log not found" -ForegroundColor Red
}Timestamp Summary Table:
Properties 0064
First Install
UTC
High
Win7+
Properties 0066
Last Connected
UTC
High
Win8+
Properties 0067
Last Removal
UTC
High
Win8+
setupapi.dev.log
First Connection
LOCAL
High
Persistent
Event 1006
Each connect/disconnect
UTC
Medium
Cleared on updates
Step 3: Identify User Attribution (MountPoints2)
Critical for Attribution: Which user account accessed the USB device?
Registry Location: NTUSER.DAT\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2
How It Works:
USB device assigned Volume GUID
User accesses USB β MountPoints2 entry created in their NTUSER.DAT
Volume GUID links to specific USB device
PowerShell - Check Current User:
<#
.SYNOPSIS
Check current user's MountPoints2 for USB access
#>
Write-Host "[+] Checking MountPoints2 for USB Device Access..." -ForegroundColor Cyan
$mountPoints = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2"
if (Test-Path $mountPoints) {
$entries = Get-ChildItem $mountPoints
if ($entries) {
Write-Host "`n[*] Found $($entries.Count) mount point entries for $env:USERNAME" -ForegroundColor Yellow
foreach ($entry in $entries) {
$guid = $entry.PSChildName
# Volume GUIDs start with {
# Network shares start with ##
if ($guid -like "{*}") {
Write-Host "`n Volume GUID: $guid" -ForegroundColor Cyan
# Try to get additional details
$props = Get-ItemProperty $entry.PSPath -ErrorAction SilentlyContinue
if ($props) {
$props.PSObject.Properties | Where-Object { $_.Name -notlike "PS*" } | ForEach-Object {
Write-Host " $($_.Name): $($_.Value)" -ForegroundColor Gray
}
}
}
}
Write-Host "`n[+] To correlate GUIDs with devices, check SYSTEM\MountedDevices" -ForegroundColor Yellow
} else {
Write-Host "[!] No mount points found for current user" -ForegroundColor Gray
}
} else {
Write-Host "[!] MountPoints2 key not found" -ForegroundColor Red
}Offline Analysis (All Users):
# For offline analysis, need to load each user's NTUSER.DAT
# Example for specific user:
$userProfile = "C:\Users\Alice"
$ntuserPath = "$userProfile\NTUSER.DAT"
# Load hive (requires admin)
reg load "HKU\TempUser" $ntuserPath
# Query MountPoints2
reg query "HKU\TempUser\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2"
# Unload hive
reg unload "HKU\TempUser"Step 4: Extract Volume Serial Number (VSN) - THE CRITICAL LINK
Why VSN is Critical:
USB Device β Formatted with file system β Assigned VSN
Files accessed on USB β LNK files created
LNK files contain VSN (embedded in shell item)
VSN in LNK = VSN from USB device = PROOF of file access from that specific USBThree Methods to Get VSN:
Method 1: Event ID 1006 (Windows 10+)
Event 1006 may include VBR (Volume Boot Record) data containing VSN
VSN Location in VBR:
FAT: Offset 0x43 (4 bytes)
exFAT: Offset 0x64 (4 bytes)
NTFS: Offset 0x48 (8 bytes, but only first 4 bytes used)
Method 2: EMDMgmt Registry Key (Legacy)
Location: SOFTWARE\Microsoft\Windows NT\CurrentVersion\EMDMgmt
Caveat: Often missing on modern systems with SSDs
PowerShell - Extract from EMDMgmt:
<#
.SYNOPSIS
Extract Volume Serial Numbers from EMDMgmt
#>
Write-Host "[+] Checking EMDMgmt for Volume Serial Numbers..." -ForegroundColor Cyan
$emdMgmtPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EMDMgmt"
if (Test-Path $emdMgmtPath) {
Get-ChildItem $emdMgmtPath | ForEach-Object {
$entry = Get-ItemProperty $_.PSPath
Write-Host "`n--- Entry: $($_.PSChildName) ---" -ForegroundColor Yellow
# Look for volume serial number (last integer in key name)
if ($_.PSChildName -match "(\d+)$") {
$vsnDecimal = $matches[1]
$vsnHex = "{0:X}" -f [int]$vsnDecimal
Write-Host " Volume Serial (Decimal): $vsnDecimal" -ForegroundColor Cyan
Write-Host " Volume Serial (Hex): $vsnHex" -ForegroundColor Green
}
# Display all properties
$entry.PSObject.Properties | Where-Object { $_.Name -notlike "PS*" } | ForEach-Object {
Write-Host " $($_.Name): $($_.Value)" -ForegroundColor Gray
}
}
} else {
Write-Host "[!] EMDMgmt key not found (common on modern systems)" -ForegroundColor Yellow
}Method 3: Cross-Reference with LNK Files (Most Reliable)
LNK files contain VSN! Extract from LNK files and correlate back to USB devices.
Using LECmd (Zimmerman Tool):
REM Parse LNK files
LECmd.exe -d "C:\Users\Alice\AppData\Roaming\Microsoft\Windows\Recent" --csv "C:\Cases\Output" --csvf lnk.csv -q
REM Filter CSV for:
REM - DriveType = "Removable"
REM - VolumeSerialNumber column
REM This gives you VSN of USB devices that had files accessedStep 5: Correlate Device to File Access (THE KEY CORRELATION)
Critical Workflow:
Extract USB Device Info:
Device serial number (USBSTOR)
Connection timestamps (Properties keys)
User who accessed it (MountPoints2)
Extract VSN:
From Event 1006 or EMDMgmt
OR from LNK files (DriveType = Removable)
Find LNK Files with Matching VSN:
Parse all LNK files with LECmd
Filter for matching VolumeSerialNumber
These LNK files = files accessed from that USB
Build Timeline:
USB connected at time X
Files accessed (LNK timestamps)
USB disconnected at time Y
Complete Correlation Script:
<#
.SYNOPSIS
Complete USB to file access correlation
.DESCRIPTION
Links USB devices to files accessed via VSN correlation
.NOTES
Requires LECmd to parse LNK files first
#>
param(
[string]$LnkCsvPath = "C:\Cases\Output\lnk.csv",
[string]$OutputPath = "C:\Cases\USB_File_Correlation.txt"
)
Write-Host "`n[+] USB Device to File Access Correlation" -ForegroundColor Cyan
Write-Host "=" * 80
# Check if LNK CSV exists
if (-not (Test-Path $LnkCsvPath)) {
Write-Host "[!] LNK CSV not found at: $LnkCsvPath" -ForegroundColor Red
Write-Host "[!] Run LECmd first: LECmd.exe -d 'C:\Users' --csv 'C:\Cases\Output' --csvf lnk.csv -q" -ForegroundColor Yellow
exit
}
# Import LNK data
Write-Host "[*] Loading LNK file data..." -ForegroundColor Yellow
$lnkData = Import-Csv $LnkCsvPath
# Filter for removable drives
$usbFiles = $lnkData | Where-Object { $_.DriveType -eq "Removable" -or $_.DriveType -eq "2" }
if ($usbFiles) {
Write-Host "[*] Found $($usbFiles.Count) LNK files from removable drives" -ForegroundColor Green
# Group by Volume Serial Number
$byVsn = $usbFiles | Group-Object VolumeSerialNumber
"=" * 80 | Out-File $OutputPath
"USB DEVICE TO FILE ACCESS CORRELATION - $(Get-Date)" | Out-File $OutputPath -Append
"=" * 80 | Out-File $OutputPath -Append
foreach ($vsnGroup in $byVsn) {
$vsn = $vsnGroup.Name
$files = $vsnGroup.Group
"`n--- Volume Serial Number: $vsn ---" | Out-File $OutputPath -Append
"Total Files Accessed: $($files.Count)" | Out-File $OutputPath -Append
"`nFiles:" | Out-File $OutputPath -Append
Write-Host "`n--- Volume Serial Number: $vsn ---" -ForegroundColor Yellow
Write-Host "Files accessed: $($files.Count)" -ForegroundColor Cyan
$files | ForEach-Object {
$entry = " $($_.TargetCreated) | $($_.TargetPath)"
Write-Host $entry -ForegroundColor Gray
$entry | Out-File $OutputPath -Append
}
}
Write-Host "`n[+] Correlation saved to: $OutputPath" -ForegroundColor Green
# Summary by VSN
Write-Host "`n[*] Summary by Volume Serial Number:" -ForegroundColor Yellow
$byVsn | ForEach-Object {
Write-Host " VSN $($_.Name): $($_.Count) files" -ForegroundColor Cyan
}
} else {
Write-Host "[!] No LNK files from removable drives found" -ForegroundColor Red
}Step 6: Identify Drive Letter Assignments
Registry Location: SYSTEM\MountedDevices
Caveat: Only shows LAST drive letter assignment (no historical record)
PowerShell - Check Drive Letters:
<#
.SYNOPSIS
Check USB drive letter assignments
#>
Write-Host "[+] Checking Drive Letter Assignments..." -ForegroundColor Cyan
$mountedDevices = "HKLM:\SYSTEM\MountedDevices"
if (Test-Path $mountedDevices) {
$props = Get-ItemProperty $mountedDevices
# Filter for DosDevices (drive letters)
$props.PSObject.Properties | Where-Object { $_.Name -like "\DosDevices\*" } | ForEach-Object {
$driveLetter = $_.Name -replace "\\DosDevices\\", ""
$data = $_.Value
# Try to extract serial number from data
if ($data) {
$dataString = [System.Text.Encoding]::Unicode.GetString($data)
Write-Host "`n Drive: $driveLetter" -ForegroundColor Yellow
Write-Host " Data: $($dataString -replace '\x00', '')" -ForegroundColor Gray
}
}
} else {
Write-Host "[!] MountedDevices key not found" -ForegroundColor Red
}Complete USB Investigation Script
<#
.SYNOPSIS
Comprehensive USB Device Investigation
.DESCRIPTION
Performs complete USB forensic analysis
#>
param(
[string]$OutputPath = "C:\Cases\USB_Investigation"
)
# Create output directory
New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null
Write-Host "`nββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Cyan
Write-Host "β USB DEVICE FORENSIC INVESTIGATION β" -ForegroundColor Cyan
Write-Host "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Cyan
Write-Host "Computer: $env:COMPUTERNAME" -ForegroundColor Yellow
Write-Host "Output: $OutputPath`n" -ForegroundColor Yellow
# Helper function
function Convert-FileTimeToDateTime {
param([byte[]]$FileTimeBytes)
if ($FileTimeBytes.Length -ge 8) {
try {
$fileTime = [BitConverter]::ToInt64($FileTimeBytes, 0)
return [DateTime]::FromFileTime($fileTime)
} catch {
return "Unable to parse"
}
}
return "No data"
}
# ============================================================================
# 1. ENUMERATE USB DEVICES
# ============================================================================
Write-Host "[1/5] Enumerating USB Storage Devices..." -ForegroundColor Yellow
$devicesOutput = "$OutputPath\01_USB_Devices.txt"
"=" * 80 | Out-File $devicesOutput
"USB STORAGE DEVICES - $(Get-Date)" | Out-File $devicesOutput -Append
"=" * 80 | Out-File $devicesOutput -Append
$usbStorPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR"
if (Test-Path $usbStorPath) {
$deviceCount = 0
Get-ChildItem $usbStorPath | ForEach-Object {
$deviceKey = $_
$deviceInfo = $_.PSChildName
if ($deviceInfo -match "Disk&Ven_(.+)&Prod_(.+)&Rev_(.+)") {
$vendor = $matches[1].Trim("_")
$product = $matches[2].Trim("_")
$revision = $matches[3].Trim("_")
"`n--- Device #$($deviceCount + 1) ---" | Out-File $devicesOutput -Append
"Vendor: $vendor" | Out-File $devicesOutput -Append
"Product: $product" | Out-File $devicesOutput -Append
"Revision: $revision" | Out-File $devicesOutput -Append
# Get serial numbers
Get-ChildItem $deviceKey.PSPath | ForEach-Object {
$serial = $_.PSChildName
$props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
"`nSerial Number: $serial" | Out-File $devicesOutput -Append
if ($serial.Length -ge 2 -and $serial[1] -eq '&') {
" Type: Windows-Generated (Device lacks unique serial)" | Out-File $devicesOutput -Append
} else {
" Type: Device Unique Serial" | Out-File $devicesOutput -Append
}
if ($props.FriendlyName) {
" Friendly Name: $($props.FriendlyName)" | Out-File $devicesOutput -Append
}
if ($props.ParentIdPrefix) {
" ParentIdPrefix: $($props.ParentIdPrefix)" | Out-File $devicesOutput -Append
}
}
$deviceCount++
}
}
"`n`nTotal Devices: $deviceCount" | Out-File $devicesOutput -Append
Write-Host " [β] Found $deviceCount USB devices" -ForegroundColor Green
} else {
"[!] USBSTOR key not found" | Out-File $devicesOutput
Write-Host " [!] USBSTOR key not found" -ForegroundColor Red
}
# ============================================================================
# 2. EXTRACT CONNECTION TIMESTAMPS
# ============================================================================
Write-Host "[2/5] Extracting Connection Timestamps..." -ForegroundColor Yellow
$timestampsOutput = "$OutputPath\02_Connection_Timestamps.txt"
"=" * 80 | Out-File $timestampsOutput
"USB CONNECTION TIMESTAMPS - $(Get-Date)" | Out-File $timestampsOutput -Append
"=" * 80 | Out-File $timestampsOutput -Append
if (Test-Path $usbStorPath) {
Get-ChildItem $usbStorPath | ForEach-Object {
$deviceKey = $_
Get-ChildItem $deviceKey.PSPath | ForEach-Object {
$serialKey = $_
$serial = $_.PSChildName
$propsPath = Join-Path $serialKey.PSPath "Properties\{83da6326-97a6-4088-9453-a19231573b29}"
if (Test-Path $propsPath) {
"`n--- Serial: $serial ---" | Out-File $timestampsOutput -Append
# First Install (0064)
$firstInstall = Get-ItemProperty "$propsPath\0064" -Name "(default)" -ErrorAction SilentlyContinue
if ($firstInstall) {
$time = Convert-FileTimeToDateTime $firstInstall.'(default)'
"First Install (UTC): $time" | Out-File $timestampsOutput -Append
}
# Last Connected (0066)
$lastConnected = Get-ItemProperty "$propsPath\0066" -Name "(default)" -ErrorAction SilentlyContinue
if ($lastConnected) {
$time = Convert-FileTimeToDateTime $lastConnected.'(default)'
"Last Connected (UTC): $time" | Out-File $timestampsOutput -Append
}
# Last Removal (0067)
$lastRemoval = Get-ItemProperty "$propsPath\0067" -Name "(default)" -ErrorAction SilentlyContinue
if ($lastRemoval) {
$time = Convert-FileTimeToDateTime $lastRemoval.'(default)'
"Last Removal (UTC): $time" | Out-File $timestampsOutput -Append
}
}
}
}
Write-Host " [β] Timestamps extracted" -ForegroundColor Green
}
# ============================================================================
# 3. CHECK USER ATTRIBUTION
# ============================================================================
Write-Host "[3/5] Checking User Attribution (MountPoints2)..." -ForegroundColor Yellow
$userOutput = "$OutputPath\03_User_Attribution.txt"
"=" * 80 | Out-File $userOutput
"USER ATTRIBUTION - $(Get-Date)" | Out-File $userOutput -Append
"=" * 80 | Out-File $userOutput -Append
$mountPoints = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2"
if (Test-Path $mountPoints) {
"`n--- Current User: $env:USERNAME ---" | Out-File $userOutput -Append
$entries = Get-ChildItem $mountPoints
if ($entries) {
"Found $($entries.Count) mount points" | Out-File $userOutput -Append
foreach ($entry in $entries) {
$guid = $entry.PSChildName
if ($guid -like "{*}") {
"`n Volume GUID: $guid" | Out-File $userOutput -Append
}
}
} else {
"No mount points found for current user" | Out-File $userOutput -Append
}
} else {
"MountPoints2 key not found" | Out-File $userOutput -Append
}
Write-Host " [β] User attribution checked" -ForegroundColor Green
Write-Host " [!] For all users, analyze offline NTUSER.DAT hives" -ForegroundColor Yellow
# ============================================================================
# 4. CHECK DRIVE LETTER ASSIGNMENTS
# ============================================================================
Write-Host "[4/5] Checking Drive Letter Assignments..." -ForegroundColor Yellow
$driveOutput = "$OutputPath\04_Drive_Letters.txt"
"=" * 80 | Out-File $driveOutput
"DRIVE LETTER ASSIGNMENTS - $(Get-Date)" | Out-File $driveOutput -Append
"=" * 80 | Out-File $driveOutput -Append
"`n[!] Only shows LAST assignment (no historical)" | Out-File $driveOutput -Append
$mountedDevices = "HKLM:\SYSTEM\MountedDevices"
if (Test-Path $mountedDevices) {
$props = Get-ItemProperty $mountedDevices
"`nRemovable Drive Letters:" | Out-File $driveOutput -Append
$props.PSObject.Properties | Where-Object { $_.Name -like "\DosDevices\[E-Z]:*" } | ForEach-Object {
$driveLetter = $_.Name -replace "\\DosDevices\\", ""
" Drive: $driveLetter" | Out-File $driveOutput -Append
}
}
Write-Host " [β] Drive letters checked" -ForegroundColor Green
# ============================================================================
# 5. CHECK SETUPAPI.DEV.LOG
# ============================================================================
Write-Host "[5/5] Checking setupapi.dev.log..." -ForegroundColor Yellow
$setupapiOutput = "$OutputPath\05_Setupapi_Log.txt"
"=" * 80 | Out-File $setupapiOutput
"SETUPAPI.DEV.LOG ANALYSIS - $(Get-Date)" | Out-File $setupapiOutput -Append
"=" * 80 | Out-File $setupapiOutput -Append
"`n[!] WARNING: Timestamps are in LOCAL TIMEZONE (not UTC)" | Out-File $setupapiOutput -Append
$setupapiPath = "C:\Windows\inf\setupapi.dev.log"
if (Test-Path $setupapiPath) {
$content = Get-Content $setupapiPath -Tail 100
"`nLast 100 lines:" | Out-File $setupapiOutput -Append
$content | Out-File $setupapiOutput -Append
Write-Host " [β] setupapi.dev.log saved (last 100 lines)" -ForegroundColor Green
} else {
"[!] setupapi.dev.log not found" | Out-File $setupapiOutput
Write-Host " [!] setupapi.dev.log not found" -ForegroundColor Red
}
# ============================================================================
# GENERATE SUMMARY
# ============================================================================
$summaryOutput = "$OutputPath\00_INVESTIGATION_SUMMARY.txt"
@"
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USB DEVICE INVESTIGATION SUMMARY β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Investigation Date: $(Get-Date)
Computer: $env:COMPUTERNAME
Analyst: $env:USERNAME
ANALYSIS PERFORMED:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[β] USB Device Enumeration (USBSTOR)
[β] Connection Timestamps (Properties keys, 0064/0066/0067)
[β] User Attribution (MountPoints2 - current user)
[β] Drive Letter Assignments (MountedDevices)
[β] setupapi.dev.log Analysis
OUTPUT FILES:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
01_USB_Devices.txt β All USB devices ever connected
02_Connection_Timestamps.txt β First/last connection times
03_User_Attribution.txt β User mount points (current user only)
04_Drive_Letters.txt β Drive letter assignments
05_Setupapi_Log.txt β Setup log (last 100 lines)
CRITICAL NEXT STEPS:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. Parse LNK files with LECmd to get Volume Serial Numbers:
LECmd.exe -d "C:\Users" --csv "$OutputPath" --csvf lnk.csv -q
2. Filter LNK CSV for DriveType = "Removable" to find USB file access
3. Correlate Volume Serial Number (VSN) from:
- Event ID 1006 (Microsoft-Windows-Partition/Diagnostic.evtx)
- EMDMgmt registry key (if available)
- LNK files (VolumeSerialNumber column)
4. Match VSN to USB device to prove file access
5. For all users' MountPoints2, load offline NTUSER.DAT hives:
reg load "HKU\TempUser" "C:\Users\[username]\NTUSER.DAT"
reg query "HKU\TempUser\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2"
6. Build complete timeline:
- USB connected (timestamps)
- Files accessed (LNK files)
- USB disconnected (timestamps)
KEY INVESTIGATION PRINCIPLES:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Volume Serial Number (VSN) is THE KEY to linking USB to files
β VSN != USB Unique Serial (different identifiers!)
β setupapi.dev.log timestamps are LOCAL timezone (not UTC!)
β Only last drive letter assignment stored (no historical)
β MountPoints2 proves user accessed specific USB (per-user attribution)
β Windows 10/11 stores up to 1 year of USB data
TOOLS REQUIRED:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LECmd.exe (LNK file parser) - CRITICAL for VSN extraction
β Registry Explorer - For offline registry analysis
β USBDeview - Alternative GUI tool
Download: https://ericzimmerman.github.io/
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
"@ | Out-File $summaryOutput
Write-Host "`nββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Green
Write-Host "β INVESTIGATION COMPLETE β" -ForegroundColor Green
Write-Host "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Green
Write-Host "`nResults: $OutputPath" -ForegroundColor Cyan
Write-Host "Review: 00_INVESTIGATION_SUMMARY.txt`n" -ForegroundColor Yellow
Write-Host "[!] CRITICAL NEXT STEP: Parse LNK files for file access evidence" -ForegroundColor Red
Write-Host " Command: LECmd.exe -d 'C:\Users' --csv '$OutputPath' --csvf lnk.csv -q`n" -ForegroundColor WhiteReal Investigation Scenarios
Scenario 1: Data Exfiltration via USB
Evidence Chain:
1. USBSTOR: Kingston USB 32GB connected
2. Timestamps: First connected 2024-11-29 14:23 UTC
3. MountPoints2: Alice's account has Volume GUID entry
4. LECmd: 50 LNK files with DriveType="Removable", VSN=1A2B-3C4D
5. LNK files: HR_Salaries_2024.xlsx, Customer_Database.sql
6. Timestamps: Last removal 2024-11-29 15:45 UTC
7. Recycle Bin: Original files deleted after USB copy
CONCLUSION: Alice copied sensitive files to USB, then deleted originalsTimeline:
14:23 - USB connected (USBSTOR timestamp 0066)
14:30 - Files accessed from C:\ (Recent Files)
14:35 - Files copied to USB (LNK with VSN=1A2B-3C4D)
14:40 - Original files deleted (Recycle Bin)
15:45 - USB disconnected (USBSTOR timestamp 0067)Scenario 2: Unauthorised Device Usage
Evidence Chain:
1. USBSTOR: Unknown brand "Generic USB" (suspicious)
2. Serial: Has & in 2nd position = Windows-generated (no unique serial)
3. Timestamps: Connected 02:30 AM (off-hours)
4. MountPoints2: Bob's account accessed device
5. LECmd: malware.exe accessed from USB (VSN=9876-5432)
6. Prefetch: malware.exe executed shortly after
CONCLUSION: Unauthorised USB containing malware used by BobScenario 3: VSN Correlation Success
Investigation Steps:
1. Find LNK file: secret_document.xlsx.lnk
2. Extract VSN from LNK: AB12-CD34
3. Search EMDMgmt or Event 1006 for VSN=AB12-CD34
4. Match to Kingston USB serial XXXXX
5. Check USBSTOR timestamps for that serial
6. Check MountPoints2 for user attribution
RESULT: Proved file accessed from specific USB device by specific userQuick Reference Commands
Registry Queries
REM USB devices
reg query "HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR"
REM Connection timestamps
reg query "HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR\Disk&Ven*" /s
REM User mount points
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2"
REM Drive letters
reg query "HKLM\SYSTEM\MountedDevices"
REM Volume serial numbers (legacy)
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EMDMgmt"PowerShell One-Liners
# List USB devices
Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR" | ForEach-Object {$_.PSChildName}
# Current user mount points
Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2" | Select-Object PSChildName
# Event 1006 (last 20)
Get-WinEvent -Path "C:\Windows\System32\winevt\Logs\Microsoft-Windows-Partition%4Diagnostic.evtx" -FilterXPath "*[System[EventID=1006]]" -MaxEvents 20 | Select-Object TimeCreated, MessageInvestigation Checklists
USB Data Exfiltration Investigation
[ ] Enumerate all USB devices (USBSTOR)
[ ] Extract connection timestamps (Properties 0064/0066/0067)
[ ] Identify Windows-generated serials (& in 2nd position)
[ ] Check MountPoints2 for user attribution
[ ] Parse LNK files with LECmd
[ ] Filter LNK for DriveType = "Removable"
[ ] Extract Volume Serial Numbers from LNK files
[ ] Correlate VSN to USB device
[ ] Build timeline: connect β access β disconnect
[ ] Check for file deletion (Recycle Bin)
[ ] Cross-reference with Recent Files registry
[ ] Document complete evidence chain
Unauthorised Device Investigation
[ ] Identify unknown/suspicious devices (USBSTOR)
[ ] Check connection times (off-hours indicator)
[ ] Verify authorised device list
[ ] Check user attribution (MountPoints2)
[ ] Look for malware/suspicious files (LNK + Prefetch)
[ ] Review execution artifacts (Prefetch, BAM)
[ ] Check for policy violations
[ ] Document user and device details
Timeline Construction
[ ] Extract all timestamp sources (0064/0066/0067)
[ ] Parse setupapi.dev.log (LOCAL timezone!)
[ ] Parse Event 1006 (if available)
[ ] Extract LNK file access times
[ ] Correlate all timestamps in single timeline
[ ] Note timezone differences
[ ] Build narrative of events
USB Forensics Tools
Essential Tools
Zimmerman Tools:
LECmd - LNK file parser (CRITICAL for VSN extraction)
Registry Explorer - Offline registry analysis
Timeline Explorer - Timeline visualisation
NirSoft:
USBDeview - GUI USB device viewer
USBLogView - setupapi.dev.log parser
Microsoft:
Registry Editor - Live registry queries
Event Viewer - Event 1006 analysis
Best Practices
Live Response
β DO:
Collect registry hives (SYSTEM, SOFTWARE, NTUSER.DAT)
Copy setupapi.dev.log immediately
Export Event 1006 before it's cleared
Collect all LNK files from all users
Document current time and timezone
Hash all collected artifacts
β DON'T:
Plug in your own USB (creates new entries!)
Modify registry during investigation
Forget timezone differences (setupapi = LOCAL)
Skip LNK file collection (VSN source!)
Offline Analysis
β DO:
Load registry hives read-only
Parse all user NTUSER.DAT files
Correlate VSN across all sources
Cross-reference with LNK files
Build complete timeline
Validate all correlations
β DON'T:
Rely on single artifact
Skip VSN correlation
Ignore setupapi timezone
Forget about Windows-generated serials
Summary: Critical Takeaways
The Most Important Concept
Volume Serial Number (VSN) is THE KEY:
USB Device β VSN assigned β Files accessed β LNK created with VSN
VSN in LNK file = VSN from USB = PROOF of file access from that USBKey Differences to Remember
USB Unique Serial
Identifies physical USB
USBSTOR registry
Volume Serial Number (VSN)
Identifies file system
LNK files, Event 1006
Printed Serial
Marketing label
Physical device
Top 5 USB Investigation Steps
USBSTOR - Identify devices connected
Timestamps - When connected (0064/0066/0067)
MountPoints2 - Who accessed device
VSN - Extract from LNK files
Correlation - Match VSN to prove file access
Critical Registry Paths
Device Identity:
SYSTEM\CurrentControlSet\Enum\USBSTOR\{Device}\{Serial}
Timestamps:
SYSTEM\CurrentControlSet\Enum\USBSTOR\{Device}\{Serial}\Properties\{83da6326-...}\0064|0066|0067
User Attribution:
NTUSER.DAT\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2
VSN (Legacy):
SOFTWARE\Microsoft\Windows NT\CurrentVersion\EMDMgmtKey Principle
USB forensics requires correlation of multiple artifacts. The Volume Serial Number (VSN) from LNK files is your most reliable evidence linking a USB device to specific file access. Always cross-reference USBSTOR, timestamps, MountPoints2, and LNK files to build complete evidence chain.
Remember: Volume Serial Number (VSN) is THE critical link between USB devices and files accessed. Extract VSN from LNK files (DriveType=Removable) and correlate with USB device records. This proves which files were accessed from which USB device!
Last updated