Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
T1027.010 on the official MITRE ATT&CK siteT1059 on the official MITRE ATT&CK siteT1059.001 on the official MITRE ATT&CK siteT1059.003 on the official MITRE ATT&CK siteT1105 on the official MITRE ATT&CK siteT1562 on the official MITRE ATT&CK siteT1562.001 on the official MITRE ATT&CK siteT1620 on the official MITRE ATT&CK site
NIST CSF 2.0
MITRE D3FEND
When to Use
- When proactively hunting for indicators of detecting suspicious powershell execution 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 |
|---|---|
| T1059.001 | PowerShell |
| T1059.003 | Windows Command Shell |
| T1562.001 | Disable or Modify Tools |
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: Base64 encoded PowerShell command launched by macro document
- Scenario 2: IEX download cradle fetching payload from C2 server
- Scenario 3: AMSI bypass via reflection patching before payload execution
- Scenario 4: PowerShell Empire agent communicating with C2
Output Format
Hunt ID: TH-DETECT-[DATE]-[SEQ]
Technique: T1059.001
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.md2.5 KB
API Reference: Suspicious PowerShell Execution Detection
Windows PowerShell Event Logs
Event IDs
| Event ID | Log | Description |
|---|---|---|
| 4104 | PowerShell/Operational | Script block logging |
| 4103 | PowerShell/Operational | Module logging |
| 800 | PowerShell | Pipeline execution details |
| 400 | PowerShell | Engine lifecycle (start) |
| 403 | PowerShell | Engine lifecycle (stop) |
Script Block Logging Query
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-PowerShell/Operational'
Id = 4104
} -MaxEvents 100Event 4104 Properties
| Index | Field | Description |
|---|---|---|
| 0 | MessageNumber | Block sequence number |
| 1 | MessageTotal | Total blocks in script |
| 2 | ScriptBlockText | Actual script content |
| 3 | ScriptBlockId | Unique script ID |
| 4 | Path | Script file path |
Suspicious PowerShell Patterns
Execution Policy Bypass
powershell -ExecutionPolicy Bypass -File script.ps1
powershell -ep bypass -nop -w hidden -enc <base64>Common Obfuscation Techniques
| Technique | Example |
|---|---|
| Concatenation | "Inv"+"oke-Ex"+"pression" |
| Variable substitution | ${Invoke-Expression} |
| Encoded commands | -enc SQBuAHYAbwBrAGUALQA... |
| Char array | [char[]]@(73,69,88) -join '' |
Sigma Detection Rules
Suspicious PowerShell Command Line
title: Suspicious PowerShell Invocation
logsource:
product: windows
category: process_creation
detection:
selection:
CommandLine|contains:
- '-enc'
- '-EncodedCommand'
- 'FromBase64String'
- 'DownloadString'
- 'Invoke-Expression'
condition: selection
level: highAMSI (Antimalware Scan Interface)
AMSI Scan Functions
HRESULT AmsiScanBuffer(
HAMSICONTEXT amsiContext,
PVOID buffer,
ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT *result
);AMSI Results
| Value | Meaning |
|---|---|
| 0 | Clean |
| 1 | Not Detected |
| 16384 | Blocked by admin |
| 32768 | Detected (malware) |
Microsoft Defender ATP API
Advanced Hunting Query
POST https://api.security.microsoft.com/api/advancedqueries/run
Authorization: Bearer {token}
{
"Query": "DeviceProcessEvents | where FileName == 'powershell.exe' | where ProcessCommandLine has_any('encodedcommand','downloadstring','invoke-expression') | project Timestamp, DeviceName, ProcessCommandLine | take 100"
}standards.md1.6 KB
Standards and References - Detecting Suspicious Powershell Execution
MITRE ATT&CK Mappings
| Technique | Name | Description |
|---|---|---|
| T1059.001 | PowerShell | See attack.mitre.org/techniques/T1059/001 |
| T1059.003 | Windows Command Shell | See attack.mitre.org/techniques/T1059/003 |
| T1562.001 | Disable or Modify Tools | See attack.mitre.org/techniques/T1562/001 |
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.9 KB
Detailed Hunting Workflow - Detecting Suspicious Powershell Execution
Phase 1: Data Collection and Querying
Splunk SPL Query
index=sysmon EventCode=1 Image="*\\powershell.exe"
| where match(CommandLine, "(?i)(-enc|-encodedcommand|-w hidden|-nop|iex|invoke-expression|downloadstring|webclient|bypass)")
| table _time Computer User CommandLine ParentImageKQL Query (Microsoft Defender for Endpoint)
DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has_any ("-enc","-encodedcommand","-w hidden","iex","downloadstring","bypass")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileNamePhase 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.py5.9 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for detecting suspicious PowerShell execution patterns."""
import argparse
import json
import os
import re
import subprocess
import sys
from datetime import datetime, timezone
SUSPICIOUS_CMDLETS = [
"Invoke-Expression", "IEX", "Invoke-WebRequest", "Invoke-RestMethod",
"Start-Process", "New-Object Net.WebClient", "DownloadString",
"DownloadFile", "System.Reflection.Assembly", "FromBase64String",
"Invoke-Mimikatz", "Invoke-Shellcode", "Invoke-DllInjection",
"Invoke-ReflectivePEInjection", "Get-Keystrokes", "Get-GPPPassword",
"Invoke-CredentialInjection", "Invoke-TokenManipulation",
"Add-Exfiltration", "Get-TimedScreenshot",
]
OBFUSCATION_PATTERNS = [
(r'\-[eE][nN][cC]\s', "Encoded command (-enc)"),
(r'[Ff][Rr][Oo][Mm][Bb][Aa][Ss][Ee]64', "Base64 decoding"),
(r'\$\{[^}]+\}', "Variable obfuscation ${...}"),
(r"'[^']*'\s*\+\s*'[^']*'", "String concatenation obfuscation"),
(r'\-[Ww]indow[Ss]tyle\s+[Hh]idden', "Hidden window execution"),
(r'\-[Nn]o[Pp]rofile', "NoProfile flag"),
(r'\-[Ee]xecution[Pp]olicy\s+[Bb]ypass', "Execution policy bypass"),
(r'[Ss]et-[Mm]pPreference.*-[Dd]isable', "Defender bypass attempt"),
(r'[Aa][Mm][Ss][Ii]', "AMSI reference"),
]
def parse_script_block_logs():
"""Parse PowerShell script block logging events (Event ID 4104)."""
events = []
if sys.platform != "win32":
return events
ps_cmd = (
"Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';"
"Id=4104} -MaxEvents 200 | Select-Object TimeCreated,"
"@{N='ScriptBlock';E={$_.Properties[2].Value}},"
"@{N='Path';E={$_.Properties[4].Value}} | ConvertTo-Json -Depth 3"
)
try:
result = subprocess.check_output(
["powershell", "-NoProfile", "-Command", ps_cmd],
text=True, errors="replace", timeout=30
)
data = json.loads(result) if result.strip() else []
return data if isinstance(data, list) else [data]
except (subprocess.SubprocessError, json.JSONDecodeError):
return []
def analyze_script_content(script_text):
"""Analyze a PowerShell script for suspicious patterns."""
findings = []
if not script_text:
return findings
for cmdlet in SUSPICIOUS_CMDLETS:
if cmdlet.lower() in script_text.lower():
findings.append({"type": "suspicious_cmdlet", "cmdlet": cmdlet})
for pattern, desc in OBFUSCATION_PATTERNS:
if re.search(pattern, script_text):
findings.append({"type": "obfuscation", "pattern": desc})
b64_match = re.findall(r'[A-Za-z0-9+/]{40,}={0,2}', script_text)
for b64 in b64_match[:3]:
try:
import base64
decoded = base64.b64decode(b64).decode("utf-8", errors="replace")
if any(c.lower() in decoded.lower() for c in SUSPICIOUS_CMDLETS[:10]):
findings.append({"type": "encoded_payload", "preview": decoded[:100]})
except Exception:
pass
return findings
def analyze_log_file(log_path):
"""Analyze a text file containing PowerShell commands."""
findings = []
try:
with open(log_path, "r", errors="replace") as f:
content = f.read()
results = analyze_script_content(content)
if results:
findings.append({
"file": log_path,
"indicators": results,
"indicator_count": len(results),
})
except FileNotFoundError:
print(f"[!] File not found: {log_path}")
return findings
def main():
parser = argparse.ArgumentParser(
description="Detect suspicious PowerShell execution patterns"
)
parser.add_argument("--event-logs", action="store_true",
help="Parse Windows PowerShell event logs")
parser.add_argument("--script", help="Analyze a PowerShell script file")
parser.add_argument("--log-dir", help="Directory of PS log files to scan")
parser.add_argument("--output", "-o", help="Output JSON report")
parser.add_argument("--verbose", "-v", action="store_true")
args = parser.parse_args()
print("[*] Suspicious PowerShell Execution Detection Agent")
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": []}
if args.event_logs:
events = parse_script_block_logs()
for evt in events:
script = evt.get("ScriptBlock", "")
indicators = analyze_script_content(script)
if indicators:
report["findings"].append({
"source": "event_log",
"time": evt.get("TimeCreated", ""),
"path": evt.get("Path", ""),
"indicators": indicators,
"preview": script[:200] if args.verbose else "",
})
print(f"[*] Analyzed {len(events)} script block events")
if args.script:
findings = analyze_log_file(args.script)
report["findings"].extend(findings)
if args.log_dir and os.path.isdir(args.log_dir):
for root, _, files in os.walk(args.log_dir):
for f in files:
if f.lower().endswith((".ps1", ".psm1", ".psd1", ".log", ".txt")):
findings = analyze_log_file(os.path.join(root, f))
report["findings"].extend(findings)
report["total_suspicious"] = len(report["findings"])
report["risk_level"] = (
"CRITICAL" if len(report["findings"]) >= 10
else "HIGH" if len(report["findings"]) >= 5
else "MEDIUM" if report["findings"]
else "LOW"
)
print(f"[*] Suspicious findings: {len(report['findings'])}")
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report saved to {args.output}")
else:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()
process.py3.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Suspicious PowerShell Detection - Analyzes logs for T1059.001 indicators."""
import json, csv, argparse, datetime, re
from collections import defaultdict
from pathlib import Path
DETECTION_PATTERNS = [
r'-enc',
r'-encodedcommand',
r'-w hidden',
r'-nop',
r'iex',
r'invoke-expression',
r'downloadstring',
r'webclient',
r'bypass',
r'Net\\.WebClient',
r'bitstransfer',
r'Start-BitsTransfer',
]
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_event(event):
cmd = event.get("CommandLine", event.get("command_line", event.get("ProcessCommandLine", "")))
content = event.get("Task_Content", event.get("Parameters", event.get("RawEventData", "")))
search_text = f"{cmd} {content}"
risk = 0
indicators = []
for pattern in DETECTION_PATTERNS:
if re.search(pattern, search_text, re.IGNORECASE):
risk += 25
indicators.append(f"Pattern match: {pattern}")
if not indicators:
return None
risk = min(risk, 100)
return {
"technique": "T1059.001",
"command_line": cmd[:500] if cmd else content[:500],
"hostname": event.get("Computer", event.get("DeviceName", event.get("hostname", "unknown"))),
"user": event.get("User", event.get("AccountName", event.get("UserId", "unknown"))),
"timestamp": event.get("_time", event.get("timestamp", event.get("UtcTime", event.get("Timestamp", "")))),
"risk_score": risk,
"risk_level": "CRITICAL" if risk >= 75 else "HIGH" if risk >= 50 else "MEDIUM" if risk >= 25 else "LOW",
"indicators": indicators,
}
def run_hunt(input_path, output_dir):
print(f"[*] Suspicious PowerShell Hunt - {datetime.datetime.now().isoformat()}")
events = parse_logs(input_path)
findings = [f for f in (analyze_event(e) for e in events) if f]
Path(output_dir).mkdir(parents=True, exist_ok=True)
slug = "detecting_suspicious"
with open(Path(output_dir) / f"{slug}_findings.json", "w", encoding="utf-8") as f:
json.dump({"hunt_id": f"TH-{datetime.date.today()}", "total_events": len(events), "findings": findings}, f, indent=2)
with open(Path(output_dir) / "hunt_report.md", "w", encoding="utf-8") as f:
f.write(f"# Suspicious PowerShell Hunt Report\n\n")
f.write(f"**Date**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"**Findings**: {len(findings)}\n\n")
for finding in sorted(findings, key=lambda x: x["risk_score"], reverse=True)[:20]:
f.write(f"### [{finding['risk_level']}] {finding['technique']}\n")
f.write(f"- **Host**: {finding['hostname']}\n")
f.write(f"- **Indicators**: {', '.join(finding['indicators'])}\n\n")
print(f"[+] {len(findings)} findings written to {output_dir}")
def main():
p = argparse.ArgumentParser(description="Suspicious PowerShell 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="./detecting_suspi_output")
sp.add_parser("queries")
args = p.parse_args()
if args.cmd == "hunt": run_hunt(args.input, args.output)
elif args.cmd == "queries":
print("=== Detection Queries ===")
print("See references/workflows.md for platform-specific queries")
else: p.print_help()
if __name__ == "__main__": main()
Assets 1
template.mdtext/markdown · 2.6 KBKeep exploring