#!/usr/bin/env python3
"""
FIXED SYSMON CLIENT - Sends data in correct format for server
"""
import socket
import os
import platform
import json
import requests
from datetime import datetime, timedelta
import psutil
import time
import re
import xml.etree.ElementTree as ET
class FixedSysmonClient:
def __init__(self, server_ip="192.168.1.13", port=5555):
self.server_ip = server_ip
self.port = port
self.computer_name = socket.gethostname()
self.user = os.getlogin()
self.event_types = self._init_event_types()
def _init_event_types(self):
return {
1: "Process Creation",
3: "Network Connection",
5: "Process Terminated",
7: "Image Loaded (DLL)",
11: "File Create",
12: "Registry Object added/deleted",
13: "Registry Value Set",
22: "DNS Query",
23: "File Delete"
}
def check_sysmon_installed(self):
try:
import win32evtlog
hand = win32evtlog.OpenEventLog("localhost", "Microsoft-Windows-Sysmon/Operational")
win32evtlog.CloseEventLog(hand)
return True
except:
return False
def parse_event_data_advanced(self, event):
try:
event_data = {}
if event.StringInserts:
for insert in event.StringInserts:
if insert:
try:
xml_string = insert.strip()
if not xml_string.startswith('<'):
continue
root = ET.fromstring(f"{xml_string}")
for data_elem in root.findall('.//Data'):
name = data_elem.get('Name')
value = data_elem.text
if name and value:
event_data[name] = value.strip()
except ET.ParseError:
pattern = r'([^<]*)'
matches = re.findall(pattern, str(insert))
for name, value in matches:
if name and value:
event_data[name] = value.strip()
return event_data
except Exception as e:
return {}
def get_all_sysmon_events(self, max_events=50):
events = []
if not self.check_sysmon_installed():
print(" ⚠️ Sysmon not installed")
return events
try:
import win32evtlog
hand = win32evtlog.OpenEventLog("localhost", "Microsoft-Windows-Sysmon/Operational")
flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
events_collected = 0
while events_collected < max_events:
events_batch = win32evtlog.ReadEventLog(hand, flags, 0)
if not events_batch:
break
for event in events_batch:
try:
event_id = event.EventID & 0xFFFF
event_type = self.event_types.get(event_id, f"Event {event_id}")
event_data = self.parse_event_data_advanced(event)
# Extract fields based on event type
event_entry = {
"event_id": event_id,
"event_type": event_type,
"timestamp": event.TimeGenerated.Format() if hasattr(event.TimeGenerated,
'Format') else str(
event.TimeGenerated),
"computer": self.computer_name,
"process": event_data.get("Image", ""),
"command_line": event_data.get("CommandLine", ""),
"user": event_data.get("User", ""),
"parent_process": event_data.get("ParentImage", ""),
"dns_query": event_data.get("QueryName", ""),
"dns_results": event_data.get("QueryResults", ""),
"source_ip": event_data.get("SourceIp", ""),
"destination_ip": event_data.get("DestinationIp", ""),
"destination_port": event_data.get("DestinationPort", ""),
"file_path": event_data.get("TargetFilename", ""),
"hash": event_data.get("Hashes", ""),
"registry_key": event_data.get("TargetObject", ""),
"registry_value": event_data.get("Details", ""),
"description": self.get_event_description(event_id, event_data),
"raw_data": json.dumps(event_data)
}
# Only add if meaningful
if any([
event_entry["process"],
event_entry["dns_query"],
event_entry["file_path"],
event_entry["destination_ip"]
]):
events.append(event_entry)
events_collected += 1
if events_collected >= max_events:
break
except Exception as e:
continue
win32evtlog.CloseEventLog(hand)
except Exception as e:
print(f" ❌ Error reading Sysmon: {e}")
return events
def get_event_description(self, event_id, event_data):
if event_id == 1:
proc = event_data.get("Image", "").split("\\")[-1] if event_data.get("Image") else "Unknown"
return f"Process started: {proc}"
elif event_id == 22:
return f"DNS query: {event_data.get('QueryName', 'Unknown')}"
elif event_id == 3:
return f"Network: {event_data.get('DestinationIp', 'Unknown')}"
elif event_id == 11:
file_name = event_data.get("TargetFilename", "").split("\\")[-1] if event_data.get(
"TargetFilename") else "Unknown"
return f"File created: {file_name}"
elif event_id == 23:
file_name = event_data.get("TargetFilename", "").split("\\")[-1] if event_data.get(
"TargetFilename") else "Unknown"
return f"File deleted: {file_name}"
else:
return f"Event {event_id}"
def get_system_info(self):
try:
return {
"computer_name": self.computer_name,
"user": self.user,
"hostname": socket.gethostname(),
"ip_address": socket.gethostbyname(self.computer_name) if hasattr(socket, 'gethostbyname') else "N/A",
"os": f"{platform.system()} {platform.release()}",
"cpu_usage": psutil.cpu_percent(interval=1),
"ram_usage": psutil.virtual_memory().percent,
"disk_usage": psutil.disk_usage("C:/").percent if os.name == 'nt' else 0,
"collection_time": datetime.now().isoformat()
}
except Exception as e:
return {"error": str(e)}
def get_running_processes(self):
processes = []
try:
for proc in psutil.process_iter(['pid', 'name', 'username']):
try:
with proc.oneshot():
processes.append({
"pid": proc.info['pid'],
"name": proc.info['name'],
"user": proc.info['username'] if proc.info['username'] else "N/A",
"cpu_percent": round(proc.cpu_percent(), 2),
"memory_mb": round(proc.memory_info().rss / (1024 ** 2), 2),
"cmdline": ' '.join(proc.cmdline())[:200] if proc.cmdline() else "",
"timestamp": datetime.now().isoformat()
})
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
if len(processes) >= 50:
break
except Exception as e:
print(f" ⚠️ Error collecting processes: {e}")
return processes
def collect_and_send(self):
print(f"\n[{datetime.now().strftime('%H:%M:%S')}] 🔍 Collecting data...")
try:
sysmon_installed = self.check_sysmon_installed()
print(f" 🔍 Sysmon: {'✅ Installed' if sysmon_installed else '❌ Not installed'}")
print(f" 📥 Collecting Sysmon events...")
events = self.get_all_sysmon_events(max_events=50)
print(f" 📥 Collecting system info...")
system_info = self.get_system_info()
print(f" 📥 Collecting processes...")
processes = self.get_running_processes()
# Prepare data in CORRECT format for server
data = {
"metadata": {
"computer": self.computer_name,
"user": self.user,
"timestamp": datetime.now().isoformat()
},
"events": events,
"system_info": system_info,
"processes": processes
}
print(f"\n 📊 STATISTICS:")
print(f" • Events: {len(events)}")
print(f" • Processes: {len(processes)}")
# Show samples
dns_events = [e for e in events if e.get("dns_query")]
file_events = [e for e in events if e.get("file_path")]
network_events = [e for e in events if e.get("destination_ip")]
if dns_events:
print(f"\n 🌐 DNS QUERIES ({len(dns_events)}):")
for dns in dns_events[:3]:
print(f" • {dns.get('dns_query')}")
if file_events:
print(f"\n 📁 FILE OPERATIONS ({len(file_events)}):")
for file_ev in file_events[:3]:
file_name = os.path.basename(file_ev.get("file_path", ""))
print(f" • {file_name}")
if network_events:
print(f"\n 🌍 NETWORK ({len(network_events)}):")
for net in network_events[:3]:
print(f" • {net.get('destination_ip')}:{net.get('destination_port')}")
print(f"\n 📤 Sending to server...")
return self.send_to_server(data)
except Exception as e:
print(f" ❌ Error: {e}")
import traceback
traceback.print_exc()
return False
def send_to_server(self, data):
try:
response = requests.post(
f"http://{self.server_ip}:{self.port}/receive_data",
json=data,
timeout=30,
headers={'Content-Type': 'application/json'}
)
if response.status_code == 200:
result = response.json()
print(f" ✅ Successfully sent!")
print(f" 📝 Server response: {result.get('message', 'Success')}")
print(f" 📊 Events inserted: {result.get('events_inserted', 0)}")
return True
else:
print(f" ❌ Server error {response.status_code}")
print(f" Response: {response.text[:200]}")
return False
except requests.exceptions.ConnectionError:
print(f" ❌ Cannot connect to server at {self.server_ip}:{self.port}")
return False
except Exception as e:
print(f" ❌ Error: {e}")
return False
def main():
print("=" * 70)
print("🛡️ FIXED SYSMON CLIENT")
print("=" * 70)
print(f"Computer: {socket.gethostname()}")
print(f"User: {os.getlogin()}")
print("=" * 70)
server_ip = input("Enter server IP (default 192.168.1.13): ").strip() or "192.168.1.13"
client = FixedSysmonClient(server_ip)
# Test connection
print(f"\n🔌 Testing connection to {server_ip}:5555...")
try:
response = requests.get(f"http://{server_ip}:5555/ping", timeout=5)
if response.status_code == 200:
print(f" ✅ Server is reachable!")
else:
print(f" ⚠️ Server responded with status {response.status_code}")
except Exception as e:
print(f" ⚠️ Cannot connect: {e}")
# Check pywin32
try:
import win32evtlog
print(f" ✅ pywin32 installed")
except ImportError:
print(f" ❌ pywin32 not installed - run: pip install pywin32")
input("Press ENTER to exit...")
return
interval = input("\nCollection interval in seconds (default 60): ").strip()
try:
interval = int(interval) if interval else 60
except:
interval = 60
try:
count = 1
while True:
print(f"\n" + "=" * 70)
print(f"📊 CYCLE #{count} - {datetime.now().strftime('%H:%M:%S')}")
print("=" * 70)
start_time = time.time()
client.collect_and_send()
elapsed = time.time() - start_time
print(f"\n ⏱️ Time: {elapsed:.2f} seconds")
count += 1
print(f"\n⏳ Waiting {interval} seconds...")
time.sleep(interval)
except KeyboardInterrupt:
print("\n\n🛑 Program stopped.")
print(f"📊 Dashboard: http://{server_ip}:5555/")
print("=" * 70)
if __name__ == "__main__":
required_modules = ["psutil", "requests"]
missing = []
for module in required_modules:
try:
__import__(module)
except ImportError:
missing.append(module)
if missing:
print(f"❌ Missing: {', '.join(missing)}")
print(f"Install: pip install {' '.join(missing)}")
if os.name == 'nt':
print("Also: pip install pywin32")
input("Press ENTER to exit...")
exit(1)
print("✅ All modules installed")
main()