-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsap_scanner.py
More file actions
234 lines (201 loc) · 8.92 KB
/
sap_scanner.py
File metadata and controls
234 lines (201 loc) · 8.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#!/usr/bin/env python3
"""
SAP S/4HANA RISE Security Scanner
===================================
Offline configuration review tool for identifying vulnerabilities
and misconfigurations in SAP S/4HANA RISE environments.
Reads exported configuration data (CSV/JSON) and produces an
HTML dashboard with findings, risk ratings, and remediation guidance.
Usage:
python sap_scanner.py --data-dir ./sample_data --output report.html
python sap_scanner.py --data-dir ./exports --output report.html --severity HIGH
"""
import argparse
import json
import os
import sys
import datetime
from pathlib import Path
from modules.user_auth_audit import UserAuthAuditor
from modules.security_params import SecurityParamAuditor
from modules.network_services import NetworkServiceAuditor
from modules.rise_btp_checks import RiseBtpAuditor
from modules.iam_advanced import AdvancedIamAuditor
from modules.btp_cloud_surface import BtpCloudSurfaceAuditor
from modules.integration_layer import IntegrationLayerAuditor
from modules.data_protection import DataProtectionAuditor
from modules.code_transport import CodeTransportAuditor
from modules.log_monitoring import LogMonitoringAuditor
from modules.fiori_ui import FioriUiAuditor
from modules.crypto_posture import CryptoPostureAuditor
from modules.report_generator import ReportGenerator
from modules.data_loader import DataLoader
def banner():
print(r"""
╔═══════════════════════════════════════════════════════╗
║ SAP S/4HANA RISE Security Scanner v1.0 ║
║ Offline Configuration Review & Vulnerability Audit ║
╚═══════════════════════════════════════════════════════╝
""")
def main():
banner()
parser = argparse.ArgumentParser(
description="SAP S/4HANA RISE Security Scanner - Offline Config Review"
)
parser.add_argument(
"--data-dir", required=True,
help="Directory containing exported SAP configuration files (CSV/JSON)"
)
parser.add_argument(
"--output", default="sap_security_report.html",
help="Output HTML report filename (default: sap_security_report.html)"
)
parser.add_argument(
"--severity", choices=["CRITICAL", "HIGH", "MEDIUM", "LOW", "ALL"],
default="ALL",
help="Minimum severity to include in report (default: ALL)"
)
parser.add_argument(
"--modules", nargs="+",
choices=["users", "params", "network", "rise", "iam", "btpcloud", "intglayer", "dataprot", "codetrans", "logmon", "fiori", "crypto", "all"],
default=["all"],
help="Which audit modules to run (default: all)"
)
parser.add_argument(
"--config", default=None,
help="Path to custom baseline config JSON (optional)"
)
args = parser.parse_args()
data_dir = Path(args.data_dir)
if not data_dir.exists():
print(f"[ERROR] Data directory not found: {data_dir}")
sys.exit(1)
# Load data
print("[*] Loading exported configuration data...")
loader = DataLoader(data_dir)
data = loader.load_all()
# Load custom baseline if provided
baseline_overrides = {}
if args.config:
with open(args.config, "r") as f:
baseline_overrides = json.load(f)
print(f"[*] Loaded custom baseline from {args.config}")
run_modules = args.modules if "all" not in args.modules else [
"users", "params", "network", "rise", "iam", "btpcloud",
"intglayer", "dataprot", "codetrans", "logmon", "fiori", "crypto"
]
all_findings = []
scan_meta = {
"scan_time": datetime.datetime.now().isoformat(),
"data_directory": str(data_dir),
"modules_run": run_modules,
"severity_filter": args.severity,
}
# --- User & Authorization Audit ---
if "users" in run_modules:
print("[*] Running User & Authorization Audit...")
auditor = UserAuthAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- Security Parameters Baseline ---
if "params" in run_modules:
print("[*] Running Security Parameters Baseline Check...")
auditor = SecurityParamAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- Network & Service Exposure ---
if "network" in run_modules:
print("[*] Running Network & Service Exposure Audit...")
auditor = NetworkServiceAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- RISE/BTP-Specific Checks ---
if "rise" in run_modules:
print("[*] Running RISE/BTP-Specific Checks...")
auditor = RiseBtpAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- Advanced Identity & Access Management ---
if "iam" in run_modules:
print("[*] Running Advanced IAM Checks (SoD, Firefighter, Role Expiry, Cross-ID)...")
auditor = AdvancedIamAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- BTP Cloud Attack Surface ---
if "btpcloud" in run_modules:
print("[*] Running BTP Cloud Attack Surface Checks...")
auditor = BtpCloudSurfaceAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- Network & Integration Layer ---
if "intglayer" in run_modules:
print("[*] Running Network & Integration Layer Checks...")
auditor = IntegrationLayerAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- Data Protection & Privacy ---
if "dataprot" in run_modules:
print("[*] Running Data Protection & Privacy Checks...")
auditor = DataProtectionAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- Code & Transport Security ---
if "codetrans" in run_modules:
print("[*] Running Code & Transport Security Checks...")
auditor = CodeTransportAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- Logging, Monitoring & Incident Response ---
if "logmon" in run_modules:
print("[*] Running Logging, Monitoring & IR Checks...")
auditor = LogMonitoringAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- Fiori & UI Layer ---
if "fiori" in run_modules:
print("[*] Running Fiori & UI Layer Checks...")
auditor = FioriUiAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# --- Cryptographic Posture ---
if "crypto" in run_modules:
print("[*] Running Cryptographic Posture Checks...")
auditor = CryptoPostureAuditor(data, baseline_overrides)
findings = auditor.run_all_checks()
all_findings.extend(findings)
print(f" Found {len(findings)} issue(s)")
# Filter by severity
severity_order = {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2, "LOW": 3, "INFO": 4}
if args.severity != "ALL":
threshold = severity_order.get(args.severity, 4)
all_findings = [
f for f in all_findings
if severity_order.get(f.get("severity", "INFO"), 4) <= threshold
]
# Generate report
print(f"\n[*] Generating HTML report: {args.output}")
generator = ReportGenerator(all_findings, scan_meta)
generator.generate(args.output)
# Summary
crit = sum(1 for f in all_findings if f["severity"] == "CRITICAL")
high = sum(1 for f in all_findings if f["severity"] == "HIGH")
med = sum(1 for f in all_findings if f["severity"] == "MEDIUM")
low = sum(1 for f in all_findings if f["severity"] == "LOW")
print(f"\n{'='*55}")
print(f" SCAN COMPLETE — Total Findings: {len(all_findings)}")
print(f" CRITICAL: {crit} | HIGH: {high} | MEDIUM: {med} | LOW: {low}")
print(f" Report saved to: {args.output}")
print(f"{'='*55}\n")
if __name__ == "__main__":
main()