Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
T1046 on the official MITRE ATT&CK siteT1053 on the official MITRE ATT&CK siteT1053.002 on the official MITRE ATT&CK siteT1053.003 on the official MITRE ATT&CK siteT1053.005 on the official MITRE ATT&CK siteT1057 on the official MITRE ATT&CK siteT1082 on the official MITRE ATT&CK siteT1083 on the official MITRE ATT&CK siteT1547 on the official MITRE ATT&CK site
NIST CSF 2.0
When to Use
- When proactively hunting for indicators of hunting for scheduled task persistence in the environment
- After threat intelligence indicates active campaigns using these techniques
- During incident response to scope compromise related to these techniques
- When EDR or SIEM alerts trigger on related indicators
- During periodic security assessments and purple team exercises
Prerequisites
- EDR platform with process and network telemetry (CrowdStrike, MDE, SentinelOne)
- SIEM with relevant log data ingested (Splunk, Elastic, Sentinel)
- Sysmon deployed with comprehensive configuration
- Windows Security Event Log forwarding enabled
- Threat intelligence feeds for IOC correlation
Workflow
- Formulate Hypothesis: Define a testable hypothesis based on threat intelligence or ATT&CK gap analysis.
- Identify Data Sources: Determine which logs and telemetry are needed to validate or refute the hypothesis.
- Execute Queries: Run detection queries against SIEM and EDR platforms to collect relevant events.
- Analyze Results: Examine query results for anomalies, correlating across multiple data sources.
- Validate Findings: Distinguish true positives from false positives through contextual analysis.
- Correlate Activity: Link findings to broader attack chains and threat actor TTPs.
- Document and Report: Record findings, update detection rules, and recommend response actions.
Key Concepts
| Concept | Description |
|---|---|
| T1053.005 | Scheduled Task |
| T1053.003 | Cron |
| T1053.002 | At |
Tools & Systems
| Tool | Purpose |
|---|---|
| CrowdStrike Falcon | EDR telemetry and threat detection |
| Microsoft Defender for Endpoint | Advanced hunting with KQL |
| Splunk Enterprise | SIEM log analysis with SPL queries |
| Elastic Security | Detection rules and investigation timeline |
| Sysmon | Detailed Windows event monitoring |
| Velociraptor | Endpoint artifact collection and hunting |
| Sigma Rules | Cross-platform detection rule format |
Common Scenarios
- Scenario 1: Cobalt Strike persistence via schtasks creating periodic beacon
- Scenario 2: Ransomware scheduled task for re-execution after reboot
- Scenario 3: APT encoded PowerShell task running every 30 minutes
- Scenario 4: Insider task to periodically copy sensitive files
Output Format
Hunt ID: TH-HUNTIN-[DATE]-[SEQ]
Technique: T1053.005
Host: [Hostname]
User: [Account context]
Evidence: [Log entries, process trees, network data]
Risk Level: [Critical/High/Medium/Low]
Confidence: [High/Medium/Low]
Recommended Action: [Containment, investigation, monitoring]Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md1.5 KB
API Reference — Hunting for Scheduled Task Persistence
Libraries Used
- subprocess: Execute
schtasks /queryandschtasks /query /xmlfor task enumeration - csv: Parse schtasks CSV output for structured task analysis
- python-evtx (Evtx): Parse Security EVTX for Event ID 4698 (Task Created)
CLI Interface
python agent.py enumerate # List and risk-score all tasks
python agent.py events --evtx-file <path> # Scan EVTX for task creation events
python agent.py export --task-name <name> # Export task XML definitionCore Functions
enumerate_tasks()
Runs schtasks /query /fo CSV /v and classifies each task as high/medium/low risk.
Returns: dict with total_tasks, high_risk, medium_risk, suspicious_tasks, non_vendor_tasks.
scan_event_log_4698(evtx_file)
Parses Windows Security EVTX for Event ID 4698 (Scheduled Task Created).
Parameters:
| Name | Type | Description |
|---|---|---|
evtx_file |
str | Path to Security .evtx log file |
export_task_xml(task_name)
Exports a task's full XML definition using schtasks /query /tn <name> /xml.
Risk Classification
| Risk | Criteria |
|---|---|
| High | Action matches suspicious patterns (powershell -enc, certutil, temp paths) |
| Medium | Non-vendor task (not under \Microsoft\, \Google\, etc.) |
| Low | Known vendor task prefix |
Dependencies
pip install python-evtx # Optional, for EVTX parsingstandards.md1.5 KB
Standards and References - Hunting For Scheduled Task Persistence
MITRE ATT&CK Mappings
| Technique | Name | Description |
|---|---|---|
| T1053.005 | Scheduled Task | See attack.mitre.org/techniques/T1053/005 |
| T1053.003 | Cron | See attack.mitre.org/techniques/T1053/003 |
| T1053.002 | At | See attack.mitre.org/techniques/T1053/002 |
Detection Data Sources
| Source | Event ID | Purpose |
|---|---|---|
| Sysmon | 1 | Process creation with command line |
| Sysmon | 3 | Network connection initiated |
| Sysmon | 7 | Image loaded (DLL) |
| Sysmon | 10 | Process access (LSASS) |
| Sysmon | 11 | File creation |
| Sysmon | 12/13 | Registry create/set |
| Sysmon | 22 | DNS query |
| Sysmon | 25 | Process tampering |
| Windows Security | 4624 | Successful logon |
| Windows Security | 4625 | Failed logon |
| Windows Security | 4648 | Explicit credential logon |
| Windows Security | 4672 | Special privileges assigned |
| Windows Security | 4688 | Process creation |
| Windows Security | 4697 | Service installed |
| Windows Security | 4698 | Scheduled task created |
| Windows Security | 4769 | Kerberos TGS requested |
| Windows Security | 5140 | Network share accessed |
References
- MITRE ATT&CK Framework: https://attack.mitre.org/
- Sigma Detection Rules: https://github.com/SigmaHQ/sigma
- LOLBAS Project: https://lolbas-project.github.io/
- Atomic Red Team Tests: https://github.com/redcanaryco/atomic-red-team
- Red Canary Threat Detection Report
- SANS Threat Hunting Summit Resources
workflows.md2.8 KB
Detailed Hunting Workflow - Hunting For Scheduled Task Persistence
Phase 1: Data Collection and Querying
Splunk SPL Query
index=wineventlog (EventCode=4698 OR EventCode=106)
| where match(Task_Content, "(?i)(powershell|cmd|wscript|mshta|http|encoded)")
| table _time Computer User Task_Name Task_ContentKQL Query (Microsoft Defender for Endpoint)
DeviceEvents
| where ActionType == "ScheduledTaskCreated"
| where AdditionalFields has_any ("powershell","cmd","wscript","http")
| project Timestamp, DeviceName, AccountName, AdditionalFieldsPhase 2: Baseline and Anomaly Detection
Step 2.1 - Establish Normal Behavior Baseline
- Collect 30 days of historical data for the targeted technique
- Document expected patterns, frequencies, and legitimate use cases
- Identify known false positive sources and document exceptions
- Build statistical baseline (mean, standard deviation) for key metrics
Step 2.2 - Identify Anomalies
- Compare current activity against the 30-day baseline
- Flag events exceeding 3 standard deviations from normal
- Prioritize anomalies by risk score and potential business impact
- Cross-reference with threat intelligence for known IOCs
Phase 3: Investigation and Correlation
Step 3.1 - Deep Dive Analysis
- For each anomaly, collect full process tree context
- Correlate with network activity, file operations, and authentication events
- Check binary signatures, file hashes, and certificate validity
- Review user account context and access patterns
Step 3.2 - Attack Chain Reconstruction
- Map findings to MITRE ATT&CK kill chain stages
- Identify initial access vector if applicable
- Trace lateral movement and privilege escalation paths
- Determine data access and potential exfiltration
Phase 4: Validation and Response
Step 4.1 - True/False Positive Determination
- Verify findings with system owners and IT operations
- Check change management records for authorized activities
- Validate user context (authorized actions vs. compromised account)
- Document determination rationale for each finding
Step 4.2 - Response Actions
- For confirmed threats: initiate incident response procedures
- For detection gaps: create or update detection rules
- For false positives: tune existing rules and update exclusions
- Update threat hunting playbook with lessons learned
Phase 5: Documentation and Reporting
Step 5.1 - Hunt Report
- Summarize hypothesis, methodology, and findings
- Include all queries executed and their results
- Document IOCs discovered and detection rules created
- Provide recommendations for security improvements
Step 5.2 - Knowledge Base Update
- Add findings to threat intelligence platform
- Update MITRE ATT&CK coverage heatmap
- Share detection rules via Sigma format
- Schedule follow-up hunts for related techniques
Scripts 2
agent.py4.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for hunting scheduled task persistence mechanisms (T1053.005)."""
import json
import argparse
import subprocess
import re
import csv
from io import StringIO
from datetime import datetime
SUSPICIOUS_TASK_PATTERNS = [
r"powershell.*-enc", r"powershell.*downloadstring", r"powershell.*iex",
r"cmd\.exe\s+/c", r"mshta\.exe", r"rundll32\.exe", r"regsvr32\.exe",
r"certutil.*-decode", r"bitsadmin.*transfer",
r"wscript\.exe", r"cscript\.exe",
r"\\temp\\", r"\\tmp\\", r"\\appdata\\local\\temp",
r"\\users\\public\\", r"\\programdata\\",
r"base64", r"http://", r"https://.*\.exe",
]
LEGITIMATE_TASK_PREFIXES = [
r"\\Microsoft\\", r"\\Adobe\\", r"\\Google\\", r"\\Apple\\",
r"\\Mozilla\\", r"\\Intel\\", r"\\NVIDIA\\",
]
def enumerate_tasks():
"""Enumerate all scheduled tasks and flag suspicious ones."""
try:
proc = subprocess.run(
["schtasks", "/query", "/fo", "CSV", "/v"],
capture_output=True, text=True, timeout=60
)
except (subprocess.TimeoutExpired, FileNotFoundError) as e:
return {"error": str(e)}
findings = []
reader = csv.DictReader(StringIO(proc.stdout))
for row in reader:
task_name = row.get("TaskName", "")
action = row.get("Task To Run", "")
author = row.get("Author", "")
schedule = row.get("Schedule Type", "")
status = row.get("Status", "")
is_legit = any(re.search(p, task_name, re.I) for p in LEGITIMATE_TASK_PREFIXES)
is_suspicious = any(re.search(p, action, re.I) for p in SUSPICIOUS_TASK_PATTERNS)
risk = "high" if is_suspicious else ("low" if is_legit else "medium")
findings.append({
"task_name": task_name,
"action": action[:500],
"author": author,
"schedule": schedule,
"status": status,
"last_run": row.get("Last Run Time", ""),
"next_run": row.get("Next Run Time", ""),
"run_as_user": row.get("Run As User", ""),
"risk": risk,
"suspicious_match": is_suspicious,
})
suspicious = [f for f in findings if f["risk"] in ("high", "medium")]
return {
"timestamp": datetime.utcnow().isoformat(),
"total_tasks": len(findings),
"high_risk": sum(1 for f in findings if f["risk"] == "high"),
"medium_risk": sum(1 for f in findings if f["risk"] == "medium"),
"suspicious_tasks": [f for f in findings if f["suspicious_match"]],
"non_vendor_tasks": [f for f in findings if f["risk"] == "medium"],
}
def scan_event_log_4698(evtx_file):
"""Parse Security EVTX for Event ID 4698 (Scheduled Task Created)."""
try:
import Evtx.Evtx as evtx_lib
except ImportError:
return {"error": "python-evtx not installed"}
findings = []
with evtx_lib.Evtx(evtx_file) as log:
for record in log.records():
xml = record.xml()
if "<EventID>4698</EventID>" not in xml:
continue
suspicious = any(re.search(p, xml, re.I) for p in SUSPICIOUS_TASK_PATTERNS)
findings.append({
"record_id": record.record_num(),
"suspicious": suspicious,
"xml_snippet": xml[:1000],
})
return {
"file": evtx_file,
"task_creation_events": len(findings),
"suspicious_events": sum(1 for f in findings if f["suspicious"]),
"findings": findings[:200],
}
def export_task_xml(task_name):
"""Export a specific scheduled task's XML configuration for analysis."""
try:
proc = subprocess.run(
["schtasks", "/query", "/tn", task_name, "/xml"],
capture_output=True, text=True, timeout=10
)
if proc.returncode == 0:
return {"task_name": task_name, "xml": proc.stdout}
return {"error": proc.stderr.strip()}
except (subprocess.TimeoutExpired, FileNotFoundError) as e:
return {"error": str(e)}
def main():
parser = argparse.ArgumentParser(description="Hunt for scheduled task persistence")
sub = parser.add_subparsers(dest="command")
sub.add_parser("enumerate", help="Enumerate and risk-score scheduled tasks")
e = sub.add_parser("events", help="Scan Security EVTX for task creation events")
e.add_argument("--evtx-file", required=True)
x = sub.add_parser("export", help="Export task XML for analysis")
x.add_argument("--task-name", required=True)
args = parser.parse_args()
if args.command == "enumerate":
result = enumerate_tasks()
elif args.command == "events":
result = scan_event_log_4698(args.evtx_file)
elif args.command == "export":
result = export_task_xml(args.task_name)
else:
parser.print_help()
return
print(json.dumps(result, indent=2, default=str))
if __name__ == "__main__":
main()
process.py3.5 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Scheduled Task Persistence Detection - Analyzes Windows task creation events for suspicious persistence indicators."""
import json, csv, argparse, datetime, re
from collections import defaultdict
from pathlib import Path
SUSPICIOUS_TASK_PATTERNS = {
"commands": [
r"powershell", r"cmd\.exe", r"wscript", r"cscript", r"mshta",
r"certutil", r"bitsadmin", r"rundll32", r"regsvr32",
],
"arguments": [
r"-enc", r"-encodedcommand", r"iex", r"downloadstring",
r"http[s]?://", r"bypass", r"hidden", r"base64",
],
"paths": [
r"\\temp\\", r"\\appdata\\", r"\\programdata\\",
r"\\public\\", r"\\downloads\\",
],
}
def parse_logs(path):
p = Path(path)
if p.suffix == ".json":
with open(p, encoding="utf-8") as f:
data = json.load(f)
return data if isinstance(data, list) else data.get("events", [])
elif p.suffix == ".csv":
with open(p, encoding="utf-8-sig") as f:
return [dict(r) for r in csv.DictReader(f)]
return []
def analyze_task(event):
eid = event.get("EventCode", event.get("EventID", event.get("event_id", "")))
if str(eid) not in ("4698", "106"):
return None
task_name = event.get("Task_Name", event.get("TaskName", ""))
task_content = event.get("Task_Content", event.get("TaskContent", event.get("command_line", "")))
host = event.get("Computer", event.get("hostname", "unknown"))
user = event.get("User", event.get("AccountName", "unknown"))
ts = event.get("_time", event.get("timestamp", event.get("UtcTime", "")))
risk = 20
indicators = []
for cat, patterns in SUSPICIOUS_TASK_PATTERNS.items():
for pattern in patterns:
if re.search(pattern, task_content, re.IGNORECASE):
risk += 15
indicators.append(f"Suspicious {cat}: {pattern}")
if not indicators:
return None
risk = min(risk, 100)
return {
"technique": "T1053.005",
"task_name": task_name,
"task_content": task_content[:500],
"hostname": host, "user": user, "timestamp": ts,
"risk_score": risk,
"risk_level": "CRITICAL" if risk >= 70 else "HIGH" if risk >= 50 else "MEDIUM" if risk >= 30 else "LOW",
"indicators": indicators,
}
def run_hunt(input_path, output_dir):
print(f"[*] Scheduled Task Hunt - {datetime.datetime.now().isoformat()}")
events = parse_logs(input_path)
findings = [f for f in (analyze_task(e) for e in events) if f]
Path(output_dir).mkdir(parents=True, exist_ok=True)
with open(Path(output_dir) / "schtask_findings.json", "w", encoding="utf-8") as f:
json.dump({"hunt_id": f"TH-SCHTASK-{datetime.date.today()}", "findings": findings}, f, indent=2)
print(f"[+] {len(findings)} findings written to {output_dir}")
def main():
p = argparse.ArgumentParser(description="Scheduled Task Persistence Detection")
sp = p.add_subparsers(dest="cmd")
h = sp.add_parser("hunt")
h.add_argument("--input", "-i", required=True)
h.add_argument("--output", "-o", default="./schtask_output")
sp.add_parser("queries")
args = p.parse_args()
if args.cmd == "hunt": run_hunt(args.input, args.output)
elif args.cmd == "queries":
print("=== Splunk ===")
print('''index=wineventlog (EventCode=4698 OR EventCode=106)
| where match(Task_Content, "(?i)(powershell|cmd|wscript|mshta|http|encoded)")
| table _time Computer User Task_Name Task_Content''')
else: p.print_help()
if __name__ == "__main__": main()
Assets 1
template.mdtext/markdown · 2.6 KBKeep exploring