33import subprocess
44import logging
55import ipaddress
6- from datetime import datetime
6+ from datetime import datetime , timedelta
77
88# Configure logging
99logging .basicConfig (level = logging .INFO , format = "%(asctime)s %(levelname)s: %(message)s" )
1010
1111OUTPUT_DIR = "data"
1212OUTPUT_FILE = os .path .join (OUTPUT_DIR , "data.json" )
1313
14- # Define suspicious ports often used by malware/trojans (example)
1514SUSPICIOUS_PORTS = {6667 , 31337 , 4444 , 5555 , 12345 , 27374 , 31338 }
15+ SUSPICIOUS_EXTENSIONS = {".dmg" , ".sh" , ".command" , ".app" , ".py" , ".pl" , ".rb" , ".exe" , ".jar" }
16+ # Directories to scan for suspicious files
17+ WATCHED_DIRS = [
18+ "/tmp" ,
19+ "/var/tmp" ,
20+ os .path .expanduser ("~/Library/Application Support" ),
21+ os .path .expanduser ("~/Downloads" ),
22+ ]
1623
1724def is_public_ip (ip ):
1825 try :
@@ -35,11 +42,6 @@ def parse_lsof():
3542 suspicious_endpoints = []
3643
3744 lines = output .strip ().split ("\n " )
38- header = lines [0 ]
39- cols = header .split ()
40- # Typical columns: COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
41- # We'll focus on COMMAND, PID, USER, NAME (last column has IP:port info)
42-
4345 for line in lines [1 :]:
4446 parts = line .split ()
4547 if len (parts ) < 9 :
@@ -48,10 +50,8 @@ def parse_lsof():
4850 command = parts [0 ]
4951 pid = parts [1 ]
5052 user = parts [2 ]
51- name = parts [- 1 ] # format like TCP 192.168.1.5:56789->198.51.100.23:80 (ESTABLISHED)
53+ name = parts [- 1 ]
5254
53- # Extract remote IP and port from NAME if possible
54- # Example: TCP 192.168.1.5:56789->198.51.100.23:80 (ESTABLISHED)
5555 if "->" not in name :
5656 continue
5757
@@ -66,7 +66,6 @@ def parse_lsof():
6666 except ValueError :
6767 continue
6868
69- # Check if remote_ip is public and port is suspicious
7069 if is_public_ip (remote_ip ) or remote_port in SUSPICIOUS_PORTS :
7170 suspicious_endpoints .append ({
7271 "timestamp" : datetime .utcnow ().isoformat () + "Z" ,
@@ -80,20 +79,73 @@ def parse_lsof():
8079
8180 return suspicious_endpoints
8281
82+ def check_suspicious_files ():
83+ """
84+ Scan WATCHED_DIRS for recently created suspicious files.
85+ """
86+ suspicious_files = []
87+ now = datetime .now ()
88+ lookback = now - timedelta (days = 1 ) # last 1 day
89+
90+ for directory in WATCHED_DIRS :
91+ if not os .path .exists (directory ):
92+ continue
93+
94+ logging .info (f"Scanning directory for suspicious files: { directory } " )
95+
96+ # Use find command to list files modified in last 1 day
97+ try :
98+ cmd = ["find" , directory , "-type" , "f" , "-mtime" , "-1" , "-print" ]
99+ output = subprocess .check_output (cmd , text = True )
100+ files = output .strip ().split ("\n " )
101+ except Exception as e :
102+ logging .error (f"Failed to scan directory { directory } : { e } " )
103+ continue
104+
105+ for filepath in files :
106+ if not filepath :
107+ continue
108+ _ , ext = os .path .splitext (filepath .lower ())
109+
110+ if ext in SUSPICIOUS_EXTENSIONS or any (s in filepath .lower () for s in ["temp" , "tmp" , "update" , "install" , "launch" ]):
111+ try :
112+ stat = os .stat (filepath )
113+ ctime = datetime .fromtimestamp (stat .st_ctime )
114+ if ctime < lookback :
115+ # Ignore files older than lookback anyway
116+ continue
117+ except Exception :
118+ ctime = None
119+
120+ suspicious_files .append ({
121+ "timestamp" : ctime .isoformat () + "Z" if ctime else None ,
122+ "filepath" : filepath ,
123+ "extension" : ext ,
124+ })
125+
126+ return suspicious_files
127+
83128def save_data_to_json (data , filepath ):
84129 os .makedirs (os .path .dirname (filepath ), exist_ok = True )
85130 with open (filepath , "w" , encoding = "utf-8" ) as f :
86131 json .dump (data , f , indent = 4 )
87- logging .info (f"Saved { len ( data ) } suspicious endpoints to { filepath } " )
132+ logging .info (f"Saved data to { filepath } " )
88133
89134def main ():
90- suspicious_data = parse_lsof ()
91- if suspicious_data :
92- logging .info (f"Found { len (suspicious_data )} suspicious network endpoints." )
93- save_data_to_json (suspicious_data , OUTPUT_FILE )
135+ network_suspicious = parse_lsof ()
136+ file_suspicious = check_suspicious_files ()
137+
138+ all_suspicious = {
139+ "network_suspicious_endpoints" : network_suspicious ,
140+ "suspicious_files_created" : file_suspicious ,
141+ }
142+
143+ if network_suspicious or file_suspicious :
144+ logging .info (f"Found { len (network_suspicious )} suspicious network endpoints and { len (file_suspicious )} suspicious files." )
94145 else :
95- logging .info ("No suspicious network endpoints found." )
146+ logging .info ("No suspicious network endpoints or file creations found." )
147+
148+ save_data_to_json (all_suspicious , OUTPUT_FILE )
96149
97150if __name__ == "__main__" :
98151 main ()
99-
0 commit comments