souleyez 2.43.29__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of souleyez might be problematic. Click here for more details.
- souleyez/__init__.py +1 -2
- souleyez/ai/__init__.py +21 -15
- souleyez/ai/action_mapper.py +249 -150
- souleyez/ai/chain_advisor.py +116 -100
- souleyez/ai/claude_provider.py +29 -28
- souleyez/ai/context_builder.py +80 -62
- souleyez/ai/executor.py +158 -117
- souleyez/ai/feedback_handler.py +136 -121
- souleyez/ai/llm_factory.py +27 -20
- souleyez/ai/llm_provider.py +4 -2
- souleyez/ai/ollama_provider.py +6 -9
- souleyez/ai/ollama_service.py +44 -37
- souleyez/ai/path_scorer.py +91 -76
- souleyez/ai/recommender.py +176 -144
- souleyez/ai/report_context.py +74 -73
- souleyez/ai/report_service.py +84 -66
- souleyez/ai/result_parser.py +222 -229
- souleyez/ai/safety.py +67 -44
- souleyez/auth/__init__.py +23 -22
- souleyez/auth/audit.py +36 -26
- souleyez/auth/engagement_access.py +65 -48
- souleyez/auth/permissions.py +14 -3
- souleyez/auth/session_manager.py +54 -37
- souleyez/auth/user_manager.py +109 -64
- souleyez/commands/audit.py +40 -43
- souleyez/commands/auth.py +35 -15
- souleyez/commands/deliverables.py +55 -50
- souleyez/commands/engagement.py +47 -28
- souleyez/commands/license.py +32 -23
- souleyez/commands/screenshots.py +36 -32
- souleyez/commands/user.py +82 -36
- souleyez/config.py +52 -44
- souleyez/core/credential_tester.py +87 -81
- souleyez/core/cve_mappings.py +179 -192
- souleyez/core/cve_matcher.py +162 -148
- souleyez/core/msf_auto_mapper.py +100 -83
- souleyez/core/msf_chain_engine.py +294 -256
- souleyez/core/msf_database.py +153 -70
- souleyez/core/msf_integration.py +679 -673
- souleyez/core/msf_rpc_client.py +40 -42
- souleyez/core/msf_rpc_manager.py +77 -79
- souleyez/core/msf_sync_manager.py +241 -181
- souleyez/core/network_utils.py +22 -15
- souleyez/core/parser_handler.py +34 -25
- souleyez/core/pending_chains.py +114 -63
- souleyez/core/templates.py +158 -107
- souleyez/core/tool_chaining.py +9564 -2881
- souleyez/core/version_utils.py +79 -94
- souleyez/core/vuln_correlation.py +136 -89
- souleyez/core/web_utils.py +33 -32
- souleyez/data/wordlists/ad_users.txt +378 -0
- souleyez/data/wordlists/api_endpoints_large.txt +769 -0
- souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
- souleyez/data/wordlists/lfi_payloads.txt +82 -0
- souleyez/data/wordlists/passwords_brute.txt +1548 -0
- souleyez/data/wordlists/passwords_crack.txt +2479 -0
- souleyez/data/wordlists/passwords_spray.txt +386 -0
- souleyez/data/wordlists/subdomains_large.txt +5057 -0
- souleyez/data/wordlists/usernames_common.txt +694 -0
- souleyez/data/wordlists/web_dirs_large.txt +4769 -0
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +12 -17
- souleyez/detection/mitre_mappings.py +61 -55
- souleyez/detection/validator.py +97 -86
- souleyez/devtools.py +23 -10
- souleyez/docs/README.md +4 -4
- souleyez/docs/api-reference/cli-commands.md +2 -2
- souleyez/docs/developer-guide/adding-new-tools.md +562 -0
- souleyez/docs/user-guide/auto-chaining.md +30 -8
- souleyez/docs/user-guide/getting-started.md +1 -1
- souleyez/docs/user-guide/installation.md +26 -3
- souleyez/docs/user-guide/metasploit-integration.md +2 -2
- souleyez/docs/user-guide/rbac.md +1 -1
- souleyez/docs/user-guide/scope-management.md +1 -1
- souleyez/docs/user-guide/siem-integration.md +1 -1
- souleyez/docs/user-guide/tools-reference.md +1 -8
- souleyez/docs/user-guide/worker-management.md +1 -1
- souleyez/engine/background.py +1239 -535
- souleyez/engine/base.py +4 -1
- souleyez/engine/job_status.py +17 -49
- souleyez/engine/log_sanitizer.py +103 -77
- souleyez/engine/manager.py +38 -7
- souleyez/engine/result_handler.py +2200 -1550
- souleyez/engine/worker_manager.py +50 -41
- souleyez/export/evidence_bundle.py +72 -62
- souleyez/feature_flags/features.py +16 -20
- souleyez/feature_flags.py +5 -9
- souleyez/handlers/__init__.py +11 -0
- souleyez/handlers/base.py +188 -0
- souleyez/handlers/bash_handler.py +277 -0
- souleyez/handlers/bloodhound_handler.py +243 -0
- souleyez/handlers/certipy_handler.py +311 -0
- souleyez/handlers/crackmapexec_handler.py +486 -0
- souleyez/handlers/dnsrecon_handler.py +344 -0
- souleyez/handlers/enum4linux_handler.py +400 -0
- souleyez/handlers/evil_winrm_handler.py +493 -0
- souleyez/handlers/ffuf_handler.py +815 -0
- souleyez/handlers/gobuster_handler.py +1114 -0
- souleyez/handlers/gpp_extract_handler.py +334 -0
- souleyez/handlers/hashcat_handler.py +444 -0
- souleyez/handlers/hydra_handler.py +564 -0
- souleyez/handlers/impacket_getuserspns_handler.py +343 -0
- souleyez/handlers/impacket_psexec_handler.py +222 -0
- souleyez/handlers/impacket_secretsdump_handler.py +426 -0
- souleyez/handlers/john_handler.py +286 -0
- souleyez/handlers/katana_handler.py +425 -0
- souleyez/handlers/kerbrute_handler.py +298 -0
- souleyez/handlers/ldapsearch_handler.py +636 -0
- souleyez/handlers/lfi_extract_handler.py +464 -0
- souleyez/handlers/msf_auxiliary_handler.py +409 -0
- souleyez/handlers/msf_exploit_handler.py +380 -0
- souleyez/handlers/nikto_handler.py +413 -0
- souleyez/handlers/nmap_handler.py +821 -0
- souleyez/handlers/nuclei_handler.py +359 -0
- souleyez/handlers/nxc_handler.py +417 -0
- souleyez/handlers/rdp_sec_check_handler.py +353 -0
- souleyez/handlers/registry.py +292 -0
- souleyez/handlers/responder_handler.py +232 -0
- souleyez/handlers/service_explorer_handler.py +434 -0
- souleyez/handlers/smbclient_handler.py +344 -0
- souleyez/handlers/smbmap_handler.py +510 -0
- souleyez/handlers/smbpasswd_handler.py +296 -0
- souleyez/handlers/sqlmap_handler.py +1116 -0
- souleyez/handlers/theharvester_handler.py +601 -0
- souleyez/handlers/web_login_test_handler.py +327 -0
- souleyez/handlers/whois_handler.py +277 -0
- souleyez/handlers/wpscan_handler.py +554 -0
- souleyez/history.py +32 -16
- souleyez/importers/msf_importer.py +106 -75
- souleyez/importers/smart_importer.py +208 -147
- souleyez/integrations/siem/__init__.py +10 -10
- souleyez/integrations/siem/base.py +17 -18
- souleyez/integrations/siem/elastic.py +108 -122
- souleyez/integrations/siem/factory.py +207 -80
- souleyez/integrations/siem/googlesecops.py +146 -154
- souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
- souleyez/integrations/siem/sentinel.py +107 -109
- souleyez/integrations/siem/splunk.py +246 -212
- souleyez/integrations/siem/wazuh.py +65 -71
- souleyez/integrations/wazuh/__init__.py +5 -5
- souleyez/integrations/wazuh/client.py +70 -93
- souleyez/integrations/wazuh/config.py +85 -57
- souleyez/integrations/wazuh/host_mapper.py +28 -36
- souleyez/integrations/wazuh/sync.py +78 -68
- souleyez/intelligence/__init__.py +4 -5
- souleyez/intelligence/correlation_analyzer.py +309 -295
- souleyez/intelligence/exploit_knowledge.py +661 -623
- souleyez/intelligence/exploit_suggestions.py +159 -139
- souleyez/intelligence/gap_analyzer.py +132 -97
- souleyez/intelligence/gap_detector.py +251 -214
- souleyez/intelligence/sensitive_tables.py +266 -129
- souleyez/intelligence/service_parser.py +137 -123
- souleyez/intelligence/surface_analyzer.py +407 -268
- souleyez/intelligence/target_parser.py +159 -162
- souleyez/licensing/__init__.py +6 -6
- souleyez/licensing/validator.py +17 -19
- souleyez/log_config.py +79 -54
- souleyez/main.py +1505 -687
- souleyez/migrations/fix_job_counter.py +16 -14
- souleyez/parsers/bloodhound_parser.py +41 -39
- souleyez/parsers/crackmapexec_parser.py +178 -111
- souleyez/parsers/dalfox_parser.py +72 -77
- souleyez/parsers/dnsrecon_parser.py +103 -91
- souleyez/parsers/enum4linux_parser.py +183 -153
- souleyez/parsers/ffuf_parser.py +29 -25
- souleyez/parsers/gobuster_parser.py +301 -41
- souleyez/parsers/hashcat_parser.py +324 -79
- souleyez/parsers/http_fingerprint_parser.py +350 -103
- souleyez/parsers/hydra_parser.py +131 -111
- souleyez/parsers/impacket_parser.py +231 -178
- souleyez/parsers/john_parser.py +98 -86
- souleyez/parsers/katana_parser.py +316 -0
- souleyez/parsers/msf_parser.py +943 -498
- souleyez/parsers/nikto_parser.py +346 -65
- souleyez/parsers/nmap_parser.py +262 -174
- souleyez/parsers/nuclei_parser.py +40 -44
- souleyez/parsers/responder_parser.py +26 -26
- souleyez/parsers/searchsploit_parser.py +74 -74
- souleyez/parsers/service_explorer_parser.py +279 -0
- souleyez/parsers/smbmap_parser.py +180 -124
- souleyez/parsers/sqlmap_parser.py +434 -308
- souleyez/parsers/theharvester_parser.py +75 -57
- souleyez/parsers/whois_parser.py +135 -94
- souleyez/parsers/wpscan_parser.py +278 -190
- souleyez/plugins/afp.py +44 -36
- souleyez/plugins/afp_brute.py +114 -46
- souleyez/plugins/ard.py +48 -37
- souleyez/plugins/bloodhound.py +95 -61
- souleyez/plugins/certipy.py +303 -0
- souleyez/plugins/crackmapexec.py +186 -85
- souleyez/plugins/dalfox.py +120 -59
- souleyez/plugins/dns_hijack.py +146 -41
- souleyez/plugins/dnsrecon.py +97 -61
- souleyez/plugins/enum4linux.py +91 -66
- souleyez/plugins/evil_winrm.py +291 -0
- souleyez/plugins/ffuf.py +166 -90
- souleyez/plugins/firmware_extract.py +133 -29
- souleyez/plugins/gobuster.py +387 -190
- souleyez/plugins/gpp_extract.py +393 -0
- souleyez/plugins/hashcat.py +100 -73
- souleyez/plugins/http_fingerprint.py +913 -267
- souleyez/plugins/hydra.py +566 -200
- souleyez/plugins/impacket_getnpusers.py +117 -69
- souleyez/plugins/impacket_psexec.py +84 -64
- souleyez/plugins/impacket_secretsdump.py +103 -69
- souleyez/plugins/impacket_smbclient.py +89 -75
- souleyez/plugins/john.py +86 -69
- souleyez/plugins/katana.py +313 -0
- souleyez/plugins/kerbrute.py +237 -0
- souleyez/plugins/lfi_extract.py +541 -0
- souleyez/plugins/macos_ssh.py +117 -48
- souleyez/plugins/mdns.py +35 -30
- souleyez/plugins/msf_auxiliary.py +253 -130
- souleyez/plugins/msf_exploit.py +239 -161
- souleyez/plugins/nikto.py +134 -78
- souleyez/plugins/nmap.py +275 -91
- souleyez/plugins/nuclei.py +180 -89
- souleyez/plugins/nxc.py +285 -0
- souleyez/plugins/plugin_base.py +35 -36
- souleyez/plugins/plugin_template.py +13 -5
- souleyez/plugins/rdp_sec_check.py +130 -0
- souleyez/plugins/responder.py +112 -71
- souleyez/plugins/router_http_brute.py +76 -65
- souleyez/plugins/router_ssh_brute.py +118 -41
- souleyez/plugins/router_telnet_brute.py +124 -42
- souleyez/plugins/routersploit.py +91 -59
- souleyez/plugins/routersploit_exploit.py +77 -55
- souleyez/plugins/searchsploit.py +91 -77
- souleyez/plugins/service_explorer.py +1160 -0
- souleyez/plugins/smbmap.py +122 -72
- souleyez/plugins/smbpasswd.py +215 -0
- souleyez/plugins/sqlmap.py +301 -113
- souleyez/plugins/theharvester.py +127 -75
- souleyez/plugins/tr069.py +79 -57
- souleyez/plugins/upnp.py +65 -47
- souleyez/plugins/upnp_abuse.py +73 -55
- souleyez/plugins/vnc_access.py +129 -42
- souleyez/plugins/vnc_brute.py +109 -38
- souleyez/plugins/web_login_test.py +417 -0
- souleyez/plugins/whois.py +77 -58
- souleyez/plugins/wpscan.py +219 -69
- souleyez/reporting/__init__.py +2 -1
- souleyez/reporting/attack_chain.py +411 -346
- souleyez/reporting/charts.py +436 -501
- souleyez/reporting/compliance_mappings.py +334 -201
- souleyez/reporting/detection_report.py +126 -125
- souleyez/reporting/formatters.py +828 -591
- souleyez/reporting/generator.py +386 -302
- souleyez/reporting/metrics.py +72 -75
- souleyez/scanner.py +35 -29
- souleyez/security/__init__.py +37 -11
- souleyez/security/scope_validator.py +175 -106
- souleyez/security/validation.py +237 -149
- souleyez/security.py +22 -6
- souleyez/storage/credentials.py +247 -186
- souleyez/storage/crypto.py +296 -129
- souleyez/storage/database.py +73 -50
- souleyez/storage/db.py +58 -36
- souleyez/storage/deliverable_evidence.py +177 -128
- souleyez/storage/deliverable_exporter.py +282 -246
- souleyez/storage/deliverable_templates.py +134 -116
- souleyez/storage/deliverables.py +135 -130
- souleyez/storage/engagements.py +109 -56
- souleyez/storage/evidence.py +181 -152
- souleyez/storage/execution_log.py +31 -17
- souleyez/storage/exploit_attempts.py +93 -57
- souleyez/storage/exploits.py +67 -36
- souleyez/storage/findings.py +48 -61
- souleyez/storage/hosts.py +176 -144
- souleyez/storage/migrate_to_engagements.py +43 -19
- souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
- souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
- souleyez/storage/migrations/_003_add_execution_log.py +14 -8
- souleyez/storage/migrations/_005_screenshots.py +13 -5
- souleyez/storage/migrations/_006_deliverables.py +13 -5
- souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
- souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
- souleyez/storage/migrations/_010_evidence_linking.py +17 -10
- souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
- souleyez/storage/migrations/_012_team_collaboration.py +34 -21
- souleyez/storage/migrations/_013_add_host_tags.py +12 -6
- souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
- souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
- souleyez/storage/migrations/_016_add_domain_field.py +10 -4
- souleyez/storage/migrations/_017_msf_sessions.py +16 -8
- souleyez/storage/migrations/_018_add_osint_target.py +10 -6
- souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
- souleyez/storage/migrations/_020_add_rbac.py +36 -15
- souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
- souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
- souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
- souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
- souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
- souleyez/storage/migrations/__init__.py +26 -26
- souleyez/storage/migrations/migration_manager.py +19 -19
- souleyez/storage/msf_sessions.py +100 -65
- souleyez/storage/osint.py +17 -24
- souleyez/storage/recommendation_engine.py +269 -235
- souleyez/storage/screenshots.py +33 -32
- souleyez/storage/smb_shares.py +136 -92
- souleyez/storage/sqlmap_data.py +183 -128
- souleyez/storage/team_collaboration.py +135 -141
- souleyez/storage/timeline_tracker.py +122 -94
- souleyez/storage/wazuh_vulns.py +64 -66
- souleyez/storage/web_paths.py +33 -37
- souleyez/testing/credential_tester.py +221 -205
- souleyez/ui/__init__.py +1 -1
- souleyez/ui/ai_quotes.py +12 -12
- souleyez/ui/attack_surface.py +2439 -1516
- souleyez/ui/chain_rules_view.py +914 -382
- souleyez/ui/correlation_view.py +312 -230
- souleyez/ui/dashboard.py +2382 -1130
- souleyez/ui/deliverables_view.py +148 -62
- souleyez/ui/design_system.py +13 -13
- souleyez/ui/errors.py +49 -49
- souleyez/ui/evidence_linking_view.py +284 -179
- souleyez/ui/evidence_vault.py +393 -285
- souleyez/ui/exploit_suggestions_view.py +555 -349
- souleyez/ui/export_view.py +100 -66
- souleyez/ui/gap_analysis_view.py +315 -171
- souleyez/ui/help_system.py +105 -97
- souleyez/ui/intelligence_view.py +436 -293
- souleyez/ui/interactive.py +23034 -10679
- souleyez/ui/interactive_selector.py +75 -68
- souleyez/ui/log_formatter.py +47 -39
- souleyez/ui/menu_components.py +22 -13
- souleyez/ui/msf_auxiliary_menu.py +184 -133
- souleyez/ui/pending_chains_view.py +336 -172
- souleyez/ui/progress_indicators.py +5 -3
- souleyez/ui/recommendations_view.py +195 -137
- souleyez/ui/rule_builder.py +343 -225
- souleyez/ui/setup_wizard.py +678 -284
- souleyez/ui/shortcuts.py +217 -165
- souleyez/ui/splunk_gap_analysis_view.py +452 -270
- souleyez/ui/splunk_vulns_view.py +139 -86
- souleyez/ui/team_dashboard.py +498 -335
- souleyez/ui/template_selector.py +196 -105
- souleyez/ui/terminal.py +6 -6
- souleyez/ui/timeline_view.py +198 -127
- souleyez/ui/tool_setup.py +264 -164
- souleyez/ui/tutorial.py +202 -72
- souleyez/ui/tutorial_state.py +40 -40
- souleyez/ui/wazuh_vulns_view.py +235 -141
- souleyez/ui/wordlist_browser.py +260 -107
- souleyez/ui.py +464 -312
- souleyez/utils/tool_checker.py +427 -367
- souleyez/utils.py +33 -29
- souleyez/wordlists.py +134 -167
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/METADATA +2 -2
- souleyez-3.0.0.dist-info/RECORD +443 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/WHEEL +1 -1
- souleyez-2.43.29.dist-info/RECORD +0 -379
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/top_level.txt +0 -0
souleyez/ai/feedback_handler.py
CHANGED
|
@@ -14,7 +14,7 @@ logger = logging.getLogger(__name__)
|
|
|
14
14
|
class FeedbackHandler:
|
|
15
15
|
"""
|
|
16
16
|
Automatically update database based on command execution results.
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
Implements the feedback loop:
|
|
19
19
|
- Update credential status (valid/invalid)
|
|
20
20
|
- Update host status (compromised/active)
|
|
@@ -32,63 +32,74 @@ class FeedbackHandler:
|
|
|
32
32
|
engagement_id: int,
|
|
33
33
|
parsed_result: Dict[str, Any],
|
|
34
34
|
recommendation: Dict[str, Any],
|
|
35
|
-
command: str
|
|
35
|
+
command: str,
|
|
36
36
|
) -> Dict[str, Any]:
|
|
37
37
|
"""
|
|
38
38
|
Apply feedback updates to database.
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
Args:
|
|
41
41
|
engagement_id: Current engagement ID
|
|
42
42
|
parsed_result: Parsed command result
|
|
43
43
|
recommendation: Original AI recommendation
|
|
44
44
|
command: Command that was executed
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
Returns:
|
|
47
47
|
Dict describing what was updated
|
|
48
48
|
"""
|
|
49
49
|
feedback = {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
"hosts_updated": 0,
|
|
51
|
+
"credentials_updated": 0,
|
|
52
|
+
"services_added": 0,
|
|
53
|
+
"notes_added": [],
|
|
54
54
|
}
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
# Extract target IP
|
|
57
|
-
target = recommendation.get(
|
|
58
|
-
action = recommendation.get(
|
|
59
|
-
|
|
57
|
+
target = recommendation.get("target", "")
|
|
58
|
+
action = recommendation.get("action", "").lower()
|
|
59
|
+
|
|
60
60
|
import re
|
|
61
|
-
|
|
61
|
+
|
|
62
|
+
ip_match = re.search(r"\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b", target)
|
|
62
63
|
if not ip_match:
|
|
63
64
|
logger.warning(f"Could not extract IP from target: {target}")
|
|
64
65
|
return feedback
|
|
65
|
-
|
|
66
|
+
|
|
66
67
|
ip = ip_match.group(1)
|
|
67
|
-
|
|
68
|
+
|
|
68
69
|
# Get host from database
|
|
69
70
|
host = self.host_mgr.get_host_by_ip(engagement_id, ip)
|
|
70
71
|
if not host:
|
|
71
72
|
logger.warning(f"Host {ip} not found in engagement {engagement_id}")
|
|
72
73
|
return feedback
|
|
73
|
-
|
|
74
|
+
|
|
74
75
|
# Handle SSH results
|
|
75
|
-
if
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
if (
|
|
77
|
+
"ssh" in command.lower()
|
|
78
|
+
and parsed_result.get("credential_valid") is not None
|
|
79
|
+
):
|
|
80
|
+
feedback.update(
|
|
81
|
+
self._handle_ssh_feedback(
|
|
82
|
+
engagement_id, host, parsed_result, recommendation
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
|
|
80
86
|
# Handle MySQL results
|
|
81
|
-
elif
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
elif (
|
|
88
|
+
"mysql" in command.lower()
|
|
89
|
+
and parsed_result.get("credential_valid") is not None
|
|
90
|
+
):
|
|
91
|
+
feedback.update(
|
|
92
|
+
self._handle_mysql_feedback(
|
|
93
|
+
engagement_id, host, parsed_result, recommendation
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
|
|
86
97
|
# Handle nmap results
|
|
87
|
-
elif
|
|
88
|
-
feedback.update(
|
|
89
|
-
engagement_id, host, parsed_result
|
|
90
|
-
)
|
|
91
|
-
|
|
98
|
+
elif "nmap" in command.lower() and parsed_result.get("open_ports"):
|
|
99
|
+
feedback.update(
|
|
100
|
+
self._handle_nmap_feedback(engagement_id, host, parsed_result)
|
|
101
|
+
)
|
|
102
|
+
|
|
92
103
|
return feedback
|
|
93
104
|
|
|
94
105
|
def _handle_ssh_feedback(
|
|
@@ -96,61 +107,63 @@ class FeedbackHandler:
|
|
|
96
107
|
engagement_id: int,
|
|
97
108
|
host: Dict[str, Any],
|
|
98
109
|
result: Dict[str, Any],
|
|
99
|
-
recommendation: Dict[str, Any]
|
|
110
|
+
recommendation: Dict[str, Any],
|
|
100
111
|
) -> Dict[str, Any]:
|
|
101
112
|
"""Handle feedback for SSH credential testing."""
|
|
102
|
-
feedback = {
|
|
103
|
-
|
|
113
|
+
feedback = {"hosts_updated": 0, "credentials_updated": 0, "notes_added": []}
|
|
114
|
+
|
|
104
115
|
# Extract credentials from recommendation
|
|
105
116
|
import re
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
117
|
+
|
|
118
|
+
text = (
|
|
119
|
+
f"{recommendation.get('action', '')} {recommendation.get('rationale', '')}"
|
|
120
|
+
)
|
|
121
|
+
cred_match = re.search(r"(\w+):(\w+)", text)
|
|
122
|
+
|
|
109
123
|
if not cred_match:
|
|
110
124
|
logger.warning("Could not extract credentials from recommendation")
|
|
111
125
|
return feedback
|
|
112
|
-
|
|
126
|
+
|
|
113
127
|
username = cred_match.group(1)
|
|
114
128
|
password = cred_match.group(2)
|
|
115
|
-
|
|
129
|
+
|
|
116
130
|
# Find credential in database
|
|
117
131
|
creds = self.creds_mgr.list_credentials(engagement_id)
|
|
118
132
|
cred_id = None
|
|
119
133
|
for cred in creds:
|
|
120
|
-
if cred.get(
|
|
121
|
-
cred_id = cred.get(
|
|
134
|
+
if cred.get("username") == username and cred.get("password") == password:
|
|
135
|
+
cred_id = cred.get("id")
|
|
122
136
|
break
|
|
123
|
-
|
|
137
|
+
|
|
124
138
|
# Update credential status
|
|
125
139
|
if cred_id:
|
|
126
|
-
status =
|
|
127
|
-
notes = result.get(
|
|
128
|
-
|
|
129
|
-
self.creds_mgr.update_credential_status(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
status = "valid" if result.get("credential_valid") else "invalid"
|
|
141
|
+
notes = result.get("details", "")
|
|
142
|
+
|
|
143
|
+
self.creds_mgr.update_credential_status(cred_id, status=status, notes=notes)
|
|
144
|
+
feedback["credentials_updated"] = 1
|
|
145
|
+
feedback["notes_added"].append(
|
|
146
|
+
f"Updated credential {username} status: {status}"
|
|
133
147
|
)
|
|
134
|
-
feedback['credentials_updated'] = 1
|
|
135
|
-
feedback['notes_added'].append(f"Updated credential {username} status: {status}")
|
|
136
148
|
logger.info(f"Updated credential {cred_id} status to {status}")
|
|
137
|
-
|
|
149
|
+
|
|
138
150
|
# Update host status if credentials were valid
|
|
139
|
-
if result.get(
|
|
140
|
-
access_level = result.get(
|
|
141
|
-
status =
|
|
151
|
+
if result.get("credential_valid"):
|
|
152
|
+
access_level = result.get("access_level", "user")
|
|
153
|
+
status = "compromised"
|
|
142
154
|
notes = f"Gained {access_level} access via SSH with {username}:{password}"
|
|
143
|
-
|
|
155
|
+
|
|
144
156
|
self.host_mgr.update_host_status(
|
|
145
|
-
host[
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
157
|
+
host["id"], status=status, access_level=access_level, notes=notes
|
|
158
|
+
)
|
|
159
|
+
feedback["hosts_updated"] = 1
|
|
160
|
+
feedback["notes_added"].append(
|
|
161
|
+
f"Updated host {host['ip_address']}: {status}, access={access_level}"
|
|
149
162
|
)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
163
|
+
logger.info(
|
|
164
|
+
f"Updated host {host['id']} to {status} with {access_level} access"
|
|
165
|
+
)
|
|
166
|
+
|
|
154
167
|
return feedback
|
|
155
168
|
|
|
156
169
|
def _handle_mysql_feedback(
|
|
@@ -158,106 +171,108 @@ class FeedbackHandler:
|
|
|
158
171
|
engagement_id: int,
|
|
159
172
|
host: Dict[str, Any],
|
|
160
173
|
result: Dict[str, Any],
|
|
161
|
-
recommendation: Dict[str, Any]
|
|
174
|
+
recommendation: Dict[str, Any],
|
|
162
175
|
) -> Dict[str, Any]:
|
|
163
176
|
"""Handle feedback for MySQL credential testing."""
|
|
164
|
-
feedback = {
|
|
165
|
-
|
|
177
|
+
feedback = {"hosts_updated": 0, "credentials_updated": 0, "notes_added": []}
|
|
178
|
+
|
|
166
179
|
# Extract credentials
|
|
167
180
|
import re
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
181
|
+
|
|
182
|
+
text = (
|
|
183
|
+
f"{recommendation.get('action', '')} {recommendation.get('rationale', '')}"
|
|
184
|
+
)
|
|
185
|
+
cred_match = re.search(r"(\w+):(\w+)", text)
|
|
186
|
+
|
|
171
187
|
if not cred_match:
|
|
172
188
|
return feedback
|
|
173
|
-
|
|
189
|
+
|
|
174
190
|
username = cred_match.group(1)
|
|
175
191
|
password = cred_match.group(2)
|
|
176
|
-
|
|
192
|
+
|
|
177
193
|
# Find/update credential
|
|
178
194
|
creds = self.creds_mgr.list_credentials(engagement_id)
|
|
179
195
|
cred_id = None
|
|
180
196
|
for cred in creds:
|
|
181
|
-
if (
|
|
182
|
-
cred.get(
|
|
183
|
-
cred.get(
|
|
184
|
-
|
|
197
|
+
if (
|
|
198
|
+
cred.get("username") == username
|
|
199
|
+
and cred.get("password") == password
|
|
200
|
+
and cred.get("service") == "mysql"
|
|
201
|
+
):
|
|
202
|
+
cred_id = cred.get("id")
|
|
185
203
|
break
|
|
186
|
-
|
|
204
|
+
|
|
187
205
|
if cred_id:
|
|
188
|
-
status =
|
|
189
|
-
notes = result.get(
|
|
190
|
-
|
|
191
|
-
self.creds_mgr.update_credential_status(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
206
|
+
status = "valid" if result.get("credential_valid") else "invalid"
|
|
207
|
+
notes = result.get("details", "")
|
|
208
|
+
|
|
209
|
+
self.creds_mgr.update_credential_status(cred_id, status=status, notes=notes)
|
|
210
|
+
feedback["credentials_updated"] = 1
|
|
211
|
+
feedback["notes_added"].append(
|
|
212
|
+
f"Updated MySQL credential {username} status: {status}"
|
|
195
213
|
)
|
|
196
|
-
|
|
197
|
-
feedback['notes_added'].append(f"Updated MySQL credential {username} status: {status}")
|
|
198
|
-
|
|
214
|
+
|
|
199
215
|
# Update host notes if connection was successful
|
|
200
|
-
if result.get(
|
|
216
|
+
if result.get("credential_valid"):
|
|
201
217
|
notes = f"MySQL access confirmed with {username}:{password}"
|
|
202
|
-
if result.get(
|
|
218
|
+
if result.get("databases"):
|
|
203
219
|
notes += f" - Databases: {', '.join(result['databases'][:5])}"
|
|
204
|
-
|
|
220
|
+
|
|
205
221
|
# Only update if not already compromised with higher access
|
|
206
|
-
current_access = host.get(
|
|
207
|
-
if current_access ==
|
|
208
|
-
self.host_mgr.update_host_status(
|
|
209
|
-
|
|
210
|
-
|
|
222
|
+
current_access = host.get("access_level", "none")
|
|
223
|
+
if current_access == "none":
|
|
224
|
+
self.host_mgr.update_host_status(host["id"], notes=notes)
|
|
225
|
+
feedback["hosts_updated"] = 1
|
|
226
|
+
feedback["notes_added"].append(
|
|
227
|
+
f"Added MySQL access notes to host {host['ip_address']}"
|
|
211
228
|
)
|
|
212
|
-
|
|
213
|
-
feedback['notes_added'].append(f"Added MySQL access notes to host {host['ip_address']}")
|
|
214
|
-
|
|
229
|
+
|
|
215
230
|
return feedback
|
|
216
231
|
|
|
217
232
|
def _handle_nmap_feedback(
|
|
218
|
-
self,
|
|
219
|
-
engagement_id: int,
|
|
220
|
-
host: Dict[str, Any],
|
|
221
|
-
result: Dict[str, Any]
|
|
233
|
+
self, engagement_id: int, host: Dict[str, Any], result: Dict[str, Any]
|
|
222
234
|
) -> Dict[str, Any]:
|
|
223
235
|
"""Handle feedback for nmap scans."""
|
|
224
|
-
feedback = {
|
|
225
|
-
|
|
236
|
+
feedback = {"hosts_updated": 0, "services_added": 0, "notes_added": []}
|
|
237
|
+
|
|
226
238
|
# Add discovered services
|
|
227
|
-
open_ports = result.get(
|
|
228
|
-
services_info = result.get(
|
|
229
|
-
|
|
239
|
+
open_ports = result.get("open_ports", [])
|
|
240
|
+
services_info = result.get("services", {})
|
|
241
|
+
|
|
230
242
|
for port in open_ports:
|
|
231
|
-
service_info = services_info.get(str(port),
|
|
232
|
-
|
|
243
|
+
service_info = services_info.get(str(port), "unknown")
|
|
244
|
+
|
|
233
245
|
# Try to parse service name and version
|
|
234
246
|
import re
|
|
235
|
-
|
|
247
|
+
|
|
248
|
+
service_match = re.match(r"(\S+)(?:\s+(.+))?", service_info)
|
|
236
249
|
if service_match:
|
|
237
250
|
service_name = service_match.group(1)
|
|
238
|
-
service_version =
|
|
251
|
+
service_version = (
|
|
252
|
+
service_match.group(2) if service_match.group(2) else None
|
|
253
|
+
)
|
|
239
254
|
else:
|
|
240
|
-
service_name =
|
|
255
|
+
service_name = "unknown"
|
|
241
256
|
service_version = None
|
|
242
|
-
|
|
257
|
+
|
|
243
258
|
# Add service to database
|
|
244
259
|
try:
|
|
245
260
|
self.host_mgr.add_service(
|
|
246
|
-
host[
|
|
261
|
+
host["id"],
|
|
247
262
|
port=port,
|
|
248
|
-
protocol=
|
|
263
|
+
protocol="tcp",
|
|
249
264
|
service_name=service_name,
|
|
250
265
|
service_version=service_version,
|
|
251
|
-
state=
|
|
266
|
+
state="open",
|
|
252
267
|
)
|
|
253
|
-
feedback[
|
|
268
|
+
feedback["services_added"] += 1
|
|
254
269
|
logger.info(f"Added service {service_name} on port {port}")
|
|
255
270
|
except Exception as e:
|
|
256
271
|
logger.warning(f"Failed to add service {port}: {e}")
|
|
257
|
-
|
|
258
|
-
if feedback[
|
|
259
|
-
feedback[
|
|
272
|
+
|
|
273
|
+
if feedback["services_added"] > 0:
|
|
274
|
+
feedback["notes_added"].append(
|
|
260
275
|
f"Added {feedback['services_added']} services to host {host['ip_address']}"
|
|
261
276
|
)
|
|
262
|
-
|
|
277
|
+
|
|
263
278
|
return feedback
|
souleyez/ai/llm_factory.py
CHANGED
|
@@ -4,6 +4,7 @@ souleyez.ai.llm_factory - Factory for creating LLM providers
|
|
|
4
4
|
This module provides a factory pattern for creating LLM providers
|
|
5
5
|
based on user configuration.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
from typing import Optional
|
|
9
10
|
|
|
@@ -35,20 +36,24 @@ class LLMFactory:
|
|
|
35
36
|
|
|
36
37
|
if provider_type is None:
|
|
37
38
|
# Read from config
|
|
38
|
-
provider_str = get(
|
|
39
|
+
provider_str = get("ai.provider", "ollama")
|
|
39
40
|
try:
|
|
40
41
|
provider_type = LLMProviderType(provider_str)
|
|
41
42
|
except ValueError:
|
|
42
|
-
logger.warning(
|
|
43
|
+
logger.warning(
|
|
44
|
+
f"Unknown provider '{provider_str}', defaulting to ollama"
|
|
45
|
+
)
|
|
43
46
|
provider_type = LLMProviderType.OLLAMA
|
|
44
47
|
|
|
45
48
|
if provider_type == LLMProviderType.CLAUDE:
|
|
46
49
|
from .claude_provider import ClaudeProvider
|
|
47
|
-
|
|
50
|
+
|
|
51
|
+
model = get("ai.claude_model")
|
|
48
52
|
return ClaudeProvider(model=model)
|
|
49
53
|
else:
|
|
50
54
|
from .ollama_provider import OllamaProvider
|
|
51
|
-
|
|
55
|
+
|
|
56
|
+
model = get("ai.ollama_model") or get("settings.ollama_model")
|
|
52
57
|
return OllamaProvider(model=model)
|
|
53
58
|
|
|
54
59
|
@staticmethod
|
|
@@ -103,33 +108,35 @@ class LLMFactory:
|
|
|
103
108
|
# Check Ollama
|
|
104
109
|
try:
|
|
105
110
|
from .ollama_provider import OllamaProvider
|
|
111
|
+
|
|
106
112
|
ollama = OllamaProvider()
|
|
107
|
-
results[
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
results["ollama"] = {
|
|
114
|
+
"available": ollama.is_available(),
|
|
115
|
+
"status": ollama.get_status(),
|
|
116
|
+
"configured": get("ai.provider", "ollama") == "ollama",
|
|
111
117
|
}
|
|
112
118
|
except Exception as e:
|
|
113
|
-
results[
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
results["ollama"] = {
|
|
120
|
+
"available": False,
|
|
121
|
+
"error": str(e),
|
|
122
|
+
"configured": get("ai.provider", "ollama") == "ollama",
|
|
117
123
|
}
|
|
118
124
|
|
|
119
125
|
# Check Claude
|
|
120
126
|
try:
|
|
121
127
|
from .claude_provider import ClaudeProvider
|
|
128
|
+
|
|
122
129
|
claude = ClaudeProvider()
|
|
123
|
-
results[
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
130
|
+
results["claude"] = {
|
|
131
|
+
"available": claude.is_available(),
|
|
132
|
+
"status": claude.get_status(),
|
|
133
|
+
"configured": get("ai.provider", "ollama") == "claude",
|
|
127
134
|
}
|
|
128
135
|
except Exception as e:
|
|
129
|
-
results[
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
results["claude"] = {
|
|
137
|
+
"available": False,
|
|
138
|
+
"error": str(e),
|
|
139
|
+
"configured": get("ai.provider", "ollama") == "claude",
|
|
133
140
|
}
|
|
134
141
|
|
|
135
142
|
return results
|
souleyez/ai/llm_provider.py
CHANGED
|
@@ -4,6 +4,7 @@ souleyez.ai.llm_provider - Abstract LLM provider interface
|
|
|
4
4
|
This module defines the abstract base class for LLM providers,
|
|
5
5
|
enabling support for multiple backends (Ollama, Claude, etc.)
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
from abc import ABC, abstractmethod
|
|
8
9
|
from enum import Enum
|
|
9
10
|
from typing import Optional, Dict, Any
|
|
@@ -14,6 +15,7 @@ logger = logging.getLogger(__name__)
|
|
|
14
15
|
|
|
15
16
|
class LLMProviderType(Enum):
|
|
16
17
|
"""Supported LLM provider types."""
|
|
18
|
+
|
|
17
19
|
OLLAMA = "ollama"
|
|
18
20
|
CLAUDE = "claude"
|
|
19
21
|
|
|
@@ -54,7 +56,7 @@ class LLMProvider(ABC):
|
|
|
54
56
|
prompt: str,
|
|
55
57
|
system_prompt: Optional[str] = None,
|
|
56
58
|
max_tokens: int = 4096,
|
|
57
|
-
temperature: float = 0.3
|
|
59
|
+
temperature: float = 0.3,
|
|
58
60
|
) -> Optional[str]:
|
|
59
61
|
"""
|
|
60
62
|
Generate text from a prompt.
|
|
@@ -86,7 +88,7 @@ class LLMProvider(ABC):
|
|
|
86
88
|
system_prompt: Optional[str] = None,
|
|
87
89
|
max_tokens: int = 4096,
|
|
88
90
|
temperature: float = 0.3,
|
|
89
|
-
fallback: Optional[str] = None
|
|
91
|
+
fallback: Optional[str] = None,
|
|
90
92
|
) -> str:
|
|
91
93
|
"""
|
|
92
94
|
Generate text with a fallback value if generation fails.
|
souleyez/ai/ollama_provider.py
CHANGED
|
@@ -3,6 +3,7 @@ souleyez.ai.ollama_provider - Ollama LLM provider implementation
|
|
|
3
3
|
|
|
4
4
|
Wraps the existing OllamaService to implement the LLMProvider interface.
|
|
5
5
|
"""
|
|
6
|
+
|
|
6
7
|
import logging
|
|
7
8
|
from typing import Optional, Dict, Any
|
|
8
9
|
|
|
@@ -20,11 +21,7 @@ class OllamaProvider(LLMProvider):
|
|
|
20
21
|
No API key required, but Ollama must be installed and running.
|
|
21
22
|
"""
|
|
22
23
|
|
|
23
|
-
def __init__(
|
|
24
|
-
self,
|
|
25
|
-
model: Optional[str] = None,
|
|
26
|
-
endpoint: Optional[str] = None
|
|
27
|
-
):
|
|
24
|
+
def __init__(self, model: Optional[str] = None, endpoint: Optional[str] = None):
|
|
28
25
|
"""
|
|
29
26
|
Initialize Ollama provider.
|
|
30
27
|
|
|
@@ -71,7 +68,7 @@ class OllamaProvider(LLMProvider):
|
|
|
71
68
|
prompt: str,
|
|
72
69
|
system_prompt: Optional[str] = None,
|
|
73
70
|
max_tokens: int = 4096,
|
|
74
|
-
temperature: float = 0.3
|
|
71
|
+
temperature: float = 0.3,
|
|
75
72
|
) -> Optional[str]:
|
|
76
73
|
"""
|
|
77
74
|
Generate text using Ollama.
|
|
@@ -108,7 +105,7 @@ class OllamaProvider(LLMProvider):
|
|
|
108
105
|
dict: Status including connection, models, availability
|
|
109
106
|
"""
|
|
110
107
|
status = self._service.get_status()
|
|
111
|
-
status[
|
|
112
|
-
status[
|
|
113
|
-
status[
|
|
108
|
+
status["provider_type"] = self.provider_type.value
|
|
109
|
+
status["provider"] = "Ollama"
|
|
110
|
+
status["provider_name"] = "Ollama (Local)"
|
|
114
111
|
return status
|