Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
T1046 on the official MITRE ATT&CK siteT1057 on the official MITRE ATT&CK siteT1059 on the official MITRE ATT&CK siteT1059.001 on the official MITRE ATT&CK siteT1082 on the official MITRE ATT&CK siteT1083 on the official MITRE ATT&CK siteT1190 on the official MITRE ATT&CK siteT1505 on the official MITRE ATT&CK siteT1505.003 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 webshell activity 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 |
|---|---|
| T1505.003 | Web Shell |
| T1190 | Exploit Public-Facing Application |
| T1059.001 | PowerShell |
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: China Chopper web shell via IIS vulnerability
- Scenario 2: ASPXSpy through vulnerable upload
- Scenario 3: PHP shell hidden in image file
- Scenario 4: JSP shell via Tomcat manager console
Output Format
Hunt ID: TH-HUNTIN-[DATE]-[SEQ]
Technique: T1505.003
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.7 KB
API Reference: Hunting for Webshell Activity
Process Tree Detection
| Parent Process | Child Process | Severity |
|---|---|---|
| w3wp.exe | cmd.exe, powershell.exe | CRITICAL |
| httpd/apache2 | bash, sh, python | CRITICAL |
| tomcat/java | cmd.exe, bash | CRITICAL |
| nginx | bash, sh | CRITICAL |
Splunk SPL - Web Server Shell Spawn
index=sysmon EventCode=1
| where match(ParentImage, "(?i)(w3wp|httpd|apache2|nginx|tomcat)")
| where match(Image, "(?i)(cmd\.exe|powershell|bash|whoami|net\.exe)")
| table _time Computer ParentImage Image CommandLine UserKQL - Web Shell Process Chain
DeviceProcessEvents
| where InitiatingProcessFileName in~ ("w3wp.exe", "httpd", "apache2", "nginx")
| where FileName in~ ("cmd.exe", "powershell.exe", "bash", "whoami.exe")
| project Timestamp, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLineWeb Access Log Patterns
webshell_patterns = [
r"POST\s+.*\.(asp|aspx|php|jsp)\s+", # POST to script files
r"cmd=|exec=|command=|shell=", # Command parameters
r"c99shell|r57shell|b374k|weevely", # Known webshell names
]Sigma Rule - Webshell Detection
title: Webshell Spawning Shell Process
logsource:
category: process_creation
product: windows
detection:
parent:
ParentImage|endswith: '\w3wp.exe'
child:
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
condition: parent and child
level: critical
tags:
- attack.persistence
- attack.t1505.003References
- MITRE T1505.003: https://attack.mitre.org/techniques/T1505/003/
- SANS Webshell Detection: https://www.sans.org/white-papers/
- Sigma webshell rules: https://github.com/SigmaHQ/sigma
standards.md1.5 KB
Standards and References - Hunting For Webshell Activity
MITRE ATT&CK Mappings
| Technique | Name | Description |
|---|---|---|
| T1505.003 | Web Shell | See attack.mitre.org/techniques/T1505/003 |
| T1190 | Exploit Public-Facing Application | See attack.mitre.org/techniques/T1190 |
| T1059.001 | PowerShell | See attack.mitre.org/techniques/T1059/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 - Hunting For Webshell Activity
Phase 1: Data Collection and Querying
Splunk SPL Query
index=sysmon EventCode=1
| where match(ParentImage, "(?i)(w3wp|httpd|nginx|tomcat|java)\.exe")
| where match(Image, "(?i)(cmd|powershell|bash|whoami|net|ipconfig)\.exe")
| table _time Computer User ParentImage Image CommandLineKQL Query (Microsoft Defender for Endpoint)
DeviceProcessEvents
| where InitiatingProcessFileName in~ ("w3wp.exe","httpd.exe","nginx.exe","java.exe")
| where FileName in~ ("cmd.exe","powershell.exe","whoami.exe","net.exe")
| project Timestamp, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLinePhase 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.py6.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for hunting web shell activity on web servers via process tree and log analysis."""
import json
import argparse
import re
from datetime import datetime
WEB_SERVER_PROCESSES = [
"w3wp.exe", "httpd", "apache2", "nginx", "tomcat", "java",
"php-cgi", "php-fpm", "node", "iisexpress",
]
SHELL_SPAWNS = [
"cmd.exe", "powershell.exe", "pwsh.exe", "bash", "sh",
"wscript.exe", "cscript.exe", "certutil.exe", "whoami.exe",
"net.exe", "net1.exe", "ipconfig.exe", "systeminfo.exe",
"tasklist.exe", "nslookup.exe",
]
WEBSHELL_HTTP_PATTERNS = [
r"POST\s+.*\.(asp|aspx|php|jsp|jspx)\s+",
r"cmd=", r"exec=", r"command=", r"shell=",
r"c99shell", r"r57shell", r"b374k", r"weevely",
r"china\s*chopper", r"antsword",
]
def load_process_logs(log_path):
"""Load process creation logs (JSON lines)."""
entries = []
with open(log_path) as f:
for line in f:
try:
entries.append(json.loads(line))
except json.JSONDecodeError:
continue
return entries
def detect_webserver_child_shells(process_logs):
"""Detect shell processes spawned by web server processes."""
findings = []
for entry in process_logs:
parent = entry.get("ParentImage", entry.get("parent_process", "")).lower()
child = entry.get("Image", entry.get("process_name", "")).lower()
is_web_parent = any(ws in parent for ws in WEB_SERVER_PROCESSES)
is_shell_child = any(sh in child for sh in SHELL_SPAWNS)
if is_web_parent and is_shell_child:
cmd = entry.get("CommandLine", entry.get("command_line", ""))
findings.append({
"timestamp": entry.get("UtcTime", entry.get("timestamp", "")),
"hostname": entry.get("Computer", entry.get("hostname", "")),
"parent_process": parent,
"child_process": child,
"command_line": cmd[:500],
"user": entry.get("User", ""),
"severity": "CRITICAL",
"technique": "T1505.003",
})
return findings
def analyze_web_access_logs(access_log_path):
"""Analyze web access logs for webshell indicators."""
findings = []
with open(access_log_path) as f:
for i, line in enumerate(f, 1):
for pattern in WEBSHELL_HTTP_PATTERNS:
if re.search(pattern, line, re.IGNORECASE):
ip_match = re.match(r"^(\S+)", line)
findings.append({
"line_number": i,
"source_ip": ip_match.group(1) if ip_match else "",
"log_entry": line.strip()[:500],
"pattern_matched": pattern,
"severity": "HIGH",
})
break
return findings
def detect_file_creation_in_webroot(file_events, webroot_paths=None):
"""Detect new script files created in web server directories."""
if webroot_paths is None:
webroot_paths = [
"/var/www", "/opt/lampp/htdocs", "inetpub/wwwroot",
"/usr/share/nginx/html", "/srv/www",
]
script_extensions = [".php", ".asp", ".aspx", ".jsp", ".jspx", ".cgi", ".cfm"]
findings = []
for event in file_events:
filepath = event.get("TargetFilename", event.get("file_path", "")).lower()
in_webroot = any(wr in filepath for wr in webroot_paths)
is_script = any(filepath.endswith(ext) for ext in script_extensions)
if in_webroot and is_script:
findings.append({
"timestamp": event.get("UtcTime", event.get("timestamp", "")),
"file_path": filepath,
"process": event.get("Image", event.get("process_name", "")),
"hostname": event.get("Computer", event.get("hostname", "")),
"severity": "CRITICAL",
"reason": "script_created_in_webroot",
})
return findings
def detect_post_exploitation(process_logs):
"""Detect reconnaissance commands typically run through webshells."""
recon_patterns = [
(r"whoami", "user_discovery"),
(r"ipconfig|ifconfig", "network_config"),
(r"net\s+(user|group|localgroup)", "account_enum"),
(r"systeminfo", "system_info"),
(r"tasklist|ps\s+aux", "process_enum"),
(r"netstat\s+-an", "connection_enum"),
(r"dir\s+/s|find\s+/|ls\s+-la", "file_enum"),
]
findings = []
for entry in process_logs:
parent = entry.get("ParentImage", entry.get("parent_process", "")).lower()
if not any(ws in parent for ws in WEB_SERVER_PROCESSES):
continue
cmd = entry.get("CommandLine", entry.get("command_line", ""))
for pattern, category in recon_patterns:
if re.search(pattern, cmd, re.IGNORECASE):
findings.append({
"timestamp": entry.get("UtcTime", entry.get("timestamp", "")),
"command": cmd[:300],
"category": category,
"parent": parent,
"severity": "HIGH",
})
break
return findings
def main():
parser = argparse.ArgumentParser(description="Webshell Activity Hunter")
parser.add_argument("--process-log", help="JSON lines process creation log")
parser.add_argument("--access-log", help="Web server access log")
parser.add_argument("--file-events", help="JSON lines file creation events")
parser.add_argument("--output", default="webshell_hunt_report.json")
args = parser.parse_args()
report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}
if args.process_log:
logs = load_process_logs(args.process_log)
shells = detect_webserver_child_shells(logs)
report["findings"]["shell_spawns"] = shells
print(f"[+] Web server shell spawns: {len(shells)}")
recon = detect_post_exploitation(logs)
report["findings"]["post_exploitation"] = recon
print(f"[+] Post-exploitation commands: {len(recon)}")
if args.access_log:
hits = analyze_web_access_logs(args.access_log)
report["findings"]["access_log_hits"] = hits
print(f"[+] Access log webshell indicators: {len(hits)}")
if args.file_events:
events = load_process_logs(args.file_events)
files = detect_file_creation_in_webroot(events)
report["findings"]["webroot_files"] = files
print(f"[+] Scripts created in webroot: {len(files)}")
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()
process.py4.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Web Shell Detection - Analyzes process and file events for web shell indicators on web servers."""
import json, csv, argparse, datetime, re
from collections import defaultdict
from pathlib import Path
WEB_SERVER_PROCESSES = {"w3wp.exe", "httpd.exe", "nginx.exe", "apache.exe", "tomcat.exe", "java.exe", "php-cgi.exe", "node.exe"}
SUSPICIOUS_CHILDREN = {"cmd.exe", "powershell.exe", "bash", "sh", "whoami.exe", "net.exe", "net1.exe", "ipconfig.exe", "systeminfo.exe", "tasklist.exe", "ping.exe", "nslookup.exe", "certutil.exe"}
WEBSHELL_EXTENSIONS = {".aspx", ".asp", ".php", ".jsp", ".jspx", ".cfm", ".ashx", ".asmx"}
WEB_DIRECTORIES = [r"\\inetpub\\", r"\\wwwroot\\", r"\\htdocs\\", r"\\webapps\\", r"\\www\\", r"\\html\\"]
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 detect_webshell_process(event):
eid = str(event.get("EventCode", event.get("EventID", "")))
if eid != "1": return None
parent = (event.get("ParentImage", event.get("InitiatingProcessFileName", ""))).lower()
image = (event.get("Image", event.get("FileName", ""))).lower()
parent_name = parent.split("\\")[-1].split("/")[-1]
image_name = image.split("\\")[-1].split("/")[-1]
if parent_name not in WEB_SERVER_PROCESSES: return None
if image_name not in SUSPICIOUS_CHILDREN: return None
return {
"detection_type": "WEBSHELL_PROCESS_SPAWN",
"technique": "T1505.003",
"web_server": parent_name, "child_process": image_name,
"command_line": event.get("CommandLine", event.get("ProcessCommandLine", "")),
"hostname": event.get("Computer", event.get("DeviceName", "unknown")),
"user": event.get("User", event.get("AccountName", "unknown")),
"timestamp": event.get("UtcTime", event.get("Timestamp", "")),
"risk_score": 80, "risk_level": "CRITICAL",
"indicators": [f"Web server {parent_name} spawned {image_name}"],
}
def detect_webshell_file(event):
eid = str(event.get("EventCode", event.get("EventID", "")))
if eid != "11": return None
target = event.get("TargetFilename", event.get("FolderPath", "")).lower()
if not any(re.search(p, target, re.IGNORECASE) for p in WEB_DIRECTORIES): return None
ext = "." + target.split(".")[-1] if "." in target else ""
if ext not in WEBSHELL_EXTENSIONS: return None
return {
"detection_type": "WEBSHELL_FILE_CREATION",
"technique": "T1505.003",
"file_path": target, "extension": ext,
"creating_process": event.get("Image", event.get("InitiatingProcessFileName", "")),
"hostname": event.get("Computer", event.get("DeviceName", "unknown")),
"timestamp": event.get("UtcTime", event.get("Timestamp", "")),
"risk_score": 70, "risk_level": "HIGH",
"indicators": [f"Web shell file created: {ext} in web directory"],
}
def run_hunt(input_path, output_dir):
print(f"[*] Web Shell Hunt - {datetime.datetime.now().isoformat()}")
events = parse_logs(input_path)
findings = []
for e in events:
r = detect_webshell_process(e)
if r: findings.append(r)
r = detect_webshell_file(e)
if r: findings.append(r)
Path(output_dir).mkdir(parents=True, exist_ok=True)
with open(Path(output_dir) / "webshell_findings.json", "w", encoding="utf-8") as f:
json.dump({"hunt_id": f"TH-WEBSHELL-{datetime.date.today()}", "findings": findings}, f, indent=2)
print(f"[+] {len(findings)} findings written to {output_dir}")
def main():
p = argparse.ArgumentParser(description="Web Shell 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="./webshell_output")
sp.add_parser("queries")
args = p.parse_args()
if args.cmd == "hunt": run_hunt(args.input, args.output)
elif args.cmd == "queries":
print('''index=sysmon EventCode=1
| where match(ParentImage, "(?i)(w3wp|httpd|nginx|tomcat|java)\\.exe")
| where match(Image, "(?i)(cmd|powershell|whoami|net|ipconfig)\\.exe")
| table _time Computer ParentImage Image CommandLine''')
else: p.print_help()
if __name__ == "__main__": main()
Assets 1
template.mdtext/markdown · 2.6 KBKeep exploring