source: sctry.py

Last change on this file was 505f39a, checked in by istevanoska <ilinastevanoska@…>, 6 months ago

Added OAuth/prototype

  • Property mode set to 100644
File size: 18.3 KB
LineĀ 
1#!/usr/bin/env python3
2"""
3netIntel Client (Fixed + more reliable)
4- Sends payload to /receive with X-Env-Token header
5"""
6
7import socket
8import os
9import platform
10import json
11import requests
12from datetime import datetime
13import psutil
14import time
15import subprocess
16import getpass
17
18
19# ----------------------------
20# Helpers
21# ----------------------------
22def safe_username():
23 try:
24 return os.getlogin()
25 except Exception:
26 return getpass.getuser()
27
28
29def get_local_ip_fallback():
30 """
31 More reliable local IP than socket.gethostbyname(hostname).
32 """
33 try:
34 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
35 s.connect(("8.8.8.8", 80))
36 ip = s.getsockname()[0]
37 s.close()
38 return ip
39 except Exception:
40 try:
41 return socket.gethostbyname(socket.gethostname())
42 except Exception:
43 return "127.0.0.1"
44
45
46# ----------------------------
47# Sysmon-like collector (simulated)
48# ----------------------------
49class FixedSysmonCollector:
50 """Simplified collector - works even without Sysmon installed"""
51
52 def __init__(self):
53 self.last_collection = None
54
55 def collect_sysmon_events(self, limit=50):
56 events = []
57 now = datetime.now()
58
59 try:
60 # 1) Process events (Event ID 1)
61 for proc in psutil.process_iter(['pid', 'name', 'create_time', 'username']):
62 try:
63 pinfo = proc.info
64 ct = pinfo.get('create_time')
65 if ct:
66 create_time = datetime.fromtimestamp(ct)
67 if (not self.last_collection) or (create_time > self.last_collection):
68 events.append({
69 "event_id": 1,
70 "event_type": "Process Creation",
71 "message": f"Process created: {pinfo.get('name')} (PID: {pinfo.get('pid')}, User: {pinfo.get('username')})",
72 "timestamp": create_time.isoformat(),
73 "process_name": pinfo.get('name'),
74 "pid": pinfo.get('pid'),
75 "user": pinfo.get('username'),
76 })
77 except (psutil.NoSuchProcess, psutil.AccessDenied):
78 continue
79
80 if len(events) >= limit // 2:
81 break
82
83 # 2) Network connections (Event ID 3)
84 for conn in psutil.net_connections(kind='inet'):
85 try:
86 if conn.raddr and conn.status in ['ESTABLISHED', 'LISTEN']:
87 proc = psutil.Process(conn.pid) if conn.pid else None
88 events.append({
89 "event_id": 3,
90 "event_type": "Network Connection",
91 "message": f"Network {conn.status}: "
92 f"{conn.laddr.ip if conn.laddr else 'N/A'}:{conn.laddr.port if conn.laddr else 'N/A'} "
93 f"-> {conn.raddr.ip}:{conn.raddr.port}",
94 "timestamp": now.isoformat(),
95 "local_address": f"{conn.laddr.ip}:{conn.laddr.port}" if conn.laddr else None,
96 "remote_address": f"{conn.raddr.ip}:{conn.raddr.port}",
97 "status": conn.status,
98 "pid": conn.pid,
99 "process_name": proc.name() if proc else "Unknown",
100 })
101 except (psutil.NoSuchProcess, psutil.AccessDenied):
102 continue
103
104 if len(events) >= limit:
105 break
106
107 # 3) Performance alerts (optional)
108 cpu = psutil.cpu_percent(interval=0.1)
109 if cpu > 80:
110 events.append({
111 "event_id": "PERF_HIGH_CPU",
112 "event_type": "High CPU Usage",
113 "message": f"High CPU usage detected: {cpu:.1f}%",
114 "timestamp": now.isoformat(),
115 "cpu_percent": cpu
116 })
117
118 ram = psutil.virtual_memory()
119 if ram.percent > 85:
120 events.append({
121 "event_id": "PERF_HIGH_RAM",
122 "event_type": "High Memory Usage",
123 "message": f"High RAM usage: {ram.percent:.1f}%",
124 "timestamp": now.isoformat(),
125 "ram_percent": ram.percent
126 })
127
128 except Exception as e:
129 print(f"FixedSysmon error: {e}")
130
131 self.last_collection = now
132 return events
133
134 def collect_network_connections_detailed(self, limit=30):
135 connections = []
136 now = datetime.now().isoformat()
137
138 try:
139 for conn in psutil.net_connections(kind='inet'):
140 try:
141 proc = psutil.Process(conn.pid) if conn.pid else None
142 conn_info = {
143 "pid": conn.pid,
144 "status": conn.status,
145 "family": str(conn.family),
146 "type": str(conn.type),
147 "timestamp": now
148 }
149
150 if conn.laddr:
151 conn_info["local_address"] = f"{conn.laddr.ip}:{conn.laddr.port}"
152 conn_info["local_ip"] = conn.laddr.ip
153 conn_info["local_port"] = conn.laddr.port
154
155 if conn.raddr:
156 conn_info["remote_address"] = f"{conn.raddr.ip}:{conn.raddr.port}"
157 conn_info["remote_ip"] = conn.raddr.ip
158 conn_info["remote_port"] = conn.raddr.port
159
160 if proc:
161 conn_info["process_name"] = proc.name()
162 try:
163 cmd = proc.cmdline()
164 conn_info["process_cmdline"] = " ".join(cmd) if cmd else None
165 except Exception:
166 conn_info["process_cmdline"] = None
167 try:
168 conn_info["process_username"] = proc.username()
169 except Exception:
170 conn_info["process_username"] = None
171
172 connections.append(conn_info)
173
174 except (psutil.NoSuchProcess, psutil.AccessDenied):
175 continue
176
177 if len(connections) >= limit:
178 break
179
180 except Exception as e:
181 print(f"Network connections error: {e}")
182
183 return connections
184
185 def collect_all_security_data(self):
186 return {
187 "sysmon_events": self.collect_sysmon_events(limit=50),
188 "network_connections": self.collect_network_connections_detailed(limit=30),
189 "file_changes": [],
190 "collection_time": datetime.now().isoformat()
191 }
192
193
194# ----------------------------
195# Client
196# ----------------------------
197class EnhancedFixedClient:
198 def __init__(self, server_ip="192.168.1.13", port=5555, env_token=None):
199 self.server_ip = server_ip
200 self.port = port
201 self.computer_name = socket.gethostname()
202 self.user = safe_username()
203 self.sysmon_collector = FixedSysmonCollector()
204 self.env_token = env_token
205
206 # warmup cpu_percent so it doesn't start at 0
207 try:
208 psutil.cpu_percent(interval=None)
209 except Exception:
210 pass
211
212 def _check_sysmon_installed(self):
213 try:
214 if platform.system() == "Windows":
215 result = subprocess.run(
216 ["powershell", "-Command", "Get-Process -Name 'sysmon' -ErrorAction SilentlyContinue"],
217 capture_output=True, text=True
218 )
219 return result.returncode == 0
220 except Exception:
221 pass
222 return False
223
224 def get_performance_metrics(self):
225 try:
226 cpu_percent = psutil.cpu_percent(interval=0.5)
227 cpu_freq = psutil.cpu_freq()
228 ram = psutil.virtual_memory()
229 swap = psutil.swap_memory()
230 disk = psutil.disk_usage("C:/" if platform.system() == "Windows" else "/")
231
232 disk_read_mb = 0
233 disk_write_mb = 0
234 try:
235 disk_io = psutil.disk_io_counters()
236 if disk_io:
237 disk_read_mb = round(disk_io.read_bytes / (1024 ** 2), 2)
238 disk_write_mb = round(disk_io.write_bytes / (1024 ** 2), 2)
239 except Exception:
240 pass
241
242 net_io = psutil.net_io_counters()
243
244 boot_dt = datetime.fromtimestamp(psutil.boot_time())
245 uptime_hours = round((datetime.now() - boot_dt).total_seconds() / 3600, 2)
246
247 return {
248 "cpu_usage": cpu_percent,
249 "cpu_cores": psutil.cpu_count(logical=True),
250 "cpu_freq_current": cpu_freq.current if cpu_freq else 0,
251 "ram_usage": ram.percent,
252 "ram_total_gb": round(ram.total / (1024 ** 3), 2),
253 "ram_used_gb": round(ram.used / (1024 ** 3), 2),
254 "swap_usage": swap.percent if swap else 0,
255 "disk_usage": disk.percent,
256 "disk_total_gb": round(disk.total / (1024 ** 3), 2),
257 "disk_used_gb": round(disk.used / (1024 ** 3), 2),
258 "disk_read_mb": disk_read_mb,
259 "disk_write_mb": disk_write_mb,
260 "network_sent_mb": round(net_io.bytes_sent / (1024 ** 2), 2),
261 "network_recv_mb": round(net_io.bytes_recv / (1024 ** 2), 2),
262 "network_packets_sent": net_io.packets_sent,
263 "network_packets_recv": net_io.packets_recv,
264 "boot_time": boot_dt.strftime("%Y-%m-%d %H:%M:%S"),
265 "uptime_hours": uptime_hours
266 }
267 except Exception as e:
268 print(f"Performance metrics error: {e}")
269 return {}
270
271 def get_hardware_info(self):
272 try:
273 partitions = []
274 for partition in psutil.disk_partitions():
275 try:
276 usage = psutil.disk_usage(partition.mountpoint)
277 partitions.append({
278 "device": partition.device,
279 "mountpoint": partition.mountpoint,
280 "fstype": partition.fstype,
281 "total_gb": round(usage.total / (1024 ** 3), 2),
282 "used_gb": round(usage.used / (1024 ** 3), 2),
283 "free_gb": round(usage.free / (1024 ** 3), 2),
284 "percent_used": usage.percent
285 })
286 except Exception:
287 continue
288
289 net_if_addrs = psutil.net_if_addrs()
290 interfaces = {}
291 for interface, addrs in net_if_addrs.items():
292 interfaces[interface] = [
293 {
294 "family": str(addr.family),
295 "address": addr.address,
296 "netmask": getattr(addr, "netmask", None)
297 }
298 for addr in addrs if getattr(addr, "address", None)
299 ]
300
301 batt = None
302 try:
303 b = psutil.sensors_battery()
304 batt = b.percent if b else None
305 except Exception:
306 batt = None
307
308 return {
309 "cpu_physical_cores": psutil.cpu_count(logical=False),
310 "cpu_logical_cores": psutil.cpu_count(logical=True),
311 "disks": partitions,
312 "network_interfaces": interfaces,
313 "battery_percent": batt,
314 "temperatures": self._get_temperatures()
315 }
316 except Exception as e:
317 print(f"Hardware info error: {e}")
318 return {}
319
320 def _get_temperatures(self):
321 try:
322 temps = {}
323 if hasattr(psutil, "sensors_temperatures"):
324 sensors = psutil.sensors_temperatures()
325 for name, entries in sensors.items():
326 if entries:
327 temps[name] = entries[0].current
328 return temps
329 except Exception:
330 return {}
331
332 def get_detailed_processes(self, limit=100):
333 processes = []
334 try:
335 for proc in psutil.process_iter(['pid', 'name', 'username', 'cpu_percent', 'memory_percent',
336 'create_time', 'status']):
337 try:
338 pinfo = proc.info
339 with proc.oneshot():
340 processes.append({
341 "pid": pinfo.get("pid"),
342 "name": pinfo.get("name"),
343 "user": pinfo.get("username"),
344 "cpu_percent": pinfo.get("cpu_percent"),
345 "memory_mb": round(proc.memory_info().rss / (1024 ** 2), 2),
346 "memory_percent": pinfo.get("memory_percent"),
347 "create_time": datetime.fromtimestamp(pinfo["create_time"]).strftime("%Y-%m-%d %H:%M:%S")
348 if pinfo.get("create_time") else None,
349 "status": pinfo.get("status"),
350 "exe": proc.exe() if hasattr(proc, "exe") else None,
351 "cmdline": " ".join(proc.cmdline()) if hasattr(proc, "cmdline") else None,
352 "num_threads": proc.num_threads() if hasattr(proc, "num_threads") else None,
353 "connections_count": 0
354 })
355 except (psutil.NoSuchProcess, psutil.AccessDenied):
356 continue
357 except Exception:
358 continue
359
360 if len(processes) >= limit:
361 break
362
363 except Exception as e:
364 print(f"Process error: {e}")
365
366 return processes
367
368 def get_detailed_info(self):
369 info = {
370 "computer_name": self.computer_name,
371 "user": self.user,
372 "ip_address": get_local_ip_fallback(),
373 "os": f"{platform.system()} {platform.release()} {platform.version()}",
374 "architecture": platform.architecture()[0],
375 "timestamp": datetime.now().isoformat(),
376 "is_sysmon_available": self._check_sysmon_installed()
377 }
378 info.update(self.get_performance_metrics())
379 info.update(self.get_hardware_info())
380 return info
381
382 def collect_and_send(self):
383 print(f"\n[{datetime.now().strftime('%H:%M:%S')}] šŸ” Collecting...")
384
385 data = {
386 "info": self.get_detailed_info(),
387 "processes": self.get_detailed_processes(limit=100),
388 "security_data": self.sysmon_collector.collect_all_security_data(),
389 "collection_time": datetime.now().isoformat(),
390 "client_version": "2.2_fixed"
391 }
392
393 info = data["info"]
394 sec = data["security_data"]
395
396 print(f" šŸ’» {info.get('computer_name')} | šŸ‘¤ {info.get('user')}")
397 print(f" šŸ“Š CPU {info.get('cpu_usage', 0)}% | RAM {info.get('ram_usage', 0)}% | Disk {info.get('disk_usage', 0)}%")
398 print(f" šŸ”„ Processes: {len(data['processes'])}")
399 print(f" šŸ›”ļø Sysmon events: {len(sec.get('sysmon_events', []))}")
400 print(f" 🌐 Net conns: {len(sec.get('network_connections', []))}")
401
402 try:
403 headers = {}
404 if self.env_token:
405 headers["X-Env-Token"] = self.env_token
406 headers["X-Client-Id"] = self.computer_name # optional
407
408 url = f"http://{self.server_ip}:{self.port}/receive"
409 r = requests.post(url, json=data, headers=headers, timeout=30)
410
411 if r.ok:
412 resp = r.json()
413 print(" āœ… Sent OK")
414 if "sysmon_events_saved" in resp:
415 print(f" šŸ“ Saved sysmon: {resp['sysmon_events_saved']}")
416 return True
417
418 # errors
419 if r.status_code == 401:
420 try:
421 msg = r.json()
422 except Exception:
423 msg = {"error": r.text[:200]}
424 print(" šŸ”’ Token invalid/expired. Generate new token in Admin panel.")
425 print(f" Server says: {msg}")
426 else:
427 print(f" āŒ HTTP {r.status_code}: {r.text[:300]}")
428 return False
429
430 except Exception as e:
431 print(f" āŒ Connection problem: {e}")
432 return False
433
434
435def main():
436 print("=" * 70)
437 print("šŸ–„ļø netIntel Collector (Fixed)")
438 print("=" * 70)
439 print(f"Computer: {socket.gethostname()}")
440 print(f"User: {safe_username()}")
441 print(f"Local IP: {get_local_ip_fallback()}")
442 print("=" * 70)
443 print("Will send every 30 seconds. Ctrl+C to stop.")
444 print("=" * 70)
445
446 server_ip = input("Server IP (default 192.168.1.13): ").strip() or "192.168.1.13"
447 env_token = input("ENV TOKEN (from Admin panel): ").strip()
448 if not env_token:
449 print("āŒ ENV TOKEN is required.")
450 return
451
452 client = EnhancedFixedClient(server_ip, 5555, env_token=env_token)
453
454 print(f"\nšŸ”Œ Testing server {server_ip}...")
455 try:
456 r = requests.get(f"http://{server_ip}:5555/ping", timeout=5)
457 if r.ok:
458 print(" āœ… Server reachable")
459 else:
460 print(f" āš ļø Server responded: {r.status_code}")
461 except Exception as e:
462 print(f" āŒ Can't reach server: {e}")
463 return
464
465 try:
466 count = 1
467 while True:
468 print(f"\nšŸ“¤ Transmission #{count}")
469 client.collect_and_send()
470 count += 1
471
472 print("\nā³ Waiting 30s...")
473 for i in range(30, 0, -1):
474 if i % 10 == 0 or i <= 5:
475 print(f"\r {i} seconds remaining...", end="")
476 time.sleep(1)
477 print("\r" + " " * 40 + "\r", end="")
478
479 except KeyboardInterrupt:
480 print("\n\nšŸ›‘ Stopped.")
481 print(f"šŸ“Š Dashboard/API: http://{server_ip}:5555/")
482
483
484if __name__ == "__main__":
485 try:
486 import psutil # noqa
487 import requests # noqa
488 except ImportError:
489 print("Install modules:")
490 print("pip install psutil requests")
491 input("Press ENTER to exit...")
492 raise SystemExit(1)
493
494 main()
Note: See TracBrowser for help on using the repository browser.