souleyez 2.23.0__py3-none-any.whl → 2.25.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.
souleyez/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = '2.23.0'
1
+ __version__ = '2.25.0'
@@ -29,15 +29,25 @@ logger = logging.getLogger(__name__)
29
29
 
30
30
  def get_msf_database_config() -> Optional[Dict[str, Any]]:
31
31
  """
32
- Get MSF database configuration from ~/.msf4/database.yml
32
+ Get MSF database configuration from ~/.msf4/database.yml or system-wide config.
33
+
34
+ Checks user config first, then falls back to system-wide config (Kali Linux).
33
35
 
34
36
  Returns:
35
37
  Dictionary with database config or None if not found/parseable
36
38
  """
37
- db_yml_path = Path.home() / ".msf4" / "database.yml"
38
-
39
- if not db_yml_path.exists():
40
- logger.debug(f"MSF database.yml not found at {db_yml_path}")
39
+ # Check user config first, then system-wide config (Kali uses system-wide)
40
+ user_db_path = Path.home() / ".msf4" / "database.yml"
41
+ system_db_path = Path('/usr/share/metasploit-framework/config/database.yml')
42
+
43
+ db_yml_path = None
44
+ if user_db_path.exists():
45
+ db_yml_path = user_db_path
46
+ elif system_db_path.exists():
47
+ db_yml_path = system_db_path
48
+
49
+ if not db_yml_path:
50
+ logger.debug("MSF database.yml not found in user or system config")
41
51
  return None
42
52
 
43
53
  try:
@@ -746,17 +746,8 @@ class ToolChaining:
746
746
  args_template=['-a', '{target}'],
747
747
  description='SMB service detected, enumerating shares and users (runs after CrackMapExec)'
748
748
  ),
749
- # DISABLED: smbmap has upstream pickling bug with impacket (affects all versions)
750
- # Use crackmapexec/netexec --shares instead (rule #10 above)
751
- ChainRule(
752
- trigger_tool='nmap',
753
- trigger_condition='service:smb',
754
- target_tool='smbmap',
755
- priority=7,
756
- enabled=False, # Disabled due to impacket pickling bug
757
- args_template=['-H', '{target}'],
758
- description='SMB service detected, mapping shares (DISABLED - use netexec)'
759
- ),
749
+ # NOTE: smbmap removed - has upstream impacket pickling bug on Python 3.13+
750
+ # Use crackmapexec/netexec --shares instead (enum4linux rule above)
760
751
  ])
761
752
 
762
753
  # Active Directory attacks - smart chaining workflow
souleyez/docs/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # SoulEyez Documentation
2
2
 
3
- **Version:** 2.23.0
4
- **Last Updated:** January 7, 2026
3
+ **Version:** 2.25.0
4
+ **Last Updated:** January 8, 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.
@@ -22,6 +22,17 @@ This guide walks you through installing souleyez on your system. The process tak
22
22
  - **RAM Usage**: Running multiple heavy tools (Metasploit, SQLMap, Hashcat) simultaneously requires additional RAM
23
23
  - **Disk I/O**: SSD recommended for database operations and log processing
24
24
 
25
+ > **🐉 Kali Linux Recommended**
26
+ >
27
+ > SoulEyez performs significantly better on **Kali Linux** than other distributions:
28
+ > - All pentesting tools pre-installed and optimized
29
+ > - Metasploit database and RPC already configured
30
+ > - Security-focused kernel and networking stack
31
+ > - No dependency hunting or version conflicts
32
+ > - Wordlists, databases, and tool configs ready to go
33
+ >
34
+ > While Ubuntu and other Debian-based distros are supported, you may experience slower setup times and occasional tool compatibility issues.
35
+
25
36
  ### Software Requirements
26
37
 
27
38
  - **Operating System**: Linux (Kali Linux recommended, any Debian-based distro supported)
@@ -1039,7 +1039,8 @@ def _is_true_error_exit_code(rc: int, tool: str) -> bool:
1039
1039
  # Tools that use non-zero exit codes for non-error conditions
1040
1040
  # Parser will determine the actual status based on output
1041
1041
  # msf_exploit returns 1 when no session opened (exploit ran but target not vulnerable)
1042
- tools_with_nonzero_success = ['gobuster', 'hydra', 'medusa', 'msf_exploit']
1042
+ # nikto returns non-zero when it finds vulnerabilities (not an error!)
1043
+ tools_with_nonzero_success = ['gobuster', 'hydra', 'medusa', 'msf_exploit', 'nikto']
1043
1044
 
1044
1045
  if tool.lower() in tools_with_nonzero_success:
1045
1046
  # Let parser determine status
@@ -1433,6 +1434,21 @@ def _detect_and_recover_stale_jobs() -> int:
1433
1434
  "status": status,
1434
1435
  "parse_result": parse_result
1435
1436
  })
1437
+
1438
+ # Mark for auto-chaining if conditions are met
1439
+ try:
1440
+ from souleyez.core.tool_chaining import ToolChaining
1441
+ chaining = ToolChaining()
1442
+ if chaining.is_enabled() and is_chainable(status):
1443
+ _update_job(jid, chainable=True)
1444
+ _append_worker_log(f"job {jid} stale recovery marked as chainable")
1445
+ logger.info("Stale job marked as chainable", extra={
1446
+ "job_id": jid,
1447
+ "tool": tool,
1448
+ "status": status
1449
+ })
1450
+ except Exception as chain_err:
1451
+ _append_worker_log(f"job {jid} stale recovery chainable error: {chain_err}")
1436
1452
  except Exception as parse_err:
