souleyez 2.43.34__py3-none-any.whl → 3.0.7__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.
- souleyez/__init__.py +1 -1
- souleyez/ai/__init__.py +7 -7
- souleyez/ai/action_mapper.py +3 -2
- souleyez/ai/chain_advisor.py +2 -1
- souleyez/ai/claude_provider.py +2 -2
- souleyez/ai/context_builder.py +4 -2
- souleyez/ai/executor.py +9 -6
- souleyez/ai/feedback_handler.py +4 -2
- souleyez/ai/llm_provider.py +2 -2
- souleyez/ai/ollama_provider.py +2 -2
- souleyez/ai/ollama_service.py +10 -26
- souleyez/ai/path_scorer.py +2 -1
- souleyez/ai/recommender.py +6 -4
- souleyez/ai/report_context.py +2 -2
- souleyez/ai/report_service.py +5 -5
- souleyez/ai/result_parser.py +3 -2
- souleyez/ai/safety.py +5 -2
- souleyez/auth/__init__.py +6 -6
- souleyez/auth/audit.py +2 -2
- souleyez/auth/engagement_access.py +5 -7
- souleyez/auth/permissions.py +1 -1
- souleyez/auth/session_manager.py +5 -5
- souleyez/auth/user_manager.py +4 -5
- souleyez/commands/audit.py +6 -5
- souleyez/commands/auth.py +6 -5
- souleyez/commands/deliverables.py +2 -3
- souleyez/commands/engagement.py +3 -3
- souleyez/commands/license.py +3 -2
- souleyez/commands/screenshots.py +5 -4
- souleyez/commands/user.py +10 -8
- souleyez/config.py +4 -2
- souleyez/core/credential_tester.py +4 -2
- souleyez/core/cve_mappings.py +2 -1
- souleyez/core/cve_matcher.py +2 -1
- souleyez/core/msf_auto_mapper.py +2 -0
- souleyez/core/msf_chain_engine.py +3 -1
- souleyez/core/msf_database.py +7 -13
- souleyez/core/msf_integration.py +2 -2
- souleyez/core/msf_rpc_client.py +3 -2
- souleyez/core/msf_rpc_manager.py +4 -4
- souleyez/core/msf_sync_manager.py +7 -7
- souleyez/core/network_utils.py +1 -1
- souleyez/core/parser_handler.py +2 -1
- souleyez/core/pending_chains.py +4 -3
- souleyez/core/templates.py +5 -2
- souleyez/core/tool_chaining.py +297 -230
- souleyez/core/version_utils.py +1 -0
- souleyez/core/vuln_correlation.py +3 -2
- souleyez/core/web_utils.py +2 -1
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +1 -1
- souleyez/detection/mitre_mappings.py +1 -2
- souleyez/detection/validator.py +5 -4
- souleyez/devtools.py +4 -2
- souleyez/docs/README.md +2 -2
- souleyez/engine/background.py +168 -7
- souleyez/engine/base.py +2 -1
- souleyez/engine/loader.py +4 -2
- souleyez/engine/log_sanitizer.py +1 -0
- souleyez/engine/manager.py +3 -1
- souleyez/engine/result_handler.py +50 -67
- souleyez/engine/worker_manager.py +6 -4
- souleyez/export/evidence_bundle.py +1 -0
- souleyez/handlers/base.py +1 -0
- souleyez/handlers/bash_handler.py +1 -0
- souleyez/handlers/bloodhound_handler.py +1 -0
- souleyez/handlers/certipy_handler.py +1 -0
- souleyez/handlers/crackmapexec_handler.py +2 -20
- souleyez/handlers/dnsrecon_handler.py +2 -1
- souleyez/handlers/enum4linux_handler.py +65 -37
- souleyez/handlers/evil_winrm_handler.py +1 -0
- souleyez/handlers/ffuf_handler.py +3 -1
- souleyez/handlers/gobuster_handler.py +7 -6
- souleyez/handlers/gpp_extract_handler.py +1 -0
- souleyez/handlers/hashcat_handler.py +1 -0
- souleyez/handlers/hydra_handler.py +5 -1
- souleyez/handlers/impacket_getuserspns_handler.py +1 -0
- souleyez/handlers/impacket_psexec_handler.py +1 -0
- souleyez/handlers/impacket_secretsdump_handler.py +1 -0
- souleyez/handlers/john_handler.py +1 -0
- souleyez/handlers/katana_handler.py +39 -2
- souleyez/handlers/kerbrute_handler.py +1 -0
- souleyez/handlers/ldapsearch_handler.py +90 -17
- souleyez/handlers/lfi_extract_handler.py +1 -0
- souleyez/handlers/msf_auxiliary_handler.py +2 -0
- souleyez/handlers/msf_exploit_handler.py +1 -0
- souleyez/handlers/nikto_handler.py +2 -1
- souleyez/handlers/nmap_handler.py +2 -1
- souleyez/handlers/nuclei_handler.py +2 -1
- souleyez/handlers/nxc_handler.py +50 -19
- souleyez/handlers/rdp_sec_check_handler.py +1 -0
- souleyez/handlers/registry.py +1 -0
- souleyez/handlers/responder_handler.py +1 -0
- souleyez/handlers/service_explorer_handler.py +2 -1
- souleyez/handlers/smbclient_handler.py +1 -0
- souleyez/handlers/smbmap_handler.py +3 -2
- souleyez/handlers/sqlmap_handler.py +6 -4
- souleyez/handlers/theharvester_handler.py +2 -1
- souleyez/handlers/web_login_test_handler.py +1 -0
- souleyez/handlers/whois_handler.py +3 -2
- souleyez/handlers/wpscan_handler.py +2 -1
- souleyez/history.py +4 -3
- souleyez/importers/msf_importer.py +5 -3
- souleyez/importers/smart_importer.py +6 -4
- souleyez/integrations/siem/__init__.py +6 -6
- souleyez/integrations/siem/base.py +1 -1
- souleyez/integrations/siem/elastic.py +3 -3
- souleyez/integrations/siem/factory.py +1 -2
- souleyez/integrations/siem/googlesecops.py +4 -4
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +1 -1
- souleyez/integrations/siem/sentinel.py +3 -3
- souleyez/integrations/siem/splunk.py +3 -3
- souleyez/integrations/siem/wazuh.py +4 -4
- souleyez/integrations/wazuh/__init__.py +1 -1
- souleyez/integrations/wazuh/client.py +3 -2
- souleyez/integrations/wazuh/config.py +3 -2
- souleyez/integrations/wazuh/host_mapper.py +3 -1
- souleyez/integrations/wazuh/sync.py +4 -1
- souleyez/intelligence/__init__.py +1 -1
- souleyez/intelligence/correlation_analyzer.py +6 -5
- souleyez/intelligence/exploit_knowledge.py +4 -4
- souleyez/intelligence/exploit_suggestions.py +4 -3
- souleyez/intelligence/gap_analyzer.py +5 -3
- souleyez/intelligence/gap_detector.py +2 -0
- souleyez/intelligence/sensitive_tables.py +1 -1
- souleyez/intelligence/service_parser.py +1 -0
- souleyez/intelligence/surface_analyzer.py +9 -9
- souleyez/intelligence/target_parser.py +1 -0
- souleyez/licensing/__init__.py +3 -3
- souleyez/main.py +25 -18
- souleyez/migrations/fix_job_counter.py +2 -1
- souleyez/parsers/bloodhound_parser.py +1 -0
- souleyez/parsers/crackmapexec_parser.py +2 -1
- souleyez/parsers/dalfox_parser.py +3 -2
- souleyez/parsers/dnsrecon_parser.py +2 -1
- souleyez/parsers/enum4linux_parser.py +2 -1
- souleyez/parsers/ffuf_parser.py +2 -1
- souleyez/parsers/gobuster_parser.py +2 -1
- souleyez/parsers/hashcat_parser.py +3 -2
- souleyez/parsers/http_fingerprint_parser.py +2 -1
- souleyez/parsers/hydra_parser.py +2 -1
- souleyez/parsers/impacket_parser.py +2 -1
- souleyez/parsers/john_parser.py +4 -3
- souleyez/parsers/katana_parser.py +134 -2
- souleyez/parsers/msf_parser.py +2 -1
- souleyez/parsers/nikto_parser.py +2 -1
- souleyez/parsers/nmap_parser.py +14 -3
- souleyez/parsers/nuclei_parser.py +3 -2
- souleyez/parsers/responder_parser.py +1 -0
- souleyez/parsers/searchsploit_parser.py +3 -2
- souleyez/parsers/service_explorer_parser.py +1 -0
- souleyez/parsers/smbmap_parser.py +2 -1
- souleyez/parsers/sqlmap_parser.py +36 -2
- souleyez/parsers/theharvester_parser.py +2 -1
- souleyez/parsers/whois_parser.py +2 -1
- souleyez/parsers/wpscan_parser.py +3 -2
- souleyez/plugins/afp.py +3 -1
- souleyez/plugins/afp_brute.py +3 -1
- souleyez/plugins/ard.py +3 -1
- souleyez/plugins/bloodhound.py +3 -2
- souleyez/plugins/certipy.py +1 -0
- souleyez/plugins/crackmapexec.py +11 -7
- souleyez/plugins/dalfox.py +5 -2
- souleyez/plugins/dns_hijack.py +3 -1
- souleyez/plugins/dnsrecon.py +3 -1
- souleyez/plugins/enum4linux.py +3 -1
- souleyez/plugins/evil_winrm.py +1 -0
- souleyez/plugins/ffuf.py +3 -1
- souleyez/plugins/firmware_extract.py +3 -2
- souleyez/plugins/gobuster.py +6 -3
- souleyez/plugins/gpp_extract.py +1 -0
- souleyez/plugins/hashcat.py +2 -1
- souleyez/plugins/http_fingerprint.py +149 -40
- souleyez/plugins/hydra.py +5 -3
- souleyez/plugins/impacket_common.py +40 -0
- souleyez/plugins/impacket_getnpusers.py +19 -2
- souleyez/plugins/impacket_getuserspns.py +158 -0
- souleyez/plugins/impacket_psexec.py +19 -2
- souleyez/plugins/impacket_secretsdump.py +19 -2
- souleyez/plugins/impacket_smbclient.py +19 -2
- souleyez/plugins/john.py +2 -1
- souleyez/plugins/katana.py +48 -6
- souleyez/plugins/kerbrute.py +1 -0
- souleyez/plugins/lfi_extract.py +1 -0
- souleyez/plugins/macos_ssh.py +3 -1
- souleyez/plugins/mdns.py +3 -1
- souleyez/plugins/msf_auxiliary.py +3 -2
- souleyez/plugins/msf_exploit.py +6 -5
- souleyez/plugins/nikto.py +5 -2
- souleyez/plugins/nmap.py +6 -4
- souleyez/plugins/nuclei.py +3 -1
- souleyez/plugins/nxc.py +1 -0
- souleyez/plugins/plugin_base.py +3 -2
- souleyez/plugins/plugin_template.py +3 -2
- souleyez/plugins/rdp_sec_check.py +1 -0
- souleyez/plugins/responder.py +2 -1
- souleyez/plugins/router_http_brute.py +3 -1
- souleyez/plugins/router_ssh_brute.py +3 -1
- souleyez/plugins/router_telnet_brute.py +3 -1
- souleyez/plugins/routersploit.py +5 -3
- souleyez/plugins/routersploit_exploit.py +5 -3
- souleyez/plugins/searchsploit.py +1 -0
- souleyez/plugins/service_explorer.py +2 -1
- souleyez/plugins/smbmap.py +3 -1
- souleyez/plugins/smbpasswd.py +1 -0
- souleyez/plugins/sqlmap.py +3 -1
- souleyez/plugins/theharvester.py +3 -1
- souleyez/plugins/tr069.py +3 -1
- souleyez/plugins/upnp.py +3 -1
- souleyez/plugins/upnp_abuse.py +4 -2
- souleyez/plugins/vnc_access.py +4 -2
- souleyez/plugins/vnc_brute.py +3 -1
- souleyez/plugins/web_login_test.py +1 -0
- souleyez/plugins/whois.py +3 -1
- souleyez/plugins/wpscan.py +49 -1
- souleyez/reporting/attack_chain.py +2 -1
- souleyez/reporting/charts.py +1 -0
- souleyez/reporting/compliance_mappings.py +1 -0
- souleyez/reporting/detection_report.py +10 -10
- souleyez/reporting/formatters.py +7 -12
- souleyez/reporting/generator.py +34 -46
- souleyez/reporting/metrics.py +2 -1
- souleyez/scanner.py +6 -3
- souleyez/security/__init__.py +7 -5
- souleyez/security/scope_validator.py +5 -4
- souleyez/security/validation.py +14 -0
- souleyez/security.py +5 -2
- souleyez/storage/credentials.py +14 -19
- souleyez/storage/crypto.py +7 -4
- souleyez/storage/database.py +6 -6
- souleyez/storage/db.py +8 -8
- souleyez/storage/deliverable_evidence.py +2 -1
- souleyez/storage/deliverable_exporter.py +3 -2
- souleyez/storage/deliverable_templates.py +2 -1
- souleyez/storage/deliverables.py +2 -1
- souleyez/storage/engagements.py +6 -4
- souleyez/storage/evidence.py +5 -4
- souleyez/storage/execution_log.py +4 -2
- souleyez/storage/exploit_attempts.py +3 -2
- souleyez/storage/exploits.py +3 -1
- souleyez/storage/findings.py +3 -1
- souleyez/storage/hosts.py +5 -2
- souleyez/storage/migrate_to_engagements.py +14 -24
- souleyez/storage/migrations/_001_add_credential_enhancements.py +12 -21
- souleyez/storage/migrations/_003_add_execution_log.py +8 -13
- souleyez/storage/migrations/_005_screenshots.py +2 -4
- souleyez/storage/migrations/_006_deliverables.py +2 -4
- souleyez/storage/migrations/_007_deliverable_templates.py +4 -8
- souleyez/storage/migrations/_008_add_nuclei_table.py +2 -4
- souleyez/storage/migrations/_010_evidence_linking.py +6 -12
- souleyez/storage/migrations/_012_team_collaboration.py +12 -24
- souleyez/storage/migrations/_013_add_host_tags.py +2 -4
- souleyez/storage/migrations/_014_exploit_attempts.py +10 -20
- souleyez/storage/migrations/_015_add_mac_os_fields.py +4 -8
- souleyez/storage/migrations/_016_add_domain_field.py +2 -4
- souleyez/storage/migrations/_017_msf_sessions.py +8 -16
- souleyez/storage/migrations/_018_add_osint_target.py +4 -8
- souleyez/storage/migrations/_019_add_engagement_type.py +4 -8
- souleyez/storage/migrations/_020_add_rbac.py +9 -17
- souleyez/storage/migrations/_021_wazuh_integration.py +4 -8
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +2 -4
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +4 -8
- souleyez/storage/migrations/_026_add_engagement_scope.py +4 -8
- souleyez/storage/migrations/_027_multi_siem_persistence.py +8 -16
- souleyez/storage/migrations/__init__.py +1 -4
- souleyez/storage/migrations/migration_manager.py +6 -9
- souleyez/storage/msf_sessions.py +1 -1
- souleyez/storage/osint.py +3 -1
- souleyez/storage/recommendation_engine.py +3 -2
- souleyez/storage/screenshots.py +2 -1
- souleyez/storage/smb_shares.py +3 -1
- souleyez/storage/sqlmap_data.py +6 -4
- souleyez/storage/team_collaboration.py +3 -2
- souleyez/storage/timeline_tracker.py +2 -1
- souleyez/storage/wazuh_vulns.py +3 -1
- souleyez/storage/web_paths.py +3 -1
- souleyez/testing/credential_tester.py +2 -0
- souleyez/ui/__init__.py +2 -1
- souleyez/ui/ai_quotes.py +1 -1
- souleyez/ui/attack_surface.py +50 -28
- souleyez/ui/chain_rules_view.py +6 -3
- souleyez/ui/correlation_view.py +3 -2
- souleyez/ui/dashboard.py +85 -139
- souleyez/ui/deliverables_view.py +1 -1
- souleyez/ui/design_system.py +5 -3
- souleyez/ui/errors.py +3 -1
- souleyez/ui/evidence_linking_view.py +2 -1
- souleyez/ui/evidence_vault.py +11 -6
- souleyez/ui/exploit_suggestions_view.py +11 -7
- souleyez/ui/export_view.py +3 -1
- souleyez/ui/gap_analysis_view.py +6 -3
- souleyez/ui/help_system.py +4 -1
- souleyez/ui/intelligence_view.py +7 -3
- souleyez/ui/interactive.py +1512 -584
- souleyez/ui/interactive_selector.py +3 -2
- souleyez/ui/log_formatter.py +1 -0
- souleyez/ui/menu_components.py +3 -1
- souleyez/ui/msf_auxiliary_menu.py +4 -1
- souleyez/ui/pending_chains_view.py +15 -12
- souleyez/ui/progress_indicators.py +5 -2
- souleyez/ui/recommendations_view.py +4 -2
- souleyez/ui/rule_builder.py +4 -1
- souleyez/ui/setup_wizard.py +10 -8
- souleyez/ui/shortcuts.py +1 -1
- souleyez/ui/splunk_gap_analysis_view.py +7 -4
- souleyez/ui/splunk_vulns_view.py +4 -1
- souleyez/ui/team_dashboard.py +7 -5
- souleyez/ui/template_selector.py +2 -1
- souleyez/ui/terminal.py +3 -2
- souleyez/ui/timeline_view.py +2 -1
- souleyez/ui/tool_setup.py +92 -31
- souleyez/ui/tutorial.py +7 -4
- souleyez/ui/tutorial_state.py +3 -2
- souleyez/ui/wazuh_vulns_view.py +5 -2
- souleyez/ui/wordlist_browser.py +4 -3
- souleyez/ui.py +13 -7
- souleyez/utils/tool_checker.py +61 -12
- souleyez/utils.py +4 -4
- souleyez/wordlists.py +1 -0
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/METADATA +2 -2
- souleyez-3.0.7.dist-info/RECORD +445 -0
- souleyez-2.43.34.dist-info/RECORD +0 -443
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/WHEEL +0 -0
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/top_level.txt +0 -0
|
@@ -4,6 +4,7 @@ Hydra handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for Hydra brute-force jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -58,8 +59,8 @@ class HydraHandler(BaseToolHandler):
|
|
|
58
59
|
Extracts credentials and usernames from the output.
|
|
59
60
|
"""
|
|
60
61
|
try:
|
|
61
|
-
from souleyez.parsers.hydra_parser import parse_hydra_output
|
|
62
62
|
from souleyez.engine.result_handler import detect_tool_error
|
|
63
|
+
from souleyez.parsers.hydra_parser import parse_hydra_output
|
|
63
64
|
|
|
64
65
|
# Import managers if not provided
|
|
65
66
|
if host_manager is None:
|
|
@@ -261,6 +262,9 @@ class HydraHandler(BaseToolHandler):
|
|
|
261
262
|
"port": parsed.get("port"),
|
|
262
263
|
"credentials_found": len(parsed.get("credentials", [])),
|
|
263
264
|
"credentials_added": creds_added,
|
|
265
|
+
"credentials": parsed.get(
|
|
266
|
+
"credentials", []
|
|
267
|
+
), # Include actual creds for smart chains
|
|
264
268
|
"usernames_found": len(parsed.get("usernames", [])),
|
|
265
269
|
"usernames": parsed.get("usernames", []),
|
|
266
270
|
"usernames_added": usernames_added,
|
|
@@ -4,6 +4,7 @@ Katana handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for katana web crawling jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
from typing import Any, Dict, List, Optional
|
|
@@ -49,11 +50,11 @@ class KatanaHandler(BaseToolHandler):
|
|
|
49
50
|
Extracts discovered URLs, parameters, forms, and JS endpoints.
|
|
50
51
|
"""
|
|
51
52
|
try:
|
|
53
|
+
from souleyez.engine.result_handler import detect_tool_error
|
|
52
54
|
from souleyez.parsers.katana_parser import (
|
|
53
|
-
parse_katana_output,
|
|
54
55
|
extract_injectable_urls,
|
|
56
|
+
parse_katana_output,
|
|
55
57
|
)
|
|
56
|
-
from souleyez.engine.result_handler import detect_tool_error
|
|
57
58
|
|
|
58
59
|
# Import managers if not provided
|
|
59
60
|
if host_manager is None:
|
|
@@ -134,6 +135,42 @@ class KatanaHandler(BaseToolHandler):
|
|
|
134
135
|
|
|
135
136
|
lfi_urls = extract_lfi_urls(parsed)
|
|
136
137
|
|
|
138
|
+
# ARM64/headless workaround: If we have JS files but few parameterized URLs,
|
|
139
|
+
# extract endpoints directly from JavaScript source code
|
|
140
|
+
js_files = [u for u in parsed.get("urls", []) if u.endswith(".js")]
|
|
141
|
+
urls_with_params_list = parsed.get("urls_with_params", [])
|
|
142
|
+
sqli_candidates = parsed.get("sqli_candidate_urls", [])
|
|
143
|
+
|
|
144
|
+
if js_files and len(urls_with_params_list) < 10:
|
|
145
|
+
try:
|
|
146
|
+
from souleyez.parsers.katana_parser import (
|
|
147
|
+
fetch_and_extract_js_endpoints,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
logger.info(
|
|
151
|
+
f"Extracting endpoints from {len(js_files)} JavaScript files..."
|
|
152
|
+
)
|
|
153
|
+
js_endpoints = fetch_and_extract_js_endpoints(target, js_files)
|
|
154
|
+
|
|
155
|
+
if js_endpoints:
|
|
156
|
+
logger.info(
|
|
157
|
+
f"Found {len(js_endpoints)} additional endpoints from JavaScript"
|
|
158
|
+
)
|
|
159
|
+
# Add to parsed results
|
|
160
|
+
for ep in js_endpoints:
|
|
161
|
+
if ep not in urls_with_params_list:
|
|
162
|
+
urls_with_params_list.append(ep)
|
|
163
|
+
if ep not in sqli_candidates:
|
|
164
|
+
sqli_candidates.append(ep)
|
|
165
|
+
if ep not in injectable_urls:
|
|
166
|
+
injectable_urls.append(ep)
|
|
167
|
+
|
|
168
|
+
# Update parsed dict for display
|
|
169
|
+
parsed["urls_with_params"] = urls_with_params_list
|
|
170
|
+
parsed["sqli_candidate_urls"] = sqli_candidates
|
|
171
|
+
except Exception as e:
|
|
172
|
+
logger.warning(f"JavaScript endpoint extraction failed: {e}")
|
|
173
|
+
|
|
137
174
|
# Determine status
|
|
138
175
|
urls_list = parsed.get("urls", [])
|
|
139
176
|
urls_with_params_list = parsed.get("urls_with_params", [])
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Handler for ldapsearch LDAP enumeration tool.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
import logging
|
|
6
7
|
import os
|
|
7
8
|
import re
|
|
@@ -177,8 +178,8 @@ class LdapsearchHandler(BaseToolHandler):
|
|
|
177
178
|
f"{user.get('sAMAccountName')} - check description field"
|
|
178
179
|
)
|
|
179
180
|
|
|
180
|
-
# Store credentials if found
|
|
181
|
-
if credentials_found and credentials_manager:
|
|
181
|
+
# Store credentials if found AND store enumerated users
|
|
182
|
+
if (credentials_found or usernames) and credentials_manager:
|
|
182
183
|
if host_manager is None:
|
|
183
184
|
from souleyez.storage.hosts import HostManager
|
|
184
185
|
|
|
@@ -186,6 +187,7 @@ class LdapsearchHandler(BaseToolHandler):
|
|
|
186
187
|
|
|
187
188
|
host = host_manager.get_host_by_ip(engagement_id, target)
|
|
188
189
|
if host:
|
|
190
|
+
# Store passwords found in descriptions
|
|
189
191
|
for cred in credentials_found:
|
|
190
192
|
credentials_manager.add_credential(
|
|
191
193
|
engagement_id=engagement_id,
|
|
@@ -199,6 +201,31 @@ class LdapsearchHandler(BaseToolHandler):
|
|
|
199
201
|
notes="Found in LDAP user description field",
|
|
200
202
|
)
|
|
201
203
|
|
|
204
|
+
# Store enumerated usernames (without passwords)
|
|
205
|
+
usernames_stored = 0
|
|
206
|
+
for username in usernames:
|
|
207
|
+
# Skip if already stored with a password
|
|
208
|
+
already_has_cred = any(
|
|
209
|
+
c["username"] == username for c in credentials_found
|
|
210
|
+
)
|
|
211
|
+
if not already_has_cred:
|
|
212
|
+
credentials_manager.add_credential(
|
|
213
|
+
engagement_id=engagement_id,
|
|
214
|
+
host_id=host["id"],
|
|
215
|
+
username=username,
|
|
216
|
+
password="",
|
|
217
|
+
service="ldap",
|
|
218
|
+
credential_type="ldap_user",
|
|
219
|
+
tool="ldapsearch",
|
|
220
|
+
status="enumerated",
|
|
221
|
+
notes="Enumerated via LDAP",
|
|
222
|
+
)
|
|
223
|
+
usernames_stored += 1
|
|
224
|
+
if usernames_stored > 0:
|
|
225
|
+
logger.info(
|
|
226
|
+
f"Stored {usernames_stored} enumerated LDAP usernames"
|
|
227
|
+
)
|
|
228
|
+
|
|
202
229
|
logger.info(
|
|
203
230
|
f"ldapsearch parse complete: {len(naming_contexts)} naming contexts, "
|
|
204
231
|
f"{len(domains)} domains, {len(users)} users, {len(credentials_found)} creds, base_dn={base_dn}"
|
|
@@ -420,8 +447,11 @@ class LdapsearchHandler(BaseToolHandler):
|
|
|
420
447
|
|
|
421
448
|
# New entry starts with "dn:"
|
|
422
449
|
if line.startswith("dn:"):
|
|
450
|
+
# Save previous entry if it's not explicitly a group
|
|
451
|
+
# Default to including (is_group=False) if no objectClass info
|
|
423
452
|
if current_user and current_user.get("sAMAccountName"):
|
|
424
|
-
|
|
453
|
+
if not current_user.get("is_group", False):
|
|
454
|
+
users.append(current_user)
|
|
425
455
|
current_user = {}
|
|
426
456
|
# Extract OU from DN
|
|
427
457
|
ou_match = re.search(r"OU=([^,]+)", line, re.IGNORECASE)
|
|
@@ -448,12 +478,43 @@ class LdapsearchHandler(BaseToolHandler):
|
|
|
448
478
|
"key ",
|
|
449
479
|
"dns",
|
|
450
480
|
"ras ",
|
|
481
|
+
"cloneable ",
|
|
451
482
|
)
|
|
452
483
|
):
|
|
453
484
|
current_user["cn_username"] = cn_name.replace(" ", ".")
|
|
454
485
|
|
|
486
|
+
elif line.startswith("objectClass:"):
|
|
487
|
+
obj_class = line.split(":", 1)[1].strip().lower()
|
|
488
|
+
# Mark as group if objectClass is group (blacklist approach)
|
|
489
|
+
if obj_class == "group":
|
|
490
|
+
current_user["is_group"] = True
|
|
491
|
+
|
|
455
492
|
elif line.startswith("sAMAccountName:"):
|
|
456
|
-
|
|
493
|
+
sam = line.split(":", 1)[1].strip()
|
|
494
|
+
current_user["sAMAccountName"] = sam
|
|
495
|
+
# Filter out obvious group names by sAMAccountName pattern
|
|
496
|
+
sam_lower = sam.lower()
|
|
497
|
+
if sam_lower in (
|
|
498
|
+
"guest",
|
|
499
|
+
"domain users",
|
|
500
|
+
"domain computers",
|
|
501
|
+
"domain guests",
|
|
502
|
+
"domain admins",
|
|
503
|
+
"enterprise admins",
|
|
504
|
+
"schema admins",
|
|
505
|
+
"cert publishers",
|
|
506
|
+
"group policy creator owners",
|
|
507
|
+
"ras and ias servers",
|
|
508
|
+
"allowed rodc password replication group",
|
|
509
|
+
"denied rodc password replication group",
|
|
510
|
+
"read-only domain controllers",
|
|
511
|
+
"enterprise read-only domain controllers",
|
|
512
|
+
"cloneable domain controllers",
|
|
513
|
+
"protected users",
|
|
514
|
+
"dnsadmins",
|
|
515
|
+
"dnsupdateproxy",
|
|
516
|
+
):
|
|
517
|
+
current_user["is_group"] = True
|
|
457
518
|
|
|
458
519
|
elif line.startswith("description:"):
|
|
459
520
|
current_user["description"] = line.split(":", 1)[1].strip()
|
|
@@ -466,9 +527,10 @@ class LdapsearchHandler(BaseToolHandler):
|
|
|
466
527
|
if cn_match:
|
|
467
528
|
current_user["memberOf"].append(cn_match.group(1))
|
|
468
529
|
|
|
469
|
-
# Don't forget last user
|
|
530
|
+
# Don't forget last user - only if it's not a group
|
|
470
531
|
if current_user and current_user.get("sAMAccountName"):
|
|
471
|
-
|
|
532
|
+
if not current_user.get("is_group", False):
|
|
533
|
+
users.append(current_user)
|
|
472
534
|
|
|
473
535
|
# Second pass: add users found only via CN (no sAMAccountName returned)
|
|
474
536
|
# This catches users from broader queries like (objectClass=*)
|
|
@@ -476,9 +538,11 @@ class LdapsearchHandler(BaseToolHandler):
|
|
|
476
538
|
for line in log_content.split("\n"):
|
|
477
539
|
line = line.strip()
|
|
478
540
|
if line.startswith("dn:"):
|
|
479
|
-
if
|
|
480
|
-
"
|
|
481
|
-
|
|
541
|
+
if (
|
|
542
|
+
current_user.get("cn_username")
|
|
543
|
+
and not current_user.get("sAMAccountName")
|
|
544
|
+
and not current_user.get("is_group", False)
|
|
545
|
+
): # Default to user if no objectClass
|
|
482
546
|
# Check if we already have this user
|
|
483
547
|
existing = [
|
|
484
548
|
u
|
|
@@ -507,24 +571,33 @@ class LdapsearchHandler(BaseToolHandler):
|
|
|
507
571
|
"key ",
|
|
508
572
|
"dns",
|
|
509
573
|
"ras ",
|
|
574
|
+
"cloneable ",
|
|
510
575
|
)
|
|
511
576
|
):
|
|
512
577
|
current_user["cn_username"] = cn_name.replace(" ", ".")
|
|
513
578
|
if ou_match:
|
|
514
579
|
current_user["ou"] = ou_match.group(1)
|
|
580
|
+
elif line.startswith("objectClass:"):
|
|
581
|
+
obj_class = line.split(":", 1)[1].strip().lower()
|
|
582
|
+
# Blacklist groups - mark as group if objectClass is group
|
|
583
|
+
if obj_class == "group":
|
|
584
|
+
current_user["is_group"] = True
|
|
515
585
|
elif line.startswith("sAMAccountName:"):
|
|
516
586
|
current_user["sAMAccountName"] = line.split(":", 1)[1].strip()
|
|
517
587
|
|
|
518
588
|
# Last entry from second pass
|
|
519
589
|
if current_user.get("cn_username") and not current_user.get("sAMAccountName"):
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
590
|
+
if not current_user.get(
|
|
591
|
+
"is_group", False
|
|
592
|
+
): # Default to user if no objectClass
|
|
593
|
+
existing = [
|
|
594
|
+
u
|
|
595
|
+
for u in users
|
|
596
|
+
if u.get("sAMAccountName") == current_user.get("cn_username")
|
|
597
|
+
]
|
|
598
|
+
if not existing:
|
|
599
|
+
current_user["sAMAccountName"] = current_user["cn_username"]
|
|
600
|
+
users.append(current_user)
|
|
528
601
|
|
|
529
602
|
return users
|
|
530
603
|
|
|
@@ -4,6 +4,7 @@ Metasploit auxiliary handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for msf_auxiliary jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -165,6 +166,7 @@ class MsfAuxiliaryHandler(BaseToolHandler):
|
|
|
165
166
|
credential_summaries.append(
|
|
166
167
|
{
|
|
167
168
|
"username": cred.get("username", ""),
|
|
169
|
+
"password": cred.get("password", ""),
|
|
168
170
|
"service": cred.get("service", "unknown"),
|
|
169
171
|
"port": cred.get("port"),
|
|
170
172
|
}
|
|
@@ -4,6 +4,7 @@ Nikto handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for nikto web scanner jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -45,8 +46,8 @@ class NiktoHandler(BaseToolHandler):
|
|
|
45
46
|
Extracts web server issues and stores them as findings.
|
|
46
47
|
"""
|
|
47
48
|
try:
|
|
48
|
-
from souleyez.parsers.nikto_parser import parse_nikto_output
|
|
49
49
|
from souleyez.engine.result_handler import detect_tool_error
|
|
50
|
+
from souleyez.parsers.nikto_parser import parse_nikto_output
|
|
50
51
|
|
|
51
52
|
# Import managers if not provided
|
|
52
53
|
if host_manager is None:
|
|
@@ -4,6 +4,7 @@ Nmap handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for nmap and ARD (which uses nmap) jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -70,9 +71,9 @@ class NmapHandler(BaseToolHandler):
|
|
|
70
71
|
Imports hosts/services into database and creates findings for CVEs.
|
|
71
72
|
"""
|
|
72
73
|
try:
|
|
73
|
-
from souleyez.parsers.nmap_parser import parse_nmap_log
|
|
74
74
|
from souleyez.core.cve_matcher import CVEMatcher
|
|
75
75
|
from souleyez.engine.result_handler import detect_tool_error
|
|
76
|
+
from souleyez.parsers.nmap_parser import parse_nmap_log
|
|
76
77
|
|
|
77
78
|
# Import managers if not provided
|
|
78
79
|
if host_manager is None:
|
|
@@ -4,6 +4,7 @@ Nuclei handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for nuclei vulnerability scanning jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -48,8 +49,8 @@ class NucleiHandler(BaseToolHandler):
|
|
|
48
49
|
Extracts vulnerabilities and stores them as findings.
|
|
49
50
|
"""
|
|
50
51
|
try:
|
|
51
|
-
from souleyez.parsers.nuclei_parser import parse_nuclei
|
|
52
52
|
from souleyez.engine.result_handler import detect_tool_error
|
|
53
|
+
from souleyez.parsers.nuclei_parser import parse_nuclei
|
|
53
54
|
|
|
54
55
|
# Import managers if not provided
|
|
55
56
|
if host_manager is None:
|
souleyez/handlers/nxc_handler.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Handler for NetExec (nxc) - successor to CrackMapExec.
|
|
4
4
|
Parses shares, credentials, and authentication results.
|
|
5
5
|
"""
|
|
6
|
+
|
|
6
7
|
import logging
|
|
7
8
|
import os
|
|
8
9
|
import re
|
|
@@ -77,10 +78,51 @@ class NxcHandler(BaseToolHandler):
|
|
|
77
78
|
hostname = banner_match.group(1)
|
|
78
79
|
domain = banner_match.group(2)
|
|
79
80
|
|
|
80
|
-
# Check for Pwn3d
|
|
81
|
+
# Check for Pwn3d (SMB admin access)
|
|
81
82
|
if re.search(self.PWNED_PATTERN, log_content):
|
|
82
83
|
is_pwned = True
|
|
83
84
|
|
|
85
|
+
# Check for SSH Shell access (Linux)
|
|
86
|
+
# Format: [+] leia_organa:help_me_obiwan Linux - Shell access!
|
|
87
|
+
has_shell_access = False
|
|
88
|
+
if "Shell access!" in log_content:
|
|
89
|
+
has_shell_access = True
|
|
90
|
+
# Parse SSH credentials
|
|
91
|
+
ssh_cred_pattern = r"\[\+\]\s+([^:\s]+):(\S+)\s+.*Shell access!"
|
|
92
|
+
for match in re.finditer(ssh_cred_pattern, log_content):
|
|
93
|
+
username = match.group(1)
|
|
94
|
+
password = match.group(2)
|
|
95
|
+
cred = {
|
|
96
|
+
"username": username,
|
|
97
|
+
"password": password,
|
|
98
|
+
"domain": "",
|
|
99
|
+
"service": "ssh",
|
|
100
|
+
"status": "valid",
|
|
101
|
+
}
|
|
102
|
+
credentials.append(cred)
|
|
103
|
+
|
|
104
|
+
# Store in database
|
|
105
|
+
if credentials_manager and host_manager:
|
|
106
|
+
try:
|
|
107
|
+
host = host_manager.get_host_by_ip(engagement_id, target)
|
|
108
|
+
if host:
|
|
109
|
+
credentials_manager.add_credential(
|
|
110
|
+
engagement_id=engagement_id,
|
|
111
|
+
host_id=host["id"],
|
|
112
|
+
username=username,
|
|
113
|
+
password=password,
|
|
114
|
+
service="ssh",
|
|
115
|
+
port=22,
|
|
116
|
+
credential_type="password",
|
|
117
|
+
tool="nxc",
|
|
118
|
+
status="valid",
|
|
119
|
+
)
|
|
120
|
+
logger.warning(
|
|
121
|
+
f"SSH SHELL ACCESS: {username}:{password} on {target}"
|
|
122
|
+
)
|
|
123
|
+
except Exception as e:
|
|
124
|
+
logger.debug(f"Could not store SSH credential: {e}")
|
|
125
|
+
|
|
84
126
|
# Parse valid credentials
|
|
85
127
|
# Format: [+] baby2.vl\Carl.Moore:Carl.Moore
|
|
86
128
|
for match in re.finditer(self.VALID_CRED_PATTERN, log_content):
|
|
@@ -218,30 +260,16 @@ class NxcHandler(BaseToolHandler):
|
|
|
218
260
|
if "WRITE" in perms:
|
|
219
261
|
writable_shares.append(share)
|
|
220
262
|
|
|
221
|
-
# Determine status
|
|
222
|
-
#
|
|
223
|
-
transient_errors = [
|
|
224
|
-
"NetBIOSTimeout",
|
|
225
|
-
"connection timed out",
|
|
226
|
-
"Connection reset",
|
|
227
|
-
]
|
|
228
|
-
has_transient_error = any(
|
|
229
|
-
err.lower() in log_content.lower() for err in transient_errors
|
|
230
|
-
)
|
|
231
|
-
|
|
263
|
+
# Determine status based on results found
|
|
264
|
+
# Retry logic is handled by background.py before parsing
|
|
232
265
|
if credentials:
|
|
233
266
|
status = STATUS_DONE
|
|
267
|
+
elif has_shell_access:
|
|
268
|
+
status = STATUS_DONE # SSH shell access without parsed creds
|
|
234
269
|
elif expired_credentials:
|
|
235
270
|
status = STATUS_WARNING # Expired creds need attention
|
|
236
271
|
elif shares:
|
|
237
272
|
status = STATUS_DONE
|
|
238
|
-
elif has_transient_error:
|
|
239
|
-
status = STATUS_WARNING # Transient error - may be retried
|
|
240
|
-
elif (
|
|
241
|
-
"STATUS_LOGON_FAILURE" in log_content
|
|
242
|
-
or "STATUS_ACCESS_DENIED" in log_content
|
|
243
|
-
):
|
|
244
|
-
status = STATUS_NO_RESULTS
|
|
245
273
|
else:
|
|
246
274
|
status = STATUS_NO_RESULTS
|
|
247
275
|
|
|
@@ -255,6 +283,8 @@ class NxcHandler(BaseToolHandler):
|
|
|
255
283
|
)
|
|
256
284
|
if is_pwned:
|
|
257
285
|
summary_parts.append("PWNED!")
|
|
286
|
+
if has_shell_access:
|
|
287
|
+
summary_parts.append("SHELL ACCESS!")
|
|
258
288
|
if shares:
|
|
259
289
|
summary_parts.append(
|
|
260
290
|
f"{len(shares)} shares ({len(readable_shares)} readable, {len(writable_shares)} writable)"
|
|
@@ -273,6 +303,7 @@ class NxcHandler(BaseToolHandler):
|
|
|
273
303
|
"credentials": credentials,
|
|
274
304
|
"expired_credentials": expired_credentials,
|
|
275
305
|
"is_pwned": is_pwned,
|
|
306
|
+
"has_shell_access": has_shell_access,
|
|
276
307
|
"summary": summary,
|
|
277
308
|
}
|
|
278
309
|
|
souleyez/handlers/registry.py
CHANGED
|
@@ -4,6 +4,7 @@ Service Explorer handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for Service Explorer jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -45,8 +46,8 @@ class ServiceExplorerHandler(BaseToolHandler):
|
|
|
45
46
|
"""
|
|
46
47
|
try:
|
|
47
48
|
from souleyez.parsers.service_explorer_parser import (
|
|
48
|
-
parse_service_explorer_output,
|
|
49
49
|
extract_findings,
|
|
50
|
+
parse_service_explorer_output,
|
|
50
51
|
)
|
|
51
52
|
|
|
52
53
|
# Import managers if not provided
|
|
@@ -4,6 +4,7 @@ SMBMap handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for SMBMap SMB share enumeration jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -44,12 +45,12 @@ class SMBMapHandler(BaseToolHandler):
|
|
|
44
45
|
Extracts SMB shares and stores them along with findings.
|
|
45
46
|
"""
|
|
46
47
|
try:
|
|
48
|
+
from souleyez.engine.result_handler import detect_tool_error
|
|
47
49
|
from souleyez.parsers.smbmap_parser import (
|
|
48
|
-
parse_smbmap_output,
|
|
49
50
|
extract_findings,
|
|
51
|
+
parse_smbmap_output,
|
|
50
52
|
)
|
|
51
53
|
from souleyez.storage.smb_shares import SMBSharesManager
|
|
52
|
-
from souleyez.engine.result_handler import detect_tool_error
|
|
53
54
|
|
|
54
55
|
# Import managers if not provided
|
|
55
56
|
if host_manager is None:
|
|
@@ -4,6 +4,7 @@ SQLMap handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for SQLMap SQL injection scanner jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -45,13 +46,14 @@ class SQLMapHandler(BaseToolHandler):
|
|
|
45
46
|
Extracts SQL injection vulnerabilities, databases, tables, and dumped data.
|
|
46
47
|
"""
|
|
47
48
|
try:
|
|
49
|
+
import socket
|
|
50
|
+
|
|
51
|
+
from souleyez.engine.result_handler import detect_tool_error
|
|
48
52
|
from souleyez.parsers.sqlmap_parser import (
|
|
49
|
-
parse_sqlmap_output,
|
|
50
53
|
get_sqli_stats,
|
|
54
|
+
parse_sqlmap_output,
|
|
51
55
|
)
|
|
52
56
|
from souleyez.storage.sqlmap_data import SQLMapDataManager
|
|
53
|
-
from souleyez.engine.result_handler import detect_tool_error
|
|
54
|
-
import socket
|
|
55
57
|
|
|
56
58
|
# Import managers if not provided
|
|
57
59
|
if host_manager is None:
|
|
@@ -833,8 +835,8 @@ class SQLMapHandler(BaseToolHandler):
|
|
|
833
835
|
"""Display successful SQLMap results."""
|
|
834
836
|
try:
|
|
835
837
|
from souleyez.parsers.sqlmap_parser import (
|
|
836
|
-
parse_sqlmap_output,
|
|
837
838
|
get_sqli_stats,
|
|
839
|
+
parse_sqlmap_output,
|
|
838
840
|
)
|
|
839
841
|
|
|
840
842
|
if not log_path or not os.path.exists(log_path):
|
|
@@ -4,6 +4,7 @@ TheHarvester handler.
|
|
|
4
4
|
|
|
5
5
|
Consolidates parsing and display logic for theHarvester OSINT jobs.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import logging
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -194,8 +195,8 @@ class TheHarvesterHandler(BaseToolHandler):
|
|
|
194
195
|
"""
|
|
195
196
|
try:
|
|
196
197
|
from souleyez.parsers.theharvester_parser import (
|
|
197
|
-
parse_theharvester_output,
|
|
198
198
|
get_osint_stats,
|
|
199
|
+
parse_theharvester_output,
|
|
199
200
|
)
|
|
200
201
|
|
|
201
202
|
# Import managers if not provided
|