Expand 39 api-reference stubs with real tool docs, expand 15 agent.py boilerplate stubs

This commit is contained in:
mukul975
2026-03-19 13:29:33 +01:00
parent d63b578a2f
commit d005ae764b
191 changed files with 4300 additions and 587 deletions
@@ -1,61 +1,324 @@
#!/usr/bin/env python3
"""PCI DSS compliance control audit."""
import argparse, json
"""PCI DSS compliance control audit agent.
Audits systems and configurations against PCI DSS v4.0 requirements
including network segmentation, encryption, access controls, logging,
vulnerability management, and secure configuration checks.
"""
import argparse
import json
import os
import re
import socket
import ssl
import subprocess
import sys
from datetime import datetime, timezone
try:
import requests
except ImportError:
requests = None
def audit_config(target, token):
def check_tls_configuration(host, port=443):
"""PCI DSS Req 4.2.1 - Strong cryptography for transmission."""
findings = []
if not requests: return [{"error": "requests required"}]
headers = {"Authorization": f"Bearer {token}"}
print(f"[*] Req 4.2.1: Checking TLS on {host}:{port}")
try:
resp = requests.get(f"{target}/api/v1/status", headers=headers, timeout=10)
if resp.status_code == 200:
data = resp.json()
if not data.get("enabled", True):
findings.append({"check": "Service Status", "status": "DISABLED", "severity": "CRITICAL"})
elif resp.status_code == 401:
findings.append({"check": "Authentication", "status": "UNAUTHORIZED", "severity": "HIGH"})
except requests.RequestException as e:
findings.append({"error": str(e)})
context = ssl.create_default_context()
with socket.create_connection((host, port), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=host) as ssock:
protocol = ssock.version()
cipher = ssock.cipher()
if protocol in ("TLSv1.0", "TLSv1.1", "SSLv3", "SSLv2"):
findings.append({
"requirement": "4.2.1", "check": "TLS Protocol Version",
"status": "FAIL", "severity": "CRITICAL",
"detail": f"Deprecated protocol: {protocol}",
})
else:
findings.append({
"requirement": "4.2.1", "check": "TLS Protocol Version",
"status": "PASS", "severity": "INFO",
"detail": f"Protocol: {protocol}",
})
if cipher:
weak_ciphers = ["RC4", "DES", "3DES", "NULL", "EXPORT", "MD5"]
if any(w in cipher[0] for w in weak_ciphers):
findings.append({
"requirement": "4.2.1", "check": "Cipher Strength",
"status": "FAIL", "severity": "HIGH",
"detail": f"Weak cipher: {cipher[0]}",
})
else:
findings.append({
"requirement": "4.2.1", "check": "Cipher Strength",
"status": "PASS", "severity": "INFO",
"detail": f"Cipher: {cipher[0]} ({cipher[2]} bits)",
})
except Exception as e:
findings.append({
"requirement": "4.2.1", "check": "TLS Connection",
"status": "ERROR", "severity": "HIGH", "detail": str(e)[:100],
})
return findings
def check_compliance(target, token):
def check_password_policy():
"""PCI DSS Req 8.3.6 - Password complexity requirements."""
findings = []
if not requests: return []
headers = {"Authorization": f"Bearer {token}"}
try:
resp = requests.get(f"{target}/api/v1/compliance", headers=headers, timeout=10)
if resp.status_code == 200:
for item in resp.json().get("checks", []):
if item.get("status") != "PASS":
findings.append({"check": item.get("name"), "status": item.get("status"),
"severity": item.get("severity", "MEDIUM")})
except requests.RequestException:
pass
print("[*] Req 8.3.6: Checking password policy")
if sys.platform != "win32":
# Check PAM password quality
pam_files = ["/etc/pam.d/common-password", "/etc/pam.d/system-auth",
"/etc/security/pwquality.conf"]
for pam_file in pam_files:
if os.path.isfile(pam_file):
with open(pam_file, "r") as f:
content = f.read()
if "minlen" in content:
match = re.search(r'minlen\s*=\s*(\d+)', content)
if match and int(match.group(1)) >= 12:
findings.append({
"requirement": "8.3.6", "check": "Min password length",
"status": "PASS", "severity": "INFO",
"detail": f"minlen={match.group(1)} in {pam_file}",
})
else:
findings.append({
"requirement": "8.3.6", "check": "Min password length",
"status": "FAIL", "severity": "HIGH",
"detail": f"Password minlen < 12 in {pam_file}",
})
break
else:
findings.append({
"requirement": "8.3.6", "check": "Password policy config",
"status": "WARN", "severity": "MEDIUM",
"detail": "Could not find PAM password config",
})
return findings
def check_audit_logging():
"""PCI DSS Req 10.2 - Audit logging configuration."""
findings = []
print("[*] Req 10.2: Checking audit logging")
if sys.platform != "win32":
# Check auditd
result = subprocess.run(
["systemctl", "is-active", "auditd"],
capture_output=True, text=True, timeout=10,
)
if result.stdout.strip() == "active":
findings.append({
"requirement": "10.2", "check": "Audit daemon running",
"status": "PASS", "severity": "INFO",
})
else:
findings.append({
"requirement": "10.2", "check": "Audit daemon running",
"status": "FAIL", "severity": "CRITICAL",
"detail": "auditd is not running",
})
# Check syslog
for syslog in ["rsyslog", "syslog-ng"]:
result = subprocess.run(
["systemctl", "is-active", syslog],
capture_output=True, text=True, timeout=10,
)
if result.stdout.strip() == "active":
findings.append({
"requirement": "10.2", "check": f"{syslog} running",
"status": "PASS", "severity": "INFO",
})
break
return findings
def check_file_integrity():
"""PCI DSS Req 11.5.2 - File integrity monitoring."""
findings = []
print("[*] Req 11.5.2: Checking file integrity monitoring")
fim_tools = {
"aide": ["/usr/bin/aide", "/usr/sbin/aide"],
"ossec": ["/var/ossec/bin/ossec-syscheckd"],
"tripwire": ["/usr/sbin/tripwire"],
"samhain": ["/usr/local/sbin/samhain"],
}
found_fim = False
for tool_name, paths in fim_tools.items():
for path in paths:
if os.path.isfile(path):
findings.append({
"requirement": "11.5.2", "check": f"FIM tool: {tool_name}",
"status": "PASS", "severity": "INFO",
"detail": f"Found at {path}",
})
found_fim = True
break
if not found_fim:
findings.append({
"requirement": "11.5.2", "check": "File integrity monitoring",
"status": "FAIL", "severity": "HIGH",
"detail": "No FIM tool detected (AIDE, OSSEC, Tripwire, Samhain)",
})
return findings
def check_default_credentials():
"""PCI DSS Req 2.2.2 - Change vendor defaults."""
findings = []
print("[*] Req 2.2.2: Checking for default credentials")
# Check for common default accounts
if os.path.isfile("/etc/passwd"):
with open("/etc/passwd", "r") as f:
for line in f:
parts = line.strip().split(":")
if len(parts) >= 7:
username = parts[0]
shell = parts[6]
if username in ("guest", "test", "demo", "admin") and shell not in ("/usr/sbin/nologin", "/bin/false"):
findings.append({
"requirement": "2.2.2", "check": f"Default account: {username}",
"status": "FAIL", "severity": "HIGH",
"detail": f"Account '{username}' has login shell: {shell}",
})
return findings
def check_network_segmentation(target_ip, ports=None):
"""PCI DSS Req 1.3 - Network segmentation check."""
findings = []
if not ports:
ports = [22, 80, 443, 3306, 5432, 1433, 6379, 9200, 27017]
print(f"[*] Req 1.3: Checking network segmentation to {target_ip}")
for port in ports:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(3)
result = sock.connect_ex((target_ip, port))
sock.close()
if result == 0:
findings.append({
"requirement": "1.3", "check": f"Port {port} reachable",
"status": "WARN", "severity": "MEDIUM",
"detail": f"{target_ip}:{port} is open from this network segment",
})
except Exception:
pass
if not findings:
findings.append({
"requirement": "1.3", "check": "Network segmentation",
"status": "PASS", "severity": "INFO",
"detail": f"No tested ports reachable on {target_ip}",
})
return findings
def format_summary(all_findings):
"""Print PCI DSS audit summary."""
print(f"\n{'='*60}")
print(f" PCI DSS v4.0 Compliance Audit Report")
print(f"{'='*60}")
pass_count = sum(1 for f in all_findings if f["status"] == "PASS")
fail_count = sum(1 for f in all_findings if f["status"] == "FAIL")
warn_count = sum(1 for f in all_findings if f["status"] == "WARN")
print(f" Total Checks : {len(all_findings)}")
print(f" Passed : {pass_count}")
print(f" Failed : {fail_count}")
print(f" Warnings : {warn_count}")
by_req = {}
for f in all_findings:
req = f.get("requirement", "unknown")
by_req.setdefault(req, []).append(f)
print(f"\n Results by Requirement:")
for req in sorted(by_req.keys()):
items = by_req[req]
failed = sum(1 for i in items if i["status"] == "FAIL")
passed = sum(1 for i in items if i["status"] == "PASS")
status = "FAIL" if failed > 0 else "PASS"
print(f" Req {req:8s}: [{status:4s}] {passed} passed, {failed} failed")
if fail_count > 0:
print(f"\n Failed Checks:")
for f in all_findings:
if f["status"] == "FAIL":
print(f" [{f['severity']:8s}] Req {f['requirement']}: {f['check']} - {f.get('detail', '')}")
severity_counts = {}
for f in all_findings:
if f["status"] == "FAIL":
sev = f.get("severity", "MEDIUM")
severity_counts[sev] = severity_counts.get(sev, 0) + 1
return severity_counts
def main():
p = argparse.ArgumentParser(description="PCI DSS compliance control audit")
p.add_argument("--target", required=True, help="Target URL")
p.add_argument("--token", required=True, help="API token")
p.add_argument("--output", "-o", help="Output JSON report")
p.add_argument("--verbose", "-v", action="store_true")
a = p.parse_args()
print("[*] PCI DSS compliance control audit")
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": []}
report["findings"].extend(audit_config(a.target, a.token))
report["findings"].extend(check_compliance(a.target, a.token))
high = sum(1 for f in report["findings"] if f.get("severity") in ("HIGH", "CRITICAL"))
report["risk_level"] = "HIGH" if high else "MEDIUM" if report["findings"] else "LOW"
print(f"[*] {len(report['findings'])} findings, risk: {report['risk_level']}")
if a.output:
with open(a.output, "w") as f: json.dump(report, f, indent=2)
else:
parser = argparse.ArgumentParser(description="PCI DSS compliance control audit agent")
parser.add_argument("--tls-host", help="Host to check TLS configuration")
parser.add_argument("--tls-port", type=int, default=443)
parser.add_argument("--segment-target", help="IP to check network segmentation")
parser.add_argument("--skip-password", action="store_true")
parser.add_argument("--skip-logging", action="store_true")
parser.add_argument("--skip-fim", action="store_true")
parser.add_argument("--output", "-o", help="Output JSON report")
parser.add_argument("--verbose", "-v", action="store_true")
args = parser.parse_args()
all_findings = []
if args.tls_host:
all_findings.extend(check_tls_configuration(args.tls_host, args.tls_port))
if not args.skip_password:
all_findings.extend(check_password_policy())
if not args.skip_logging:
all_findings.extend(check_audit_logging())
if not args.skip_fim:
all_findings.extend(check_file_integrity())
all_findings.extend(check_default_credentials())
if args.segment_target:
all_findings.extend(check_network_segmentation(args.segment_target))
if not all_findings:
print("[!] No checks performed. Use --tls-host or other options.", file=sys.stderr)
sys.exit(1)
severity_counts = format_summary(all_findings)
report = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"tool": "PCI DSS Audit",
"standard": "PCI DSS v4.0",
"findings": all_findings,
"severity_counts": severity_counts,
"risk_level": (
"CRITICAL" if severity_counts.get("CRITICAL", 0) > 0
else "HIGH" if severity_counts.get("HIGH", 0) > 0
else "MEDIUM" if severity_counts.get("MEDIUM", 0) > 0
else "LOW"
),
}
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"\n[+] Report saved to {args.output}")
elif args.verbose:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()