Claude 24f816b6a3
Consolidate 22 sibling repos into layered organism structure
Place useful parts of the surrounding repos into sica-fondt by layer, per the
body model (Ada = membrane; brain/endocrine/capabilities/knowledge non-Ada):

- brain/        LLM reasoning + providers (dapr, hermes, MoMoA)
- capabilities/ REPRAG sidecars: hermes tools/skills, dapr tools, parallel
                dispatch, A51 channels, and the OSINT cluster
- knowledge/    LORAG corpus: 754 cyber-skills, agency personas, secure-coding,
                MITRE ATT&CK data
- reference/    defensive threat-reference (C3, shhbruh doc) + AdaYaml parser

License handling: AGPL sources (worldosint, advanced_evolution, mercury,
Reticulum) and GPL DeTTECT are SPEC-only clean-room/port descriptions — no
copyleft code copied. MIT/Apache/data parts copied as working trees.

Safety: shhbruh escape/persistence material and C3 covert-C2 kept as reference
only, not wired into the running organism. See CONSOLIDATION.md.

https://claude.ai/code/session_01UehUqEXXJJCsHoA4voCU5c
2026-06-10 06:53:01 +00:00

198 lines
6.7 KiB
Python

#!/usr/bin/env python3
"""Agent for detecting T1548 Abuse Elevation Control Mechanism (UAC bypass, sudo abuse)."""
import argparse
import json
import os
import re
import subprocess
import sys
from datetime import datetime, timezone
UAC_BYPASS_BINARIES = [
"fodhelper.exe", "computerdefaults.exe", "eventvwr.exe",
"sdclt.exe", "slui.exe", "cmstp.exe", "mmc.exe",
"wsreset.exe", "changepk.exe", "dism.exe",
]
UAC_BYPASS_REGISTRY_KEYS = [
r"HKCU\Software\Classes\ms-settings\Shell\Open\command",
r"HKCU\Software\Classes\mscfile\Shell\Open\command",
r"HKCU\Software\Classes\exefile\Shell\Open\command",
r"HKCU\Software\Microsoft\Windows\CurrentVersion\App Paths",
]
SUDO_ABUSE_PATTERNS = [
r"sudo\s+-u\s+\#-1",
r"sudo\s+.*NOPASSWD",
r"sudo\s+.*env_reset.*env_keep",
r"sudo\s+\S+\s+/bin/bash",
r"sudo\s+find\s+.*-exec",
r"sudo\s+vim\s+-c\s+.*!",
r"sudo\s+python\s+-c",
]
def check_uac_bypass_registry():
"""Check for UAC bypass registry modifications."""
findings = []
if sys.platform != "win32":
return findings
for key in UAC_BYPASS_REGISTRY_KEYS:
try:
result = subprocess.check_output(
["reg", "query", key], text=True, errors="replace", timeout=5
)
if result.strip() and "ERROR" not in result:
findings.append({
"type": "uac_registry",
"key": key,
"value": result.strip()[:200],
"severity": "HIGH",
})
except subprocess.SubprocessError:
pass
return findings
def check_uac_bypass_processes():
"""Check Sysmon logs for auto-elevate binary abuse."""
findings = []
if sys.platform != "win32":
return findings
ps_cmd = (
"Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-Sysmon/Operational';"
"Id=1} -MaxEvents 500 "
"| Where-Object {$_.Properties[4].Value -match '"
+ "|".join(UAC_BYPASS_BINARIES)
+ "'} | Select-Object TimeCreated,"
"@{N='Image';E={$_.Properties[4].Value}},"
"@{N='CommandLine';E={$_.Properties[10].Value}},"
"@{N='ParentImage';E={$_.Properties[20].Value}} "
"| ConvertTo-Json"
)
try:
result = subprocess.check_output(
["powershell", "-NoProfile", "-Command", ps_cmd],
text=True, errors="replace", timeout=30
)
data = json.loads(result) if result.strip() else []
if not isinstance(data, list):
data = [data]
for evt in data:
parent = (evt.get("ParentImage", "") or "").lower()
if "explorer.exe" not in parent and "svchost.exe" not in parent:
findings.append({
"type": "uac_auto_elevate",
"time": evt.get("TimeCreated", ""),
"image": evt.get("Image", ""),
"parent": evt.get("ParentImage", ""),
"commandline": evt.get("CommandLine", "")[:200],
})
except (subprocess.SubprocessError, json.JSONDecodeError):
pass
return findings
def check_linux_sudo_abuse():
"""Check auth logs for sudo abuse patterns."""
findings = []
if sys.platform == "win32":
return findings
log_paths = ["/var/log/auth.log", "/var/log/secure"]
for log_path in log_paths:
if not os.path.isfile(log_path):
continue
try:
with open(log_path, "r", errors="replace") as f:
for line in f:
if "sudo" not in line.lower():
continue
for pat in SUDO_ABUSE_PATTERNS:
if re.search(pat, line, re.IGNORECASE):
findings.append({
"type": "sudo_abuse",
"log": log_path,
"line": line.strip()[:200],
"pattern": pat,
})
except PermissionError:
pass
try:
result = subprocess.check_output(
["sudo", "-l", "-n"], text=True, errors="replace", timeout=5
)
if "NOPASSWD" in result:
for line in result.splitlines():
if "NOPASSWD" in line:
findings.append({
"type": "nopasswd_sudo",
"rule": line.strip(),
"severity": "MEDIUM",
})
except subprocess.SubprocessError:
pass
return findings
def check_setuid_binaries():
"""Find SUID/SGID binaries that could be abused for elevation."""
findings = []
if sys.platform == "win32":
return findings
try:
result = subprocess.check_output(
["find", "/", "-perm", "-4000", "-type", "f"],
text=True, errors="replace", timeout=30, stderr=subprocess.DEVNULL
)
known_suid = {"/usr/bin/sudo", "/usr/bin/passwd", "/usr/bin/su",
"/usr/bin/mount", "/usr/bin/umount", "/usr/bin/ping"}
for line in result.strip().splitlines():
path = line.strip()
if path and path not in known_suid:
findings.append({"type": "unusual_suid", "path": path})
except subprocess.SubprocessError:
pass
return findings
def main():
parser = argparse.ArgumentParser(
description="Detect T1548 Abuse Elevation Control Mechanism"
)
parser.add_argument("--output", "-o", help="Output JSON report")
parser.add_argument("--verbose", "-v", action="store_true")
args = parser.parse_args()
print("[*] T1548 Elevation Abuse Detection Agent")
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": {}}
if sys.platform == "win32":
reg = check_uac_bypass_registry()
procs = check_uac_bypass_processes()
report["findings"]["uac_registry"] = reg
report["findings"]["uac_processes"] = procs
print(f"[*] UAC registry: {len(reg)}, UAC process: {len(procs)}")
else:
sudo = check_linux_sudo_abuse()
suid = check_setuid_binaries()
report["findings"]["sudo_abuse"] = sudo
report["findings"]["suid_binaries"] = suid
print(f"[*] Sudo abuse: {len(sudo)}, SUID binaries: {len(suid)}")
total = sum(len(v) if isinstance(v, list) else 0 for v in report["findings"].values())
report["risk_level"] = "CRITICAL" if total >= 5 else "HIGH" if total >= 2 else "MEDIUM" if total > 0 else "LOW"
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()