Case file TH-007. The workstation was fully patched, EDR was healthy, and email filtering had caught every phishing attempt that month. The malware still got in — carried through the front door on a USB stick someone found in the parking lot. Within two minutes of the drive being plugged in, a file named
autorun.inf appeared in its root, and a registry Run key was created pointing at E:\RECYCLER\sys.exe. The endpoint rebooted that night, the payload ran at logon, and the hunt began.
USB-borne malware never went away; it just stopped being fashionable to talk about. Worms like Raspberry Robin still spread through removable media, and targeted operators use USB drops against air-gapped or high-security networks precisely because everyone assumes the vector is dead. The forensic trail is distinctive and short-lived: a mount event, a file drop, a persistence write, and execution from the removable volume. If you know the sequence, you can hunt it in minutes.
The hypothesis
If removable media is being used to deliver or persist malware, then endpoints will show USB mount events closely followed — within minutes — by autorun-style artifacts: autorun.inf drops, Run/RunOnce or Winlogon persistence pointing at the removable volume, or process execution from a removable drive letter.
Data you'll need
| Source | What it gives you |
|---|---|
DeviceEvents (UsbDriveMounted) | Every USB insertion: drive letter, serial number, volume, user, timestamp. |
| DeviceRegistryEvents | Run-key and Winlogon persistence writes and the process that made them. |
| DeviceFileEvents | autorun.inf drops and payload staging on the removable volume. |
| DeviceProcessEvents | Execution with an image path on the removable drive. |
Splunk: index=wineventlog + Sysmon | Event 6416 (new external device), Sysmon 11 (file create), Sysmon 13 (registry set). |
Hunting with KQL
This query anchors on the mount event and then looks for persistence writes on the same device within 30 minutes. The 30-minute window is deliberate: worms persist fast, before the user unplugs the drive.
// Hunt H-USB-01: persistence written within 30 minutes of a USB mount
let Mounts =
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType == "UsbDriveMounted"
| extend P = parse_json(AdditionalFields)
| project DeviceId, DeviceName, DriveLetter = tostring(P.DriveLetter),
Serial = tostring(P.SerialNumber), MountTime = Timestamp;
let Persistence =
DeviceRegistryEvents
| where Timestamp > ago(7d)
| where RegistryKey has @"\Microsoft\Windows\CurrentVersion\Run"
or RegistryKey has @"\Microsoft\Windows NT\CurrentVersion\Winlogon"
| where RegistryValueData matches regex @"(?i)^[D-Z]:\\"
| project RegTime = Timestamp, DeviceId, DeviceName, RegistryKey,
RegistryValueName, RegistryValueData, InitiatingProcessFileName,
InitiatingProcessCommandLine;
Mounts
| join kind=inner (Persistence) on DeviceId
| where RegTime between (MountTime .. MountTime + 30m)
| project MountTime, DeviceName, DriveLetter, Serial, RegistryValueName,
RegistryValueData, InitiatingProcessFileName
| order by MountTime desc
What this does, in plain English: it lists every USB drive plugged in over the last week, then checks whether anything wrote an auto-start entry pointing at a non-system drive letter (D: through Z:) on that same machine within half an hour of the mount. Legitimate installers persist from C:\; malware staging from a thumb drive persists from E:\ or F:\ — and that distinction is the whole hunt.
Walkthrough: how the query reads the evidence
ActionType == "UsbDriveMounted"gives you the anchor: the exact moment and drive letter of each insertion, plus the device serial for pivoting.- The registry filter targets the classic persistence locations —
Run,RunOnce, andWinlogon— where USB worms have written themselves for twenty years. matches regex @"(?i)^[D-Z]:\\"keeps only persistence pointing at removable-style drive letters, excludingC:\. This one line removes roughly 99% of benign Run-key noise.- The
between (MountTime .. MountTime + 30m)temporal join is the causality test: persistence that appears right after a mount is evidence; persistence from last month is coincidence. InitiatingProcessFileNametells you what wrote the key —explorer.exeor a script host launched from the drive is far more suspicious thanmsiexec.exe.
Bonus triage query — sweep for the classic worm marker file across the fleet:
DeviceFileEvents
| where Timestamp > ago(7d)
| where FileName =~ "autorun.inf"
| project Timestamp, DeviceName, FolderPath, InitiatingProcessFileName,
InitiatingProcessCommandLine, SHA256
| order by Timestamp desc
Example: what a true positive looks like
| Field | Value | Why it matters |
|---|---|---|
DeviceName | DESKTOP-FIN03 | Finance workstation — data worth stealing |
MountTime / DriveLetter | 2026-09-19 09:41:02 / E: | Unknown serial, never seen in the fleet before |
RegistryValueName / RegistryValueData | "WindowsUpdate" / E:\RECYCLER\sys.exe | Run key written 3 minutes after mount, masquerading as a system component |
InitiatingProcessFileName | explorer.exe | Written via shell interaction with the drive — the classic worm behavior |
Hunting with Splunk
Same chain, built from Windows event logs and Sysmon: device arrival (6416), then file and registry writes tied to the same host inside a 30-minute window.
index=wineventlog EventCode=6416 (ClassName="USB*" OR DeviceDescription="*USB*")
| rename ComputerName as host, _time as mount_time
| stats earliest(mount_time) as mount_time values(DeviceDescription) as usb_device by host
| join host [
search index=wineventlog (EventCode=11 TargetFilename="*autorun.inf")
OR (EventCode=13 TargetObject="*\\CurrentVersion\\Run*")
| rename ComputerName as host
| stats earliest(_time) as artifact_time values(TargetFilename) as files
values(TargetObject) as reg_keys by host
]
| where artifact_time > mount_time AND (artifact_time - mount_time) < 1800
| table host, usb_device, mount_time, artifact_time, files, reg_keys
What this does, in plain English: it finds every host where a USB device arrived, then checks whether an autorun.inf file or a Run-key registry write appeared on that same host within 30 minutes (1800 seconds) of the arrival. Hosts passing both tests go on the investigation list.
Example hit
host=DESKTOP-FIN03 usb_device="USB Mass Storage Device" mount_time=2026-09-19 09:41:02 artifact_time=2026-09-19 09:44:17 files=E:\autorun.inf reg_keys=HKLM\...\Run\WindowsUpdate -> E:\RECYCLER\sys.exe
Validating the hit
- Identify the drive. Pivot on the serial number across
DeviceEvents— has this physical stick touched other endpoints? A serial appearing on five machines in a day is a worm spreading, not a one-off. - Recover and analyze the payload. Pull the hash of the referenced executable and detonate it in a sandbox. Check whether it beaconed — look at
DeviceNetworkEventsfrom the host in the hour after the mount. - Reconstruct the execution chain. In
DeviceProcessEvents, walk from the mount forward: what launched the payload, did it spawn children (cmd.exe,powershell.exe,rundll32.exe), and did it touch credentials? - Check the human. Who was logged on at mount time, and where did the drive come from — parking lot, vendor, conference swag? The source shapes the whole response.
Tuning out false positives
- Corporate deployment media: IT's imaging and software-install USBs write Run keys legitimately. Allowlist known serials and volume labels.
- Encrypted corporate drives: BitLocker-to-Go and sanctioned encrypted sticks mount constantly — exclude devices matching your standard volume label pattern.
- Vendor installer artifacts: some hardware vendors still ship an
autorun.infon driver media. A file created at mount time by a user process is suspicious; one that arrived with the factory image is not. - Portable apps and user habits: users running portable tools from personal drives generate mount events all day. The query only fires on persistence writes, so most of this noise is already filtered — keep it that way.
What to do next
- Isolate the host and physically secure the USB stick — it is evidence now, not office supplies.
- Block the device by serial in Defender device control so it cannot mount anywhere else in the fleet.
- Reimage the endpoint rather than "cleaning" it; assume credential exposure for any account that logged on after the mount and rotate accordingly.
- Sweep the fleet for the same serial number and the same payload hash — worms do not stop at one machine.
- Fix the policy gap: enforce device control (deny-by-default for removable storage, allowlist exceptions), disable AutoRun/AutoPlay via GPO, and run the parking-lot-USB security reminder. It works better than you'd think.
The cheapest initial access in the world still fits in a pocket. Hunt the mount, not the malware. — Amit Vijayan
This sample preserves the article’s original text and publication date, restyled for Amit’s personal website. Older material may describe historical tools or techniques.
Read the original article on Blogger