1437
1453
  _append_worker_log(f"job {jid} stale recovery parse exception: {parse_err}")
1438
1454
 
souleyez/main.py CHANGED
@@ -173,7 +173,7 @@ def _check_privileged_tools():
173
173
 
174
174
 
175
175
  @click.group()
176
- @click.version_option(version='2.23.0')
176
+ @click.version_option(version='2.25.0')
177
177
  def cli():
178
178
  """SoulEyez - AI-Powered Pentesting Platform by CyberSoul Security"""
179
179
  from souleyez.log_config import init_logging
@@ -1388,19 +1388,24 @@ def _run_doctor(fix=False, verbose=False):
1388
1388
  path_dirs = os.environ.get('PATH', '').split(':')
1389
1389
  pipx_bin = str(Path.home() / '.local' / 'bin')
1390
1390
  go_bin = str(Path.home() / 'go' / 'bin')
1391
+
1392
+ # Detect shell config file (zsh for Kali, bash for others)
1393
+ shell = os.environ.get('SHELL', '/bin/bash')
1394
+ shell_rc = '~/.zshrc' if 'zsh' in shell else '~/.bashrc'
1395
+
1391
1396
  if pipx_bin in path_dirs:
1392
1397
  if verbose:
1393
1398
  check_pass("PATH includes ~/.local/bin (pipx)")
1394
1399
  else:
1395
1400
  if Path(pipx_bin).exists() and any(Path(pipx_bin).iterdir()):
1396
- check_warn("~/.local/bin not in PATH", "Add to ~/.bashrc: export PATH=\"$HOME/.local/bin:$PATH\"")
1401
+ check_warn("~/.local/bin not in PATH", f"Add to {shell_rc}: export PATH=\"$HOME/.local/bin:$PATH\"")
1397
1402
 
1398
1403
  if go_bin in path_dirs:
1399
1404
  if verbose:
1400
1405
  check_pass("PATH includes ~/go/bin")
1401
1406
  else:
1402
1407
  if Path(go_bin).exists() and any(Path(go_bin).iterdir()):
1403
- check_warn("~/go/bin not in PATH", "Add to ~/.bashrc: export PATH=\"$HOME/go/bin:$PATH\"")
1408
+ check_warn("~/go/bin not in PATH", f"Add to {shell_rc}: export PATH=\"$HOME/go/bin:$PATH\"")
1404
1409
 
1405
1410
  # Check database is writable
1406
1411
  if db_path.exists():
@@ -1430,8 +1435,10 @@ def _run_doctor(fix=False, verbose=False):
1430
1435
  # Section 7: MSF Database (if msfconsole available)
1431
1436
  if shutil.which('msfconsole'):
1432
1437
  click.echo(click.style("Metasploit", bold=True))
1438
+ # Check user config first, then system-wide config (Kali uses system-wide)
1433
1439
  msf_db = Path.home() / '.msf4' / 'database.yml'
1434
- if msf_db.exists():
1440
+ system_msf_db = Path('/usr/share/metasploit-framework/config/database.yml')
1441
+ if msf_db.exists() or system_msf_db.exists():
1435
1442
  check_pass("MSF database configured")
1436
1443
  else:
1437
1444
  check_fail("MSF database not initialized", "msfdb init")
@@ -207,19 +207,51 @@ class NucleiPlugin(PluginBase):
207
207
  return True
208
208
  return False
209
209
 
210
- def build_command(self, target: str, args: List[str] = None, label: str = "", log_path: str = None):
211
- """Build nuclei command for background execution with PID tracking."""
212
- # For URLs, validate them. For bare IPs/domains, let Nuclei auto-detect protocols
210
+ def _normalize_target(self, target: str, args: List[str] = None, log_path: str = None) -> str:
211
+ """
212
+ Normalize target for Nuclei scanning.
213
+
214
+ - URLs are validated and passed through
215
+ - Bare IPs/domains get http:// prepended for web scanning
216
+
217
+ This fixes the issue where nmap chains pass bare IPs but Nuclei
218
+ needs URLs to properly scan web services.
219
+ """
220
+ import re
221
+
222
+ # Already a URL - validate and return
213
223
  if target.startswith(('http://', 'https://')):
214
224
  try:
215
- target = validate_url(target)
225
+ return validate_url(target)
216
226
  except ValidationError as e:
217
227
  if log_path:
218
228
  with open(log_path, 'w') as f:
219
229
  f.write(f"ERROR: Invalid URL: {e}\n")
220
230
  return None
221
231
 
232
+ # Bare IP or domain - prepend http:// for web scanning
233
+ # This is needed because Nuclei web templates require a URL
234
+ ip_pattern = r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(:\d+)?$'
235
+ domain_pattern = r'^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$'
236
+
237
+ if re.match(ip_pattern, target) or re.match(domain_pattern, target):
238
+ # Log the conversion
239
+ if log_path:
240
+ with open(log_path, 'a') as f:
241
+ f.write(f"NOTE: Converting bare target '{target}' to 'http://{target}' for web scanning\n")
242
+ return f"http://{target}"
243
+
244
+ # Unknown format - return as-is
245
+ return target
246
+
247
+ def build_command(self, target: str, args: List[str] = None, label: str = "", log_path: str = None):
248
+ """Build nuclei command for background execution with PID tracking."""
222
249
  args = args or []
