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
souleyez/core/version_utils.py
CHANGED
|
@@ -8,9 +8,10 @@ Analyzes findings from multiple tools to:
|
|
|
8
8
|
3. Prioritize findings based on correlation
|
|
9
9
|
4. Suggest exploit paths
|
|
10
10
|
"""
|
|
11
|
-
|
|
12
|
-
from dataclasses import dataclass, field
|
|
11
|
+
|
|
13
12
|
import re
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from typing import Any, Dict, List, Optional
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
@dataclass
|
souleyez/core/web_utils.py
CHANGED
|
@@ -4,10 +4,11 @@ Web utility functions for SoulEyez.
|
|
|
4
4
|
Includes HTTP redirect detection and other web-related helpers.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import requests
|
|
8
7
|
from typing import Dict, Optional
|
|
9
8
|
from urllib.parse import urlparse
|
|
10
9
|
|
|
10
|
+
import requests
|
|
11
|
+
|
|
11
12
|
|
|
12
13
|
def check_http_redirect(ip: str, port: int = 80, timeout: int = 3) -> Dict[str, any]:
|
|
13
14
|
"""
|
souleyez/detection/__init__.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# SoulEyez Detection Validation
|
|
2
2
|
# Correlates attacks with SIEM detections
|
|
3
3
|
|
|
4
|
-
from .validator import DetectionValidator
|
|
5
4
|
from .attack_signatures import ATTACK_SIGNATURES
|
|
5
|
+
from .validator import DetectionValidator
|
|
6
6
|
|
|
7
7
|
__all__ = ["DetectionValidator", "ATTACK_SIGNATURES"]
|
|
@@ -5,7 +5,7 @@ Maps SoulEyez tool names to expected Wazuh detection rules and search patterns.
|
|
|
5
5
|
Used for correlating attacks with SIEM alerts.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import Any, Dict, List
|
|
9
9
|
|
|
10
10
|
# Detection window in seconds after attack completes
|
|
11
11
|
DEFAULT_DETECTION_WINDOW = 300 # 5 minutes
|
|
@@ -5,9 +5,8 @@ Maps SoulEyez attack tools to MITRE ATT&CK techniques and tactics.
|
|
|
5
5
|
Used for generating detection coverage reports with ATT&CK heatmaps.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from typing import Dict, List, Any, Optional
|
|
9
8
|
from dataclasses import dataclass, field
|
|
10
|
-
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
11
10
|
|
|
12
11
|
# MITRE ATT&CK Tactics (Enterprise Matrix)
|
|
13
12
|
# Reference: https://attack.mitre.org/tactics/enterprise/
|
souleyez/detection/validator.py
CHANGED
|
@@ -9,13 +9,14 @@ Supports multiple SIEM platforms: Wazuh, Splunk, Elastic, Sentinel.
|
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
11
|
import os
|
|
12
|
+
from dataclasses import asdict, dataclass, field
|
|
12
13
|
from datetime import datetime, timedelta
|
|
13
|
-
from
|
|
14
|
-
from typing import List, Dict, Any, Optional
|
|
14
|
+
from typing import Any, Dict, List, Optional
|
|
15
15
|
|
|
16
|
+
from souleyez.integrations.siem import SIEMClient, SIEMFactory
|
|
16
17
|
from souleyez.storage.database import get_db
|
|
17
|
-
|
|
18
|
-
from .attack_signatures import
|
|
18
|
+
|
|
19
|
+
from .attack_signatures import DEFAULT_DETECTION_WINDOW, get_signature
|
|
19
20
|
|
|
20
21
|
# Job queue file location (same as background.py)
|
|
21
22
|
DATA_DIR = os.path.join(os.path.expanduser("~"), ".souleyez", "data")
|
souleyez/devtools.py
CHANGED
|
@@ -9,11 +9,13 @@ Command: souleyez dev repair
|
|
|
9
9
|
- Verifies installed version and import path
|
|
10
10
|
- Prints helpful guidance (no destructive data ops)
|
|
11
11
|
"""
|
|
12
|
+
|
|
12
13
|
from __future__ import annotations
|
|
14
|
+
|
|
13
15
|
import os
|
|
14
|
-
import sys
|
|
15
|
-
import subprocess
|
|
16
16
|
import shutil
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
17
19
|
from pathlib import Path
|
|
18
20
|
|
|
19
21
|
CSI = "\033["
|
souleyez/docs/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# SoulEyez Documentation
|
|
2
2
|
|
|
3
|
-
**Version:**
|
|
4
|
-
**Last Updated:** January
|
|
3
|
+
**Version:** 3.0.7
|
|
4
|
+
**Last Updated:** January 31, 2026
|
|
5
5
|
**Organization:** CyberSoul Security
|
|
6
6
|
|
|
7
7
|
Welcome to the SoulEyez documentation! This documentation covers architecture, development, user guides, and operational information for the SoulEyez penetration testing platform.
|
souleyez/engine/background.py
CHANGED
|
@@ -73,6 +73,10 @@ TRANSIENT_ERROR_PATTERNS = [
|
|
|
73
73
|
"Resource temporarily unavailable",
|
|
74
74
|
"SMBTimeout",
|
|
75
75
|
"timed out while waiting",
|
|
76
|
+
# Impacket-specific timeout patterns
|
|
77
|
+
"] timed out", # Matches: [Errno Connection error (IP:port)] timed out
|
|
78
|
+
"RemoteOperations failed", # Impacket remote operation failures
|
|
79
|
+
"Errno Connection error", # Generic Impacket connection errors
|
|
76
80
|
]
|
|
77
81
|
|
|
78
82
|
_lock = threading.RLock() # Reentrant lock allows nested acquisition by same thread
|
|
@@ -88,6 +92,40 @@ def _is_transient_error(log_content: str) -> bool:
|
|
|
88
92
|
return False
|
|
89
93
|
|
|
90
94
|
|
|
95
|
+
def _is_netexec_flaky_empty(log_content: str, job: dict) -> bool:
|
|
96
|
+
"""
|
|
97
|
+
Check if netexec/crackmapexec produced no output (flaky ARM behavior).
|
|
98
|
+
|
|
99
|
+
On ARM, netexec is ~20% flaky - it exits 0 but sometimes produces
|
|
100
|
+
zero output. This detects ONLY that case.
|
|
101
|
+
|
|
102
|
+
DOES NOT retry when:
|
|
103
|
+
- Access denied (has "[-]" error output)
|
|
104
|
+
- Connected but no shares (legitimate result)
|
|
105
|
+
- Any netexec output exists
|
|
106
|
+
"""
|
|
107
|
+
tool = job.get("tool", "").lower()
|
|
108
|
+
args = job.get("args", [])
|
|
109
|
+
|
|
110
|
+
if tool not in ("crackmapexec", "nxc", "netexec"):
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
args_str = " ".join(args).lower() if args else ""
|
|
114
|
+
if "--shares" not in args_str and "smb" not in args_str:
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
lower = log_content.lower()
|
|
118
|
+
|
|
119
|
+
# If we got ANY netexec output, it's a real response - don't retry
|
|
120
|
+
# This includes error output like "[-]" which indicates access denied
|
|
121
|
+
has_any_output = any(
|
|
122
|
+
x in lower for x in ["smb", "[*]", "[+]", "[-]", "445", "signing"]
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Only retry if truly zero output (ARM flakiness)
|
|
126
|
+
return not has_any_output
|
|
127
|
+
|
|
128
|
+
|
|
91
129
|
class _CrossProcessLock:
|
|
92
130
|
"""
|
|
93
131
|
Cross-process file lock using fcntl.flock().
|
|
@@ -1516,6 +1554,78 @@ def _is_stdbuf_available() -> bool:
|
|
|
1516
1554
|
return _stdbuf_available
|
|
1517
1555
|
|
|
1518
1556
|
|
|
1557
|
+
def _is_python_tool(cmd: List[str]) -> bool:
|
|
1558
|
+
"""
|
|
1559
|
+
Check if a command is a Python-based tool.
|
|
1560
|
+
|
|
1561
|
+
stdbuf doesn't work well with Python scripts because Python manages its own
|
|
1562
|
+
buffering internally. On some systems (especially ARM), stdbuf can prevent
|
|
1563
|
+
Python tools from producing any output at all.
|
|
1564
|
+
|
|
1565
|
+
Args:
|
|
1566
|
+
cmd: Command array to check
|
|
1567
|
+
|
|
1568
|
+
Returns:
|
|
1569
|
+
True if the command is a Python tool that should skip stdbuf
|
|
1570
|
+
"""
|
|
1571
|
+
if not cmd:
|
|
1572
|
+
return False
|
|
1573
|
+
|
|
1574
|
+
executable = cmd[0]
|
|
1575
|
+
|
|
1576
|
+
# Direct Python invocation
|
|
1577
|
+
if executable in ("python", "python3") or executable.startswith("python"):
|
|
1578
|
+
return True
|
|
1579
|
+
|
|
1580
|
+
# .py extension
|
|
1581
|
+
if executable.endswith(".py"):
|
|
1582
|
+
return True
|
|
1583
|
+
|
|
1584
|
+
# Known Python tools that don't work with stdbuf
|
|
1585
|
+
# These are tools installed via pip/pipx that are Python scripts
|
|
1586
|
+
python_tools = {
|
|
1587
|
+
"netexec",
|
|
1588
|
+
"nxc",
|
|
1589
|
+
"crackmapexec",
|
|
1590
|
+
"cme",
|
|
1591
|
+
"smbmap",
|
|
1592
|
+
"impacket-GetNPUsers",
|
|
1593
|
+
"impacket-GetUserSPNs",
|
|
1594
|
+
"impacket-secretsdump",
|
|
1595
|
+
"impacket-psexec",
|
|
1596
|
+
"impacket-smbclient",
|
|
1597
|
+
"impacket-wmiexec",
|
|
1598
|
+
"impacket-dcomexec",
|
|
1599
|
+
"impacket-atexec",
|
|
1600
|
+
"GetNPUsers.py",
|
|
1601
|
+
"GetUserSPNs.py",
|
|
1602
|
+
"secretsdump.py",
|
|
1603
|
+
"psexec.py",
|
|
1604
|
+
"smbclient.py",
|
|
1605
|
+
"certipy",
|
|
1606
|
+
"bloodhound-python",
|
|
1607
|
+
"ldapdomaindump",
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
# Check base name (handle full paths)
|
|
1611
|
+
base_name = os.path.basename(executable)
|
|
1612
|
+
if base_name in python_tools:
|
|
1613
|
+
return True
|
|
1614
|
+
|
|
1615
|
+
# Check shebang for Python interpreter
|
|
1616
|
+
exe_path = shutil.which(executable)
|
|
1617
|
+
if exe_path:
|
|
1618
|
+
try:
|
|
1619
|
+
with open(exe_path, "rb") as f:
|
|
1620
|
+
first_bytes = f.read(100)
|
|
1621
|
+
if first_bytes.startswith(b"#!") and b"python" in first_bytes:
|
|
1622
|
+
return True
|
|
1623
|
+
except (IOError, OSError):
|
|
1624
|
+
pass
|
|
1625
|
+
|
|
1626
|
+
return False
|
|
1627
|
+
|
|
1628
|
+
|
|
1519
1629
|
def _wrap_cmd_for_line_buffering(cmd: List[str]) -> List[str]:
|
|
1520
1630
|
"""
|
|
1521
1631
|
Wrap a command with stdbuf for line-buffered output when available.
|
|
@@ -1524,6 +1634,9 @@ def _wrap_cmd_for_line_buffering(cmd: List[str]) -> List[str]:
|
|
|
1524
1634
|
improving real-time log monitoring and ensuring output is captured
|
|
1525
1635
|
before process termination.
|
|
1526
1636
|
|
|
1637
|
+
Note: Python tools are excluded because stdbuf interferes with Python's
|
|
1638
|
+
internal buffering and can cause zero output on some systems (Ubuntu ARM).
|
|
1639
|
+
|
|
1527
1640
|
Args:
|
|
1528
1641
|
cmd: Command to wrap
|
|
1529
1642
|
|
|
@@ -1533,6 +1646,10 @@ def _wrap_cmd_for_line_buffering(cmd: List[str]) -> List[str]:
|
|
|
1533
1646
|
if not cmd:
|
|
1534
1647
|
return cmd
|
|
1535
1648
|
|
|
1649
|
+
# Skip stdbuf for Python tools - causes output capture failures on ARM
|
|
1650
|
+
if _is_python_tool(cmd):
|
|
1651
|
+
return cmd
|
|
1652
|
+
|
|
1536
1653
|
if _is_stdbuf_available():
|
|
1537
1654
|
# stdbuf -oL = line-buffered stdout, -eL = line-buffered stderr
|
|
1538
1655
|
return ["stdbuf", "-oL", "-eL"] + cmd
|
|
@@ -2064,21 +2181,30 @@ def run_job(jid: int) -> None:
|
|
|
2064
2181
|
job = get_job(jid)
|
|
2065
2182
|
retry_count = job.get("metadata", {}).get("retry_count", 0)
|
|
2066
2183
|
if retry_count < MAX_RETRIES:
|
|
2067
|
-
# Read log to check for transient errors
|
|
2068
|
-
# Note: Check even when rc==0 because tools like nxc may exit 0 but log errors
|
|
2184
|
+
# Read log to check for transient errors or flaky netexec
|
|
2069
2185
|
log_path = job.get("log", "")
|
|
2070
2186
|
if log_path and os.path.exists(log_path):
|
|
2071
2187
|
try:
|
|
2072
2188
|
with open(log_path, "r", encoding="utf-8", errors="replace") as f:
|
|
2073
2189
|
log_content = f.read()
|
|
2074
|
-
|
|
2075
|
-
|
|
2190
|
+
|
|
2191
|
+
# Check for transient errors OR flaky netexec (connected but no shares)
|
|
2192
|
+
is_transient = _is_transient_error(log_content)
|
|
2193
|
+
is_netexec_flaky = _is_netexec_flaky_empty(log_content, job)
|
|
2194
|
+
retry_reason = None
|
|
2195
|
+
|
|
2196
|
+
if is_transient:
|
|
2197
|
+
retry_reason = "transient error"
|
|
2198
|
+
elif is_netexec_flaky:
|
|
2199
|
+
retry_reason = "netexec connected but no shares"
|
|
2200
|
+
|
|
2201
|
+
if retry_reason:
|
|
2076
2202
|
logger.info(
|
|
2077
|
-
"
|
|
2203
|
+
f"Auto-retrying job: {retry_reason}",
|
|
2078
2204
|
extra={"job_id": jid, "retry_count": retry_count + 1},
|
|
2079
2205
|
)
|
|
2080
2206
|
_append_worker_log(
|
|
2081
|
-
f"job {jid}:
|
|
2207
|
+
f"job {jid}: {retry_reason}, auto-retry {retry_count + 1}/{MAX_RETRIES}"
|
|
2082
2208
|
)
|
|
2083
2209
|
|
|
2084
2210
|
# Build new job metadata with incremented retry count
|
|
@@ -2095,7 +2221,7 @@ def run_job(jid: int) -> None:
|
|
|
2095
2221
|
engagement_id=job.get("engagement_id"),
|
|
2096
2222
|
metadata=new_metadata,
|
|
2097
2223
|
parent_id=job.get("metadata", {}).get("parent_id"),
|
|
2098
|
-
reason=f"Auto-retry {retry_count + 1}/{MAX_RETRIES} (
|
|
2224
|
+
reason=f"Auto-retry {retry_count + 1}/{MAX_RETRIES} ({retry_reason})",
|
|
2099
2225
|
rule_id=job.get("metadata", {}).get("rule_id"),
|
|
2100
2226
|
skip_scope_check=True, # Already validated on first run
|
|
2101
2227
|
)
|
|
@@ -2120,6 +2246,41 @@ def run_job(jid: int) -> None:
|
|
|
2120
2246
|
|
|
2121
2247
|
# Re-fetch job to get updated data
|
|
2122
2248
|
job = get_job(jid)
|
|
2249
|
+
|
|
2250
|
+
# Ensure log file is fully flushed to disk before parsing
|
|
2251
|
+
# Some tools (especially Python-based like impacket) may have buffered output
|
|
2252
|
+
log_path = job.get("log", "")
|
|
2253
|
+
if log_path and os.path.exists(log_path):
|
|
2254
|
+
# Wait for completion marker with retries
|
|
2255
|
+
# Log files end with "Exit Code:" or "=== Completed"
|
|
2256
|
+
max_retries = 5
|
|
2257
|
+
retry_delay = 0.2 # 200ms between retries
|
|
2258
|
+
log_complete = False
|
|
2259
|
+
|
|
2260
|
+
for attempt in range(max_retries):
|
|
2261
|
+
try:
|
|
2262
|
+
with open(
|
|
2263
|
+
log_path, "r", encoding="utf-8", errors="replace"
|
|
2264
|
+
) as f:
|
|
2265
|
+
content = f.read()
|
|
2266
|
+
# Check for completion markers
|
|
2267
|
+
if "Exit Code:" in content or "=== Completed" in content:
|
|
2268
|
+
log_complete = True
|
|
2269
|
+
break
|
|
2270
|
+
except Exception:
|
|
2271
|
+
pass
|
|
2272
|
+
|
|
2273
|
+
if attempt < max_retries - 1:
|
|
2274
|
+
time.sleep(retry_delay)
|
|
2275
|
+
|
|
2276
|
+
if not log_complete:
|
|
2277
|
+
# Last resort: force filesystem sync and proceed anyway
|
|
2278
|
+
try:
|
|
2279
|
+
with open(log_path, "a") as f:
|
|
2280
|
+
os.fsync(f.fileno())
|
|
2281
|
+
except Exception:
|
|
2282
|
+
pass
|
|
2283
|
+
|
|
2123
2284
|
parse_result = handle_job_result(job)
|
|
2124
2285
|
|
|
2125
2286
|
# Handle parse failure cases
|
souleyez/engine/base.py
CHANGED
souleyez/engine/loader.py
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Simple plugin loader for souleyez (L1).
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from __future__ import annotations
|
|
6
|
-
|
|
7
|
+
|
|
7
8
|
import importlib
|
|
8
|
-
|
|
9
|
+
import pkgutil
|
|
10
|
+
from typing import Any, Dict
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
def _safe_import_module(fullname: str):
|
souleyez/engine/log_sanitizer.py
CHANGED
souleyez/engine/manager.py
CHANGED
|
@@ -6,11 +6,13 @@ This manager contains a small built-in adapter for "nmap" that uses your existin
|
|
|
6
6
|
souleyez.scanner.run_nmap function. Later plugins can be added by implementing
|
|
7
7
|
ScannerPlugin in their own modules and registering them here.
|
|
8
8
|
"""
|
|
9
|
+
|
|
10
|
+
import importlib
|
|
9
11
|
import threading
|
|
10
12
|
from typing import Optional
|
|
13
|
+
|
|
11
14
|
from ..storage.db import init_db, insert_scan, update_scan
|
|
12
15
|
from ..utils import timestamp_str
|
|
13
|
-
import importlib
|
|
14
16
|
|
|
15
17
|
# lazy import existing run_nmap (your project has souleyez/scanner.py)
|
|
16
18
|
|