sysvex 0.1.0__tar.gz

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.
sysvex-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 PuRiToX
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,11 @@
1
+ include README.md
2
+ include LICENSE
3
+ include pyproject.toml
4
+ recursive-include src/sysvex *.py
5
+ recursive-exclude * __pycache__
6
+ recursive-exclude * *.py[co]
7
+ exclude .gitignore
8
+ exclude .git
9
+ exclude venv
10
+ exclude .venv
11
+ exclude *.egg-info
sysvex-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.4
2
+ Name: sysvex
3
+ Version: 0.1.0
4
+ Summary: Modular system security auditing toolkit
5
+ Author: PuRIToX
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/PuRiToX/sysvex
8
+ Project-URL: Repository, https://github.com/PuRiToX/sysvex
9
+ Project-URL: Documentation, https://github.com/PuRiToX/sysvex#readme
10
+ Project-URL: Bug Tracker, https://github.com/PuRiToX/sysvex/issues
11
+ Keywords: security,auditing,system,forensics,cross-platform
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: System Administrators
14
+ Classifier: Intended Audience :: Information Technology
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Security
21
+ Classifier: Topic :: System :: Systems Administration
22
+ Classifier: Topic :: System :: Monitoring
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: psutil
27
+ Dynamic: license-file
@@ -0,0 +1,40 @@
1
+ [project]
2
+ name = "sysvex"
3
+ version = "0.1.0"
4
+ description = "Modular system security auditing toolkit"
5
+ authors = [
6
+ { name = "PuRIToX" }
7
+ ]
8
+ readme = "README.md"
9
+ license = "MIT"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "psutil"
13
+ ]
14
+ keywords = ["security", "auditing", "system", "forensics", "cross-platform"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: System Administrators",
18
+ "Intended Audience :: Information Technology",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Security",
25
+ "Topic :: System :: Systems Administration",
26
+ "Topic :: System :: Monitoring"
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/PuRiToX/sysvex"
31
+ Repository = "https://github.com/PuRiToX/sysvex"
32
+ Documentation = "https://github.com/PuRiToX/sysvex#readme"
33
+ "Bug Tracker" = "https://github.com/PuRiToX/sysvex/issues"
34
+
35
+ [project.scripts]
36
+ sysvex = "sysvex.cli:main"
37
+
38
+ [build-system]
39
+ requires = ["setuptools", "wheel"]
40
+ build-backend = "setuptools.build_meta"
sysvex-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,21 @@
1
+ import argparse
2
+ from sysvex.engine.loader import load_modules
3
+ from sysvex.engine.runner import run_modules
4
+ from sysvex.reporting.console import print_report
5
+
6
+ DEFAULT_MODULES = ["filesystem", "network", "processes"]
7
+
8
+ def main():
9
+ parser = argparse.ArgumentParser(description="Sysvex Security Auditor")
10
+ parser.add_argument("--modules", help="Comma-separated modules")
11
+
12
+ args = parser.parse_args()
13
+
14
+ module_names = (
15
+ args.modules.split(",") if args.modules else DEFAULT_MODULES
16
+ )
17
+
18
+ modules = load_modules(module_names)
19
+ findings = run_modules(modules)
20
+
21
+ print_report(findings)
File without changes
@@ -0,0 +1,10 @@
1
+ import importlib
2
+
3
+ def load_modules(module_names):
4
+ modules = []
5
+
6
+ for name in module_names:
7
+ module = importlib.import_module(f"sysvex.modules.{name}")
8
+ modules.append(module.Module())
9
+
10
+ return modules
@@ -0,0 +1,13 @@
1
+ class Finding:
2
+ def __init__(self, finding_id, title, severity, description,
3
+ evidence=None, recommendation=None, source_module=None):
4
+ self.id = finding_id
5
+ self.title = title
6
+ self.severity = severity
7
+ self.description = description
8
+ self.evidence = evidence
9
+ self.recommendation = recommendation
10
+ self.source_module = source_module
11
+
12
+ def to_dict(self):
13
+ return self.__dict__
@@ -0,0 +1,11 @@
1
+ def run_modules(modules, context=None):
2
+ findings = []
3
+
4
+ for module in modules:
5
+ try:
6
+ results = module.run(context)
7
+ findings.extend(results)
8
+ except (NotImplementedError, AttributeError, ValueError, RuntimeError) as e:
9
+ print(f"[ERROR] Module {module.name} failed: {e}")
10
+
11
+ return findings
File without changes
@@ -0,0 +1,5 @@
1
+ class BaseModule:
2
+ name = "base"
3
+
4
+ def run(self, context=None):
5
+ raise NotImplementedError
@@ -0,0 +1,155 @@
1
+ import os
2
+ import time
3
+ import stat
4
+ from sysvex.engine.models import Finding
5
+ from .base import BaseModule
6
+ from sysvex.utils.platform import get_platform_config, get_default_scan_path, is_windows
7
+
8
+ HIDDEN_FILE_DAYS = 7
9
+
10
+ class Module(BaseModule):
11
+ name = "filesystem"
12
+
13
+ def run(self, context=None):
14
+ config = get_platform_config()
15
+ scan_path = context.get('scan_path', get_default_scan_path()) if context else get_default_scan_path()
16
+ findings = []
17
+
18
+ # Scan for sensitive file permissions
19
+ for sensitive_path in config['sensitive_paths']:
20
+ if os.path.exists(sensitive_path):
21
+ try:
22
+ file_stat = os.stat(sensitive_path)
23
+ mode = file_stat.st_mode
24
+
25
+ # Check for world-readable sensitive files (Unix only)
26
+ if not is_windows():
27
+ if mode & stat.S_IROTH:
28
+ findings.append(Finding(
29
+ finding_id="FS-004",
30
+ title="World-readable sensitive file",
31
+ severity="HIGH",
32
+ description=f"Sensitive file {sensitive_path} is readable by others",
33
+ evidence=sensitive_path,
34
+ recommendation="Restrict permissions: chmod o-r {sensitive_path}",
35
+ source_module=self.name
36
+ ))
37
+
38
+ # Check for world-writable sensitive files (Unix only)
39
+ if mode & stat.S_IWOTH:
40
+ findings.append(Finding(
41
+ finding_id="FS-005",
42
+ title="World-writable sensitive file",
43
+ severity="CRITICAL",
44
+ description=f"Sensitive file {sensitive_path} is writable by others",
45
+ evidence=sensitive_path,
46
+ recommendation="Restrict permissions: chmod o-w {sensitive_path}",
47
+ source_module=self.name
48
+ ))
49
+ else:
50
+ # Windows: Check if sensitive file has weak permissions
51
+ # This is a simplified check - in reality, Windows ACLs are more complex
52
+ try:
53
+ # Try to read the file - if we can, it might be too permissive
54
+ with open(sensitive_path, 'r', encoding='utf-8') as f:
55
+ f.read(1) # Try to read first byte
56
+ findings.append(Finding(
57
+ finding_id="FS-004",
58
+ title="Sensitive file with potentially weak permissions",
59
+ severity="MEDIUM",
60
+ description=f"Sensitive file {sensitive_path} may have overly permissive access",
61
+ evidence=sensitive_path,
62
+ recommendation="Review file permissions and ACLs",
63
+ source_module=self.name
64
+ ))
65
+ except (PermissionError, OSError):
66
+ # Good - file is properly protected
67
+ pass
68
+
69
+ except (OSError, PermissionError, FileNotFoundError):
70
+ continue
71
+
72
+ for root, _, files in os.walk(scan_path):
73
+ for f in files:
74
+ path = os.path.join(root, f)
75
+ try:
76
+ file_stat = os.stat(path)
77
+ mode = file_stat.st_mode
78
+
79
+ # World-writable files (Unix only)
80
+ if not is_windows():
81
+ if mode & stat.S_IWOTH:
82
+ findings.append(Finding(
83
+ finding_id="FS-001",
84
+ title="World-writable file",
85
+ severity="HIGH",
86
+ description="File is writable by others",
87
+ evidence=path,
88
+ recommendation="Restrict permissions: chmod o-w {path}",
89
+ source_module=self.name
90
+ ))
91
+
92
+ # SUID/SGID files (Unix only)
93
+ if mode & stat.S_ISUID:
94
+ findings.append(Finding(
95
+ finding_id="FS-006",
96
+ title="SUID executable",
97
+ severity="HIGH",
98
+ description="File has SUID bit set - runs with owner privileges",
99
+ evidence=path,
100
+ recommendation="Verify SUID bit is necessary and file is secure",
101
+ source_module=self.name
102
+ ))
103
+
104
+ if mode & stat.S_ISGID:
105
+ findings.append(Finding(
106
+ finding_id="FS-007",
107
+ title="SGID executable",
108
+ severity="MEDIUM",
109
+ description="File has SGID bit set - runs with group privileges",
110
+ evidence=path,
111
+ recommendation="Verify SGID bit is necessary and file is secure",
112
+ source_module=self.name
113
+ ))
114
+ else:
115
+ # Windows: Check for files in suspicious locations
116
+ if any(path.lower().startswith(temp_dir.lower()) for temp_dir in config['temp_dirs']):
117
+ findings.append(Finding(
118
+ finding_id="FS-001",
119
+ title="File in temporary directory",
120
+ severity="MEDIUM",
121
+ description="File located in temporary directory",
122
+ evidence=path,
123
+ recommendation="Review file - temporary directories are common attack vectors",
124
+ source_module=self.name
125
+ ))
126
+
127
+ # Hidden files (cross-platform)
128
+ if f.startswith(".") or (is_windows() and f.startswith("$")):
129
+ findings.append(Finding(
130
+ finding_id="FS-002",
131
+ title="Hidden file",
132
+ severity="MEDIUM",
133
+ description="Hidden file detected",
134
+ evidence=path,
135
+ recommendation="Review file contents",
136
+ source_module=self.name
137
+ ))
138
+
139
+ # Recently modified files (cross-platform)
140
+ mtime = os.path.getmtime(path)
141
+ if (time.time() - mtime) < (HIDDEN_FILE_DAYS * 86400):
142
+ findings.append(Finding(
143
+ finding_id="FS-003",
144
+ title="Recently modified file",
145
+ severity="LOW",
146
+ description=f"File modified in last {HIDDEN_FILE_DAYS} days",
147
+ evidence=path,
148
+ recommendation="Check if change is expected",
149
+ source_module=self.name
150
+ ))
151
+
152
+ except (OSError, PermissionError, FileNotFoundError):
153
+ continue
154
+
155
+ return findings
@@ -0,0 +1,115 @@
1
+ import psutil
2
+ import ipaddress
3
+ from sysvex.engine.models import Finding
4
+ from .base import BaseModule
5
+
6
+ # Common public service ports
7
+ PUBLIC_SERVICES = {
8
+ 20: "FTP Data", 21: "FTP Control", 22: "SSH", 23: "Telnet", 25: "SMTP",
9
+ 53: "DNS", 80: "HTTP", 110: "POP3", 143: "IMAP", 443: "HTTPS",
10
+ 993: "IMAPS", 995: "POP3S", 3389: "RDP", 5432: "PostgreSQL", 3306: "MySQL"
11
+ }
12
+
13
+ # Suspicious remote ports (commonly used in attacks)
14
+ SUSPICIOUS_PORTS = {
15
+ 4444: "Metasploit", 5555: "Android Debug", 6667: "IRC", 8080: "Proxy",
16
+ 8443: "Alternative HTTPS", 9000: "Alternative HTTP", 12345: "NetBus",
17
+ 31337: "Back Orifice", 5900: "VNC"
18
+ }
19
+
20
+ class Module(BaseModule):
21
+ name = "network"
22
+
23
+ def run(self, context=None):
24
+ findings = []
25
+
26
+ # Get listening ports
27
+ listening_ports = {}
28
+ for conn in psutil.net_connections(kind='inet'):
29
+ if conn.status == "LISTEN" and conn.laddr:
30
+ listening_ports[conn.laddr.port] = conn
31
+
32
+ # Get all current network connections
33
+ for conn in psutil.net_connections(kind='inet'):
34
+ laddr = f"{conn.laddr.ip}:{conn.laddr.port}" if conn.laddr else "N/A"
35
+ raddr = f"{conn.raddr.ip}:{conn.raddr.port}" if conn.raddr else "N/A"
36
+ status = conn.status
37
+
38
+ # High severity: listening on all interfaces for public services
39
+ if conn.status == "LISTEN" and conn.laddr and conn.laddr.ip == "0.0.0.0":
40
+ service_name = PUBLIC_SERVICES.get(conn.laddr.port, "Unknown service")
41
+ findings.append(Finding(
42
+ finding_id="NET-001",
43
+ title="Public service listening on all interfaces",
44
+ severity="HIGH",
45
+ description=f"{service_name} listening on 0.0.0.0:{conn.laddr.port}",
46
+ evidence=f"Local: {laddr}, Service: {service_name}",
47
+ recommendation="Bind service to specific IP or firewall if not intended for public",
48
+ source_module=self.name
49
+ ))
50
+
51
+ # Medium severity: unknown public services
52
+ if conn.status == "LISTEN" and conn.laddr and conn.laddr.port in PUBLIC_SERVICES:
53
+ service_name = PUBLIC_SERVICES[conn.laddr.port]
54
+ findings.append(Finding(
55
+ finding_id="NET-003",
56
+ title="Known public service detected",
57
+ severity="MEDIUM",
58
+ description=f"{service_name} service is running",
59
+ evidence=f"Local: {laddr}, Service: {service_name}",
60
+ recommendation="Ensure service is properly configured and secured",
61
+ source_module=self.name
62
+ ))
63
+
64
+ # High severity: connections to suspicious ports
65
+ if conn.status == "ESTABLISHED" and conn.raddr and conn.raddr.port in SUSPICIOUS_PORTS:
66
+ suspicious_service = SUSPICIOUS_PORTS[conn.raddr.port]
67
+ findings.append(Finding(
68
+ finding_id="NET-004",
69
+ title="Connection to suspicious port",
70
+ severity="HIGH",
71
+ description=f"Connection to {suspicious_service} service on port {conn.raddr.port}",
72
+ evidence=f"Local: {laddr}, Remote: {raddr}, Service: {suspicious_service}",
73
+ recommendation="Investigate potential malicious activity",
74
+ source_module=self.name
75
+ ))
76
+
77
+ # Medium severity: established connections to unknown remote addresses
78
+ if conn.status == "ESTABLISHED" and conn.raddr:
79
+ # Check if remote IP is public (not private)
80
+ if not self._is_private_ip(conn.raddr.ip):
81
+ findings.append(Finding(
82
+ finding_id="NET-002",
83
+ title="Established external connection",
84
+ severity="MEDIUM",
85
+ description="Connection established to remote host",
86
+ evidence=f"Local: {laddr}, Remote: {raddr}, Status: {status}",
87
+ recommendation="Verify connection is expected and authorized",
88
+ source_module=self.name
89
+ ))
90
+
91
+ # Low severity: unusual outbound connection patterns
92
+ if conn.status == "ESTABLISHED" and conn.raddr and conn.raddr.port > 1024:
93
+ if conn.raddr.port not in PUBLIC_SERVICES and conn.raddr.port not in SUSPICIOUS_PORTS:
94
+ findings.append(Finding(
95
+ finding_id="NET-005",
96
+ title="Unusual outbound connection",
97
+ severity="LOW",
98
+ description=f"Connection to non-standard port {conn.raddr.port}",
99
+ evidence=f"Local: {laddr}, Remote: {raddr}",
100
+ recommendation="Monitor for potential data exfiltration",
101
+ source_module=self.name
102
+ ))
103
+
104
+ return findings
105
+
106
+ def _is_private_ip(self, ip):
107
+ """Check if IP address is private"""
108
+ try:
109
+ ip_obj = ipaddress.ip_address(ip)
110
+ return ip_obj.is_private
111
+ except ValueError:
112
+ # Fallback to basic check for common private ranges
113
+ return (ip.startswith('10.') or ip.startswith('192.168.') or
114
+ ip.startswith('172.') or ip.startswith('127.') or
115
+ ip.startswith('169.254.'))
@@ -0,0 +1,165 @@
1
+ import psutil
2
+ from sysvex.engine.models import Finding
3
+ from .base import BaseModule
4
+ from sysvex.utils.platform import get_platform_config, is_windows
5
+
6
+ class Module(BaseModule):
7
+ name = "processes"
8
+
9
+ def run(self, context=None):
10
+ config = get_platform_config()
11
+ findings = []
12
+
13
+ for proc in psutil.process_iter(['pid', 'name', 'exe', 'cmdline', 'username', 'uids', 'gids']):
14
+ try:
15
+ proc_info = proc.info
16
+
17
+ # Skip if we can't get basic info
18
+ if not proc_info['name'] or not proc_info['exe']:
19
+ continue
20
+
21
+ # Check for unsigned/unexpected binaries
22
+ if self._is_suspicious_binary(proc_info['exe'], config):
23
+ findings.append(Finding(
24
+ finding_id="PROC-001",
25
+ title="Suspicious or unsigned binary",
26
+ severity="HIGH",
27
+ description=f"Process running from suspicious location: {proc_info['exe']}",
28
+ evidence=f"PID: {proc_info['pid']}, Name: {proc_info['name']}, Path: {proc_info['exe']}",
29
+ recommendation="Investigate binary authenticity and origin",
30
+ source_module=self.name
31
+ ))
32
+
33
+ # Check for suspicious command-line patterns
34
+ if proc_info['cmdline']:
35
+ cmdline = ' '.join(proc_info['cmdline']).lower()
36
+ for pattern in config['suspicious_patterns']:
37
+ if pattern in cmdline:
38
+ findings.append(Finding(
39
+ finding_id="PROC-002",
40
+ title="Suspicious command-line pattern",
41
+ severity="HIGH",
42
+ description=f"Process with suspicious command line: {pattern}",
43
+ evidence=f"PID: {proc_info['pid']}, Command: {' '.join(proc_info['cmdline'])}",
44
+ recommendation="Investigate potential malicious activity",
45
+ source_module=self.name
46
+ ))
47
+ break # Only report once per process
48
+
49
+ # Check for privilege anomalies
50
+ if proc_info['uids'] and proc_info['gids']:
51
+ real_uid, effective_uid, saved_uid = proc_info['uids']
52
+ real_gid, effective_gid, saved_gid = proc_info['gids']
53
+
54
+ # Process running with elevated privileges (Unix: root, Windows: admin)
55
+ if is_windows():
56
+ # Windows: Check for SYSTEM or Administrator privileges
57
+ if effective_uid == 0 and not self._is_system_process(proc_info['name'], config):
58
+ findings.append(Finding(
59
+ finding_id="PROC-003",
60
+ title="Non-system process with elevated privileges",
61
+ severity="MEDIUM",
62
+ description=f"Process {proc_info['name']} running with elevated privileges",
63
+ evidence=f"PID: {proc_info['pid']}, Name: {proc_info['name']}, User: {proc_info['username']}",
64
+ recommendation="Verify if elevated privileges are necessary",
65
+ source_module=self.name
66
+ ))
67
+ else:
68
+ # Unix: Check for root privileges
69
+ if effective_uid == 0 and not self._is_system_process(proc_info['name'], config):
70
+ findings.append(Finding(
71
+ finding_id="PROC-003",
72
+ title="Non-system process running as root",
73
+ severity="MEDIUM",
74
+ description=f"Process {proc_info['name']} running with root privileges",
75
+ evidence=f"PID: {proc_info['pid']}, Name: {proc_info['name']}, User: {proc_info['username']}",
76
+ recommendation="Verify if root privileges are necessary",
77
+ source_module=self.name
78
+ ))
79
+
80
+ # SetUID/SetGID anomalies
81
+ if real_uid != effective_uid:
82
+ findings.append(Finding(
83
+ finding_id="PROC-004",
84
+ title="Process with elevated user privileges",
85
+ severity="HIGH",
86
+ description=f"Process running with different effective UID than real UID",
87
+ evidence=f"PID: {proc_info['pid']}, Real UID: {real_uid}, Effective UID: {effective_uid}",
88
+ recommendation="Investigate privilege escalation",
89
+ source_module=self.name
90
+ ))
91
+
92
+ if real_gid != effective_gid:
93
+ findings.append(Finding(
94
+ finding_id="PROC-005",
95
+ title="Process with elevated group privileges",
96
+ severity="MEDIUM",
97
+ description=f"Process running with different effective GID than real GID",
98
+ evidence=f"PID: {proc_info['pid']}, Real GID: {real_gid}, Effective GID: {effective_gid}",
99
+ recommendation="Investigate group privilege escalation",
100
+ source_module=self.name
101
+ ))
102
+
103
+ # Check for processes with no executable path (potential malware)
104
+ if not proc_info['exe'] and proc_info['name']:
105
+ findings.append(Finding(
106
+ finding_id="PROC-006",
107
+ title="Process without executable path",
108
+ severity="HIGH",
109
+ description=f"Process {proc_info['name']} has no associated executable",
110
+ evidence=f"PID: {proc_info['pid']}, Name: {proc_info['name']}",
111
+ recommendation="Investigate potential memory-only malware",
112
+ source_module=self.name
113
+ ))
114
+
115
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
116
+ continue
117
+
118
+ return findings
119
+
120
+ def _is_suspicious_binary(self, exe_path, config):
121
+ """Check if binary is in suspicious location or has suspicious characteristics"""
122
+ if not exe_path:
123
+ return True
124
+
125
+ # Common legitimate binary locations
126
+ legitimate_paths = config['legitimate_paths']
127
+
128
+ # Check if binary is in legitimate location
129
+ is_legitimate = any(exe_path.lower().startswith(path.lower()) for path in legitimate_paths)
130
+
131
+ # Check for temporary directories
132
+ suspicious_paths = config['temp_dirs']
133
+ is_suspicious = any(exe_path.lower().startswith(temp_dir.lower()) for temp_dir in suspicious_paths)
134
+
135
+ # Check for hidden directories
136
+ if "/." in exe_path and not is_legitimate:
137
+ is_suspicious = True
138
+
139
+ # Windows-specific hidden directory check
140
+ if is_windows() and ("\\." in exe_path or exe_path.startswith("\\\\?\\")):
141
+ is_suspicious = True
142
+
143
+ return is_suspicious or not is_legitimate
144
+
145
+ def _is_system_process(self, process_name, config):
146
+ """Check if process is a known system process"""
147
+ if not process_name:
148
+ return False
149
+
150
+ # Check against whitelist
151
+ for legitimate in config['legitimate_processes']:
152
+ if legitimate.lower() in process_name.lower():
153
+ return True
154
+
155
+ # Platform-specific checks
156
+ if is_windows():
157
+ # Windows system processes
158
+ if process_name.lower().endswith('.exe') and any(sys_proc in process_name.lower() for sys_proc in ['system', 'smss', 'csrss', 'wininit', 'services']):
159
+ return True
160
+ else:
161
+ # Unix kernel processes
162
+ if process_name.startswith('[') and process_name.endswith(']'):
163
+ return True
164
+
165
+ return False
@@ -0,0 +1,11 @@
1
+ def print_report(findings):
2
+ if not findings:
3
+ print("No issues found.")
4
+ return
5
+
6
+ for f in findings:
7
+ print(f"[{f.severity}] {f.title}")
8
+ print(f" -> {f.description}")
9
+ if f.evidence:
10
+ print(f" Evidence: {f.evidence}")
11
+ print()
@@ -0,0 +1,5 @@
1
+ import json
2
+
3
+ def export_json(findings, path="report.json"):
4
+ with open(path, "w", encoding="utf-8") as f:
5
+ json.dump([f.to_dict() for f in findings], f, indent=2)
File without changes
@@ -0,0 +1,104 @@
1
+ import platform as _platform
2
+ import os
3
+
4
+ def get_platform():
5
+ """Get the current platform name"""
6
+ return _platform.system().lower()
7
+
8
+ def is_windows():
9
+ """Check if running on Windows"""
10
+ return get_platform() == 'windows'
11
+
12
+ def is_linux():
13
+ """Check if running on Linux"""
14
+ return get_platform() == 'linux'
15
+
16
+ def is_macos():
17
+ """Check if running on macOS"""
18
+ return get_platform() == 'darwin'
19
+
20
+ def get_platform_config():
21
+ """Get platform-specific configuration"""
22
+ if is_windows():
23
+ return {
24
+ 'sensitive_paths': [
25
+ os.path.expandvars(r'%SystemRoot%\System32\config\SAM'),
26
+ os.path.expandvars(r'%SystemRoot%\System32\drivers\etc\hosts'),
27
+ os.path.expandvars(r'%SystemRoot%\System32\drivers\etc\networks'),
28
+ os.path.expandvars(r'%SystemRoot%\System32\config\SECURITY'),
29
+ os.path.expandvars(r'%ProgramData%\Microsoft\Network\Connections\Pbk\rasphone.pbk'),
30
+ ],
31
+ 'temp_dirs': [
32
+ os.path.expandvars(r'%TEMP%'),
33
+ os.path.expandvars(r'%TMP%'),
34
+ os.path.expandvars(r'%SystemRoot%\Temp'),
35
+ ],
36
+ 'legitimate_paths': [
37
+ os.path.expandvars(r'%SystemRoot%\System32'),
38
+ os.path.expandvars(r'%SystemRoot%\SysWOW64'),
39
+ os.path.expandvars(r'%ProgramFiles%'),
40
+ os.path.expandvars(r'%ProgramFiles(x86)%'),
41
+ os.path.expandvars(r'%ProgramData%'),
42
+ ],
43
+ 'suspicious_patterns': [
44
+ 'powershell -c', 'cmd /c', 'powershell.exe -enc',
45
+ 'rundll32.exe', 'regsvr32.exe', 'certutil.exe',
46
+ 'bitsadmin.exe', 'wmic.exe', 'netsh.exe',
47
+ 'schtasks.exe', 'sc.exe', 'wevtutil.exe'
48
+ ],
49
+ 'legitimate_processes': {
50
+ 'svchost.exe', 'lsass.exe', 'winlogon.exe', 'explorer.exe',
51
+ 'chrome.exe', 'firefox.exe', 'code.exe', 'python.exe',
52
+ 'java.exe', 'node.exe', 'powershell.exe', 'cmd.exe',
53
+ 'system', 'smss.exe', 'csrss.exe', 'wininit.exe'
54
+ }
55
+ }
56
+ else: # Linux/Unix/macOS
57
+ return {
58
+ 'sensitive_paths': [
59
+ '/etc/passwd', '/etc/shadow', '/etc/sudoers',
60
+ '/etc/ssh/sshd_config', '/etc/hosts', '/etc/crontab',
61
+ '/etc/gshadow', '/etc/group', '/etc/protocols'
62
+ ],
63
+ 'temp_dirs': [
64
+ '/tmp', '/var/tmp', '/dev/shm', '/run/user'
65
+ ],
66
+ 'legitimate_paths': [
67
+ '/usr/bin', '/usr/sbin', '/bin', '/sbin',
68
+ '/usr/local/bin', '/usr/local/sbin',
69
+ '/opt', '/snap', '/flatpak',
70
+ '/lib', '/lib64', '/usr/lib', '/usr/lib64'
71
+ ],
72
+ 'suspicious_patterns': [
73
+ 'nc -l', 'netcat', 'ncat', 'socat',
74
+ 'bash -i', 'sh -i', '/bin/sh', '/bin/bash',
75
+ 'python -c', 'perl -e', 'ruby -e',
76
+ 'wget', 'curl', 'fetch',
77
+ 'chmod +x', 'chmod 777',
78
+ 'nohup', 'screen', 'tmux',
79
+ 'iptables', 'ufw', 'firewall',
80
+ 'crontab', 'at', 'batch',
81
+ 'ssh-keygen', 'authorized_keys',
82
+ 'passwd', 'shadow', '/etc/passwd'
83
+ ],
84
+ 'legitimate_processes': {
85
+ 'init', 'kthreadd', 'ksoftirqd', 'migration', 'rcu_', 'watchdog',
86
+ 'systemd', 'kmod', 'udevd', 'NetworkManager', 'gdm', 'Xorg',
87
+ 'gnome-shell', 'firefox', 'chrome', 'chromium', 'code', 'vim',
88
+ 'bash', 'zsh', 'fish', 'python', 'python3', 'node', 'java'
89
+ }
90
+ }
91
+
92
+ def get_default_scan_path():
93
+ """Get default scan path for the current platform"""
94
+ if is_windows():
95
+ return os.path.expandvars(r'%TEMP%')
96
+ else:
97
+ return '/tmp'
98
+
99
+ def normalize_path(path):
100
+ """Normalize path for the current platform"""
101
+ if is_windows():
102
+ return os.path.normpath(path).replace('/', '\\')
103
+ else:
104
+ return os.path.normpath(path)
@@ -0,0 +1,5 @@
1
+ import psutil
2
+
3
+ def get_open_ports():
4
+ connections = psutil.net_connections()
5
+ return [c.laddr.port for c in connections if c.status == "LISTEN"]
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.4
2
+ Name: sysvex
3
+ Version: 0.1.0
4
+ Summary: Modular system security auditing toolkit
5
+ Author: PuRIToX
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/PuRiToX/sysvex
8
+ Project-URL: Repository, https://github.com/PuRiToX/sysvex
9
+ Project-URL: Documentation, https://github.com/PuRiToX/sysvex#readme
10
+ Project-URL: Bug Tracker, https://github.com/PuRiToX/sysvex/issues
11
+ Keywords: security,auditing,system,forensics,cross-platform
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: System Administrators
14
+ Classifier: Intended Audience :: Information Technology
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Security
21
+ Classifier: Topic :: System :: Systems Administration
22
+ Classifier: Topic :: System :: Monitoring
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: psutil
27
+ Dynamic: license-file
@@ -0,0 +1,25 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ pyproject.toml
4
+ src/sysvex/__init__.py
5
+ src/sysvex/cli.py
6
+ src/sysvex.egg-info/PKG-INFO
7
+ src/sysvex.egg-info/SOURCES.txt
8
+ src/sysvex.egg-info/dependency_links.txt
9
+ src/sysvex.egg-info/entry_points.txt
10
+ src/sysvex.egg-info/requires.txt
11
+ src/sysvex.egg-info/top_level.txt
12
+ src/sysvex/engine/__init__.py
13
+ src/sysvex/engine/loader.py
14
+ src/sysvex/engine/models.py
15
+ src/sysvex/engine/runner.py
16
+ src/sysvex/modules/__init__.py
17
+ src/sysvex/modules/base.py
18
+ src/sysvex/modules/filesystem.py
19
+ src/sysvex/modules/network.py
20
+ src/sysvex/modules/processes.py
21
+ src/sysvex/reporting/console.py
22
+ src/sysvex/reporting/json_report.py
23
+ src/sysvex/utils/__init__.py
24
+ src/sysvex/utils/platform.py
25
+ src/sysvex/utils/system.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sysvex = sysvex.cli:main
@@ -0,0 +1 @@
1
+ psutil
@@ -0,0 +1 @@
1
+ sysvex