250
+
251
+ # Normalize target (convert bare IPs to URLs)
252
+ target = self._normalize_target(target, args, log_path)
253
+ if target is None:
254
+ return None
223
255
  args = [arg.replace("<target>", target) for arg in args]
224
256
 
225
257
  cmd = ["nuclei", "-target", target]
@@ -252,21 +284,13 @@ class NucleiPlugin(PluginBase):
252
284
 
253
285
  def run(self, target: str, args: List[str] = None, label: str = "", log_path: str = None) -> int:
254
286
  """Execute nuclei scan and write JSON output to log_path."""
255
-
256
- # For URLs, validate them. For bare IPs/domains, let Nuclei auto-detect protocols
257
- if target.startswith(('http://', 'https://')):
258
- try:
259
- target = validate_url(target)
260
- except ValidationError as e:
261
- if log_path:
262
- with open(log_path, 'w') as f:
263
- f.write(f"ERROR: Invalid URL: {e}\n")
264
- return 1
265
- raise ValueError(f"Invalid URL: {e}")
266
- # Otherwise keep target as-is (IP or domain) for Nuclei auto-detect protocols
267
-
268
287
  args = args or []
269
288
 
289
+ # Normalize target (convert bare IPs to URLs)
290
+ target = self._normalize_target(target, args, log_path)
291
+ if target is None:
292
+ return 1
293
+
270
294
  # Replace <target> placeholder
271
295
  args = [arg.replace("<target>", target) for arg in args]
272
296
 
@@ -130,6 +130,63 @@ def render_standard_header(title: str, width: int = None) -> None:
130
130
  click.echo()
131
131
 
132
132
 
133
+ def parse_syslog_description(desc: str) -> str:
134
+ """
135
+ Extract meaningful message from syslog-formatted descriptions.
136
+
137
+ Syslog format: <timestamp> <host> [timestamp] <program>[pid]: <message>
138
+ Example input: "Jan 8 07:00:05 192.168.1.111 Jan 8 07:00:05 eyez CRON[537281]: pam_unix(cron:session): session closed for user yoda"
139
+ Example output: "CRON: pam_unix(cron:session): session closed for user yoda"
140
+ """
141
+ import re
142
+
143
+ if not desc:
144
+ return 'No description'
145
+
146
+ # Try to find the actual message after common syslog patterns
147
+ # Pattern 1: Look for process name with PID followed by colon (e.g., "CRON[537281]:")
148
+ pid_match = re.search(r'([A-Za-z_][A-Za-z0-9_-]*)\[(\d+)\]:\s*(.+)$', desc)
149
+ if pid_match:
150
+ process_name = pid_match.group(1)
151
+ message = pid_match.group(3)
152
+ return f"{process_name}: {message}"
153
+
154
+ # Pattern 2: Look for systemd-style messages (e.g., "systemd[1]: Started...")
155
+ systemd_match = re.search(r'(systemd(?:-[a-z]+)?)\[?\d*\]?:\s*(.+)$', desc, re.IGNORECASE)
156
+ if systemd_match:
157
+ return f"{systemd_match.group(1)}: {systemd_match.group(2)}"
158
+
159
+ # Pattern 3: Look for kernel messages
160
+ kernel_match = re.search(r'kernel:\s*(.+)$', desc)
161
+ if kernel_match:
162
+ return f"kernel: {kernel_match.group(1)}"
163
+
164
+ # Pattern 4: Generic - find content after last colon that has substance
165
+ colon_parts = desc.split(': ')
166
+ if len(colon_parts) > 1:
167
+ # Get the meaningful part (usually after the first "process:" pattern)
168
+ for i, part in enumerate(colon_parts):
169
+ # Skip parts that look like timestamps or IPs
170
+ if not re.match(r'^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec|\d{1,3}\.\d{1,3}|\d{4}-\d{2})', part):
171
+ # Found something meaningful - join from here
172
+ meaningful = ': '.join(colon_parts[i:])
173
+ if len(meaningful) > 10: # Ensure it's substantial
174
+ return meaningful
175
+
176
+ # Pattern 5: Strip leading timestamp patterns
177
+ # Remove patterns like "Jan 8 07:00:05 192.168.1.111 Jan 8 07:00:05 hostname"
178
+ stripped = re.sub(
179
+ r'^(?:[A-Z][a-z]{2}\s+\d+\s+\d{2}:\d{2}:\d{2}\s+\S+\s*)+',
180
+ '', desc
181
+ ).strip()
182
+
183
+ if stripped and len(stripped) > 5:
184
+ return stripped
185
+
186
+ # Fallback: return original if no patterns matched
187
+ return desc
188
+
189
+
133
190
  def _show_upgrade_prompt(feature_name: str):
134
191
  """Show upgrade prompt when FREE user tries to access Pro feature."""
135
192
  from rich.panel import Panel
@@ -5345,7 +5402,7 @@ def view_job_detail(job_id: int):
5345
5402
 
5346
5403
  # Check if tool has a parser - if yes, hide raw logs by default
5347
5404
  tool = job.get('tool', '')
5348
- has_parser = tool in ['dnsrecon', 'nmap', 'nuclei', 'nikto', 'dalfox', 'theharvester', 'sqlmap', 'ffuf', 'gobuster', 'wpscan', 'crackmapexec', 'hydra', 'whois', 'smbmap', 'enum4linux', 'msf_auxiliary', 'searchsploit']
5405
+ has_parser = tool in ['dnsrecon', 'nmap', 'ard', 'nuclei', 'nikto', 'dalfox', 'theharvester', 'sqlmap', 'ffuf', 'gobuster', 'wpscan', 'crackmapexec', 'hydra', 'whois', 'smbmap', 'enum4linux', 'msf_auxiliary', 'searchsploit']
5349
5406
 
5350
5407
  # Show log file if exists
5351
5408
  log_path = job.get('log')
@@ -5941,7 +5998,9 @@ def view_job_detail(job_id: int):
5941
5998
  pass
5942
5999
 
5943
6000
  # Parse and display Nmap results if available (only when not showing raw logs)
5944
- if not show_raw_logs and job.get('tool') == 'nmap' and job.get('status') in ['done', 'completed'] and log_path and os.path.exists(log_path):
6001
+ # ARD plugin uses nmap under the hood, so include it here
6002
+ nmap_based_tools = ['nmap', 'ard']
6003
+ if not show_raw_logs and job.get('tool') in nmap_based_tools and job.get('status') in ['done', 'completed'] and log_path and os.path.exists(log_path):
5945
6004
  try:
5946
6005
  from souleyez.parsers.nmap_parser import parse_nmap_output
5947
6006
  with open(log_path, 'r', encoding='utf-8', errors='replace') as f:
@@ -8898,7 +8957,8 @@ def _view_wazuh_alerts(engagement_id: int):
8898
8957
  icon = get_level_icon(level)
8899
8958
  rule_id = str(alert.get('rule_id', 'N/A'))[:10]
8900
8959
  agent_name = alert.get('agent_name', 'N/A')[:15]
8901
- desc = (alert.get('description') or 'No description')[:45]
8960
+ raw_desc = alert.get('description') or 'No description'
8961
+ desc = parse_syslog_description(raw_desc)[:45]
8902
8962
  ts = alert.get('timestamp', 'N/A')
8903
8963
  if hasattr(ts, 'strftime'):
8904
8964
  ts = ts.strftime('%Y-%m-%d %H:%M:%S')
@@ -9075,7 +9135,8 @@ def _view_alert_detail(alert: dict):
9075
9135
 
9076
9136
  # Get values from normalized format first, then fall back to raw_data
9077
9137
  rule_id = alert.get('rule_id') or rule.get('id', 'N/A')
9078
- description = alert.get('description') or rule.get('description', 'N/A')
9138
+ raw_description = alert.get('description') or rule.get('description', 'N/A')
9139
+ description = parse_syslog_description(raw_description)
9079
9140
  level = alert.get('level', 0) or rule.get('level', 0)
9080
9141
  severity = alert.get('severity', 'info')
9081
9142
 
@@ -15790,6 +15851,37 @@ def view_findings(engagement_id: int):
15790
15851
  summary_parts.append(f"Filters: {', '.join(active_filters)}")
15791
15852
 
15792
15853
  click.echo(" " + " | ".join(summary_parts))
15854
+
15855
+ # Show tool distribution legend
15856
+ if findings:
15857
+ tool_counts = {}
15858
+ for f in findings:
15859
+ tool = f.get('tool') or 'unknown'
15860
+ tool_counts[tool] = tool_counts.get(tool, 0) + 1
15861
+
15862
+ # Sort by count (descending) and format
15863
+ sorted_tools = sorted(tool_counts.items(), key=lambda x: x[1], reverse=True)
15864
+ tool_parts = [f"{tool}({count})" for tool, count in sorted_tools]
15865
+
15866
+ # Display on one or more lines if needed
15867
+ tool_legend = " Tools: " + " | ".join(tool_parts)
15868
+ if len(tool_legend) > width - 4:
15869
+ # Wrap to multiple lines if too long
15870
+ lines = []
15871
+ current_line = " Tools: "
15872
+ for i, part in enumerate(tool_parts):
15873
+ test_line = current_line + part + (" | " if i < len(tool_parts) - 1 else "")
15874
+ if len(test_line) > width - 4 and current_line != " Tools: ":
15875
+ lines.append(current_line.rstrip(" | "))
15876
+ current_line = " " + part + (" | " if i < len(tool_parts) - 1 else "")
15877
+ else:
15878
+ current_line = test_line
15879
+ lines.append(current_line.rstrip(" | "))
15880
+ for line in lines:
15881
+ click.echo(click.style(line, fg='cyan'))
15882
+ else:
15883
+ click.echo(click.style(tool_legend, fg='cyan'))
15884
+
15793
15885
  click.echo()
15794
15886
 
15795
15887
  if not findings:
souleyez/ui/tool_setup.py CHANGED
@@ -542,6 +542,9 @@ def run_tool_setup(check_only: bool = False, install_all: bool = False):
542
542
 
543
543
  def _run_post_install_tasks(console, distro: str):
544
544
  """Run tasks that should happen after tool installation or when all tools are present."""
545
+ # Ensure PATH is configured in shell rc files
546
+ _add_paths_to_shell_rc()
547
+
545
548
  # Configure passwordless sudo for privileged scans
546
549
  _configure_sudoers(console)
547
550
 
@@ -721,6 +721,7 @@ def check_msfdb_status() -> Dict[str, any]:
721
721
  - message: str - Human-readable status message
722
722
  """
723
723
  import subprocess
724
+ from pathlib import Path
724
725
 
725
726
  result = {
726
727
  'initialized': False,
@@ -734,6 +735,32 @@ def check_msfdb_status() -> Dict[str, any]:
734
735
  result['message'] = 'msfdb command not found - Metasploit may not be installed'
735
736
  return result
736
737
 
738
+ # Helper to check if PostgreSQL is running
739
+ def check_postgresql_running() -> bool:
740
+ try:
741
+ proc = subprocess.run(
742
+ ['systemctl', 'is-active', 'postgresql'],
743
+ capture_output=True,
744
+ text=True,
745
+ timeout=5
746
+ )
747
+ return proc.returncode == 0 and 'active' in proc.stdout.lower()
748
+ except Exception:
749
+ return False
750
+
751
+ # Helper to check system-wide MSF database config (Kali fallback)
752
+ def check_system_config() -> bool:
753
+ """Check if system-wide database.yml exists with valid PostgreSQL config."""
754
+ config_path = Path('/usr/share/metasploit-framework/config/database.yml')
755
+ if config_path.exists():
756
+ try:
757
+ content = config_path.read_text()
758
+ # Check for PostgreSQL adapter configuration
759
+ return 'adapter: postgresql' in content and 'database: msf' in content
760
+ except Exception:
761
+ return False
762
+ return False
763
+
737
764
  try:
738
765
  # Run msfdb status
739
766
  proc = subprocess.run(
@@ -743,10 +770,23 @@ def check_msfdb_status() -> Dict[str, any]:
743
770
  timeout=10
744
771
  )
745
772
  output = proc.stdout + proc.stderr
746
-
747
- # Parse output for status indicators
748
773
  output_lower = output.lower()
749
774
 
775
+ # Check if msfdb requires root (common on Kali)
776
+ if 'run as root' in output_lower or (proc.returncode != 0 and 'error' in output_lower):
777
+ # Fall back to checking system config file and PostgreSQL status
778
+ result['running'] = check_postgresql_running()
779
+ if check_system_config():
780
+ result['initialized'] = True
781
+ if result['running']:
782
+ result['connected'] = True
783
+ result['message'] = 'Database initialized and running'
784
+ else:
785
+ result['message'] = 'Database initialized but PostgreSQL not running - run: sudo systemctl start postgresql'
786
+ else:
787
+ result['message'] = 'Need sudo to verify - run: sudo msfdb status'
788
+ return result
789
+
750
790
  # Check if database is initialized
751
791
  if 'no database' in output_lower or 'not initialized' in output_lower:
752
792
  result['message'] = 'Database not initialized - run: msfdb init'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: souleyez
3
- Version: 2.23.0
3
+ Version: 2.25.0
4
4
  Summary: AI-Powered Penetration Testing Platform with 40+ integrated tools
5
5
  Author-email: CyberSoul Security <contact@cybersoulsecurity.com>
6
6
  Maintainer-email: CyberSoul Security <contact@cybersoulsecurity.com>
@@ -72,7 +72,7 @@ Welcome to the SoulEyez beta! Thank you for helping us test and improve this pen
72
72
 
73
73
  > ⚠️ **Important**: Only use SoulEyez on systems you have explicit authorization to test.
74
74
 
75
- ## Version: 2.23.0
75
+ ## Version: 2.25.0
76
76
 
77
77
  ### What's Included
78
78
 
@@ -110,6 +110,17 @@ Welcome to the SoulEyez beta! Thank you for helping us test and improve this pen
110
110
  - **Python**: 3.8 or newer
111
111
  - **Storage**: ~500MB for SoulEyez + tools
112
112
 
113
+ > **🐉 Kali Linux Recommended**
114
+ >
115
+ > SoulEyez performs significantly better on **Kali Linux** than other distributions:
116
+ > - All pentesting tools pre-installed and optimized
117
+ > - Metasploit database and RPC already configured
118
+ > - Security-focused kernel and networking stack
119
+ > - No dependency hunting or version conflicts
120
+ > - Wordlists, databases, and tool configs ready to go
121
+ >
122
+ > While Ubuntu and other Debian-based distros are supported, you may experience slower setup times and occasional tool compatibility issues.
123
+
113
124
  ### Known Issues
114
125
 
115
126
  - Very large scan outputs (>10MB) may slow the interface
@@ -299,4 +310,4 @@ Happy hacking! 🛡️
299
310
 
300
311
  ---
301
312
 
302
- **Version**: 2.23.0 | **Release Date**: January 2026 | **Maintainer**: CyberSoul Security
313
+ **Version**: 2.24.0 | **Release Date**: January 2026 | **Maintainer**: CyberSoul Security
@@ -1,10 +1,10 @@
1
- souleyez/__init__.py,sha256=Gfo1bPtx3vXPruBuKBhFTBXQMeD59Ul8vKsAH84yQsk,23
1
+ souleyez/__init__.py,sha256=Gwu_1X8_-6D9YneU0PXTLXImdMbVJ586ZzZwZ1kCbd8,23
2
2
  souleyez/config.py,sha256=av357I3GYRWAklv8Dto-9-5Db699Wq5znez7zo7241Q,11595
3
3
  souleyez/devtools.py,sha256=rptmUY4a5eVvYjdEc6273MSagL-D9xibPOFgohVqUno,3508
4
4
  souleyez/feature_flags.py,sha256=mo6YAq07lc6sR3lEFKmIwTKxXZ2JPxwa5X97uR_mu50,4642
5
5
  souleyez/history.py,sha256=gzs5I_j-3OigIP6yfmBChdqxaFmyUIxvTpzWUPe_Q6c,2853
6
6
  souleyez/log_config.py,sha256=MMhPAJOqgXDfuE-xm5g0RxAfWndcmbhFHvIEMm1a_Wo,5830
7
- souleyez/main.py,sha256=apVMU33AxgtFm1DF_AzHeM4fDAxtQ8xG1TIzicrEWDI,118990
7
+ souleyez/main.py,sha256=ePJkT92BAJJ5XnTGiwbdYwVs0_CpT4HJoWeSU4rLxxA,119362
8
8
  souleyez/scanner.py,sha256=U3IWHRrJ5aQ32dSHiVAHB60w1R_z0E0QxfM99msYNlw,3124
9
9
  souleyez/security.py,sha256=S84m1QmnKz_6NgH2I6IBIAorMHxRPNYVFSnks5xjihQ,2479
10
10
  souleyez/ui.py,sha256=15pfsqoDPnojAqr5S0TZHJE2ZkSHzkHpNVfVvsRj66A,34301
@@ -52,12 +52,12 @@ souleyez/core/msf_database.py,sha256=xaGt0wMX15CQv3-s2NobLK8niHgrE98qAkmS9zhrLe8
52
52
  souleyez/core/msf_integration.py,sha256=J9EXecxq72q65Itv1lBqjSkhh8Zx6SbZO2VPtlZXuOg,64842
53
53
  souleyez/core/msf_rpc_client.py,sha256=DL-_uJz_6G1pQud8iTg3_SjRJmgl4-W1YWmb0xg6f8Q,15994
54
54
  souleyez/core/msf_rpc_manager.py,sha256=8irWzXdiASVIokGSTf8DV57Uh_DUJ3Q6L-2oR9y8qeI,15572
55
- souleyez/core/msf_sync_manager.py,sha256=iEZ8_CJNdFAaEpp4PecIqrqslSH5oR23qrfJnrPntOg,27354
55
+ souleyez/core/msf_sync_manager.py,sha256=1alAqM2jHiMxbBdPTQL9Vjzbl8XVhrnS2VYhVdfNwUw,27779
56
56
  souleyez/core/network_utils.py,sha256=-4WgUE91RBzyXDFgGTxMa0zsWowJ47cEOAKXNeVa-Wc,4555
57
57
  souleyez/core/parser_handler.py,sha256=cyZtEDctqMdWgubsU0Jg6o4XqBgyfaJ_AeBHQmmv4hM,5564
58
58
  souleyez/core/pending_chains.py,sha256=Dnka7JK7A8gTWCGpTu6qrIgIDIXprkZmwJ0Rm2oWqRE,10972
59
59
  souleyez/core/templates.py,sha256=DzlXlAz8_lwAFjjUWPp3r81KCCzbNeK-bkN1IlgQBSU,18112
60
- souleyez/core/tool_chaining.py,sha256=hJ5uTI38blqJYexkCZOlxCR8KyrwI5vOGpqfdn1y5zo,270431
60
+ souleyez/core/tool_chaining.py,sha256=WPUJk0ArOFcF8kDUt5ZXgCnAc7LrPE16ETzpDgqFfcg,270028
61
61
  souleyez/core/version_utils.py,sha256=UOrOa3qfUdLKdzWT6GAGNV9TauwinXyLyelS8sOk0eE,11769
62
62
  souleyez/core/vuln_correlation.py,sha256=U69MSI5I-AtiyOAbXohGDKMpEHRW9y4G_0M1ppRGX18,14765
63
63
  souleyez/core/web_utils.py,sha256=f-Dqa6tH8ROnygn6-k7J1y8Qz2f1FmeJnPjPE0WRn34,4902
@@ -102,7 +102,7 @@ souleyez/detection/__init__.py,sha256=QIhvXjFdjrquQ6A0VQ7GZQkK_EXB59t8Dv9PKXhEUe
102
102
  souleyez/detection/attack_signatures.py,sha256=akgWwiIkh6WYnghCuLhRV0y6FS0SQ0caGF8tZUc49oA,6965
103
103
  souleyez/detection/mitre_mappings.py,sha256=xejE80YK-g8kKaeQoo-vBl8P3t8RTTItbfN0NaVZw6s,20558
104
104
  souleyez/detection/validator.py,sha256=-AJ7QSJ3-6jFKLnPG_Rc34IXyF4JPyI82BFUgTA9zw0,15641
105
- souleyez/docs/README.md,sha256=0lxLcTBckFxVigWPoKJ-_PZnqidWk9An7LQKfK2bjrE,7183
105
+ souleyez/docs/README.md,sha256=2xyQnpisNZMMTAmWc1YuRi0KIkUc56X96-qzqKnBATY,7183
106
106
  souleyez/docs/api-reference/cli-commands.md,sha256=lTLFnILN3YRVdqCaag7WgsYXfDGglb1TuPexkxDsVdE,12917
107
107
  souleyez/docs/api-reference/engagement-api.md,sha256=nd-EvQMtiJrobg2bzFEADp853HP1Uhb9dmgok0_-neE,11672
108
108
  souleyez/docs/api-reference/integration-guide.md,sha256=c96uX79ukHyYotLa54wZ20Kx-EUZnrKegTeGkfLD-pw,16285
@@ -132,7 +132,7 @@ souleyez/docs/user-guide/dependencies.md,sha256=WOPilg0W0U3KnsdGREkM5_gAG7Rr5P10
132
132
  souleyez/docs/user-guide/evidence-vault.md,sha256=PNg7cIUlVXr41iMJTi66j4qUV2fkrPATljunx0pD5sI,9454
133
133
  souleyez/docs/user-guide/exploit-suggestions.md,sha256=Qv9CPwDe9ypKoeUG3XAL6dtg4YA5PmlE5DA6JVHK4Nk,17971
134
134
  souleyez/docs/user-guide/getting-started.md,sha256=4QfZiQlYnReORAUpsy2gWzKe1uFHOePZyzDSz8zldgc,20932
135
- souleyez/docs/user-guide/installation.md,sha256=HGD4G2UYydiO-lp_VEvyClLtyBqnpqq52IuE6_al8lQ,13911
135
+ souleyez/docs/user-guide/installation.md,sha256=uM_qBpgG5YjkxSf8u6gUJh0TGYtPlo4pbn_wEXJHX0Q,14431
136
136
  souleyez/docs/user-guide/metasploit-integration.md,sha256=kSCai2PO4kiv3BEUSXa6mIC3vCdqIA70GyLVQH_Kaj4,10026
137
137
  souleyez/docs/user-guide/rbac.md,sha256=ULY5IbTCoNGOnvRrT1oH5XayCqD10PKoUwRDBRzpK2g,21055
138
138
  souleyez/docs/user-guide/report-generation.md,sha256=7Qe47jfPxmZ4U1uuM3kggPLQ6JM7_TCOOhYIvYen4Ao,20754
@@ -143,7 +143,7 @@ souleyez/docs/user-guide/uninstall.md,sha256=gDknetFhjZ0tnYk4JqhLa369NT4bIRb50rm
143
143
  souleyez/docs/user-guide/worker-management.md,sha256=hNu6eSTVb6XM4Zbb0I9Y5aL4AA2EiWOSFI6iGjn17kU,12035
144
144
  souleyez/docs/user-guide/workflows.md,sha256=4EyZKWRyuWf9wrENJwtidWKN25PGis1Pk33HIHk5UHM,22261
145
145
  souleyez/engine/__init__.py,sha256=THI_89hQfAPJDsfzDcur6H9sEGhGAnTxSNim7UOExYc,110
146
- souleyez/engine/background.py,sha256=ss8q0LexT6LPWB2bZHyPBjphB-BY9lNdrA6jyitD6sE,65224
146
+ souleyez/engine/background.py,sha256=Wm7dBzwq8qTi1vYvJk7T2TRktkdNzk50YQGZddcI3NU,66278
147
147
  souleyez/engine/base.py,sha256=G35U1d-fygUvzmHH8zxLXw-vyQ9JzcfhGaSYOsHJtzQ,728
148
148
  souleyez/engine/job_status.py,sha256=OAEf2rAzapm55m4tc3PSilotdA5ONX15JavUMLre0is,2685
149
149
  souleyez/engine/loader.py,sha256=ke6QQVVWozDnqGNBotajC3RBYOa2_DZmv5DAnDZVgIc,2769
@@ -236,7 +236,7 @@ souleyez/plugins/msf_auxiliary.py,sha256=pOL9yLJr_L0niwaHLPguM2Gaunr3iAe7HdIFbDL
236
236
  souleyez/plugins/msf_exploit.py,sha256=BNAZz5EO4jgwx64dEB4OE-CQdYkqJk5N4eXT140DRqs,23765
237
237
  souleyez/plugins/nikto.py,sha256=_BPzypwNTliBg2Tr6sPGMKYFTvnQgqEHO1xesDZ-6uo,9957
238
238
  souleyez/plugins/nmap.py,sha256=Bh3xauEfsDw_hxSarNfLN-J6tNda-mG3DqHHkphpttE,15997
239
- souleyez/plugins/nuclei.py,sha256=wIqlkwfLvn2NfHog8Z_P7roxMFyJs0xmuclL584UaqI,14999
239
+ souleyez/plugins/nuclei.py,sha256=A2pbSVFGJCu1QlokpV4-d4SJWw4Yv8FrQiLHE9lwRfc,15862
240
240
  souleyez/plugins/plugin_base.py,sha256=zB0wzZBBx5V63Ipc7CUEApYADLC8T-A__CLnTaXb49A,6731
241
241
  souleyez/plugins/plugin_template.py,sha256=Tcd_JrCBNgT1o88On4vjG5Y7mlGSVGh-hXyUak_KXlE,1786
242
242
  souleyez/plugins/responder.py,sha256=ImhISPLtvzqvJSUQrgavlZ_h9ZrJ4s9NrTkPAhEcHQM,13160
@@ -338,7 +338,7 @@ souleyez/ui/export_view.py,sha256=0nQvVsKk7FU4uRzSfJ_qBZh_Lfn8hgGA2rbJ5bNg5-Y,65
338
338
  souleyez/ui/gap_analysis_view.py,sha256=AytAOEBq010wwo9hne1TE-uJpY_xicjLrFANbvN3r3w,30727
339
339
  souleyez/ui/help_system.py,sha256=nKGxLaMi-TKYs6xudTyw_tZqBb1cGFEuYYh6N-MAsJE,16648
340
340
  souleyez/ui/intelligence_view.py,sha256=VeAQ-3mANRnLIVpRqocL3JV0HUmJtADdxDeC5lzQhE0,32168
341
- souleyez/ui/interactive.py,sha256=3jhlwxhrc0NzGTsYNiakWcdB516Gn2wNzYbgzpT7jR8,1371279
341
+ souleyez/ui/interactive.py,sha256=d-fGuSDG1n2a5GeF1aY_mZMTDWqMsQfBB2_-1kpSobw,1375354
342
342
  souleyez/ui/interactive_selector.py,sha256=6A51fgmFRnemBY0aCPHIhK2Rpba16NjSGKLzC0Q5vI8,16407
343
343
  souleyez/ui/log_formatter.py,sha256=akhIkYoO_cCaKxS1V5N3iPmIrHzgsU7pmsedx70s9TI,3845
344
344
  souleyez/ui/menu_components.py,sha256=N8zq2QXGmfaLJ08l53MMYt1y-5LRWgpZH6r8nXHonj8,3519
@@ -355,15 +355,15 @@ souleyez/ui/team_dashboard.py,sha256=ejM_44nbJbEIPxxxdEK7SCPcqQtcuJLjoO-C53qED2Y
355
355
  souleyez/ui/template_selector.py,sha256=qQJkFNnVjYctb-toeYlupP_U1asGrJWYi5-HR89Ab9g,19103
356
356
  souleyez/ui/terminal.py,sha256=Sw9ma1-DZclJE1sENjTZ3Q7r-Ct1NiB3Lpmv-RZW5tE,2372
357
357
  souleyez/ui/timeline_view.py,sha256=Ze8Mev9VE4_ECdNFEJwZK2V42EBguR83uCCdwAbJqmc,11111
358
- souleyez/ui/tool_setup.py,sha256=1PEWz0CpgeLjn0QZergH9Hzsd0qJZNXjV4e3gyzc-bE,32511
358
+ souleyez/ui/tool_setup.py,sha256=pkOUr-1inZlYnvaIc8Kj-Qaxk2KHWR2opJAgI_Er-Wo,32591
359
359
  souleyez/ui/tutorial.py,sha256=GGbBsze0ioL00WBWKEwPKy1ikegP1eusI2REDVMx4gY,14262
360
360
  souleyez/ui/tutorial_state.py,sha256=Thf7_qCj4VKjG7UqgJqa9kjIqiFUU-7Q7kG4v-u2B4A,8123
361
361
  souleyez/ui/wazuh_vulns_view.py,sha256=3vJJEmrjgS2wD6EDB7ZV7WxgytBHTm-1WqNDjp7lVEI,21830
362
362
  souleyez/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
363
- souleyez/utils/tool_checker.py,sha256=98G61Mp62P0wzzQ8QAdbnse3Ld2eKFe84PjrFHnXboY,28955
364
- souleyez-2.23.0.dist-info/licenses/LICENSE,sha256=J7vDD5QMF4w2oSDm35eBgosATE70ah1M40u9W4EpTZs,1090
365
- souleyez-2.23.0.dist-info/METADATA,sha256=b8F6zhXI0yv8Got_iyRNJ87Eo2IJUXRIOMu6KPRpMSc,10171
366
- souleyez-2.23.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
367
- souleyez-2.23.0.dist-info/entry_points.txt,sha256=bN5W1dhjDZJl3TKclMjRpfQvGPmyrJLwwDuCj_X39HE,48
368
- souleyez-2.23.0.dist-info/top_level.txt,sha256=afAMzS9p4lcdBNxhGo6jl3ipQE9HUvvNIPOdjtPjr_Q,9
369
- souleyez-2.23.0.dist-info/RECORD,,
363
+ souleyez/utils/tool_checker.py,sha256=kQcXJVY5NiO-orQAUnpHhpQvR5UOBNHJ0PaT0fBxYoQ,30782
364
+ souleyez-2.25.0.dist-info/licenses/LICENSE,sha256=J7vDD5QMF4w2oSDm35eBgosATE70ah1M40u9W4EpTZs,1090
365
+ souleyez-2.25.0.dist-info/METADATA,sha256=CqQ6AFaFoE6vTx2bU3l9vXeH16I3rd9o8qtIGmvL4Yo,10691
366
+ souleyez-2.25.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
367
+ souleyez-2.25.0.dist-info/entry_points.txt,sha256=bN5W1dhjDZJl3TKclMjRpfQvGPmyrJLwwDuCj_X39HE,48
368
+ souleyez-2.25.0.dist-info/top_level.txt,sha256=afAMzS9p4lcdBNxhGo6jl3ipQE9HUvvNIPOdjtPjr_Q,9
369
+ souleyez-2.25.0.dist-info/RECORD,,