1- from impacket import smb , smb3
21import ntpath
3- from os import makedirs
4- from os .path import join , exists
5- from dploot . lib . smb import DPLootSMBConnection
6- from dploot . lib . target import Target
2+ import os
3+ from os .path import join , getsize , exists
4+ from nxc . paths import NXC_PATH
5+
76
87class NXCModule :
98
@@ -16,105 +15,120 @@ class NXCModule:
1615 def __init__ (self ):
1716 self .context = None
1817 self .module_options = None
18+ self .excluded_files = ["desktop.ini" ]
1919
2020 def options (self , context , module_options ):
21- """
22- USERS Download only specified user(s); format: -o USERS=user1,user2,user3
23- """
21+ """USERS: Download only specified user(s); format: -o USERS=user1,user2,user3"""
2422 self .context = context
25- self .screenshot_path_stub = r"Pictures\Screenshots"
26- self .users = module_options ["USERS" ].split ("," ) if "USERS" in module_options else None
23+ self .users = [user .lower () for user in module_options ["USERS" ].split ("," )] if "USERS" in module_options else None
24+
25+
2726
2827 def on_admin_login (self , context , connection ):
2928 self .context = context
3029 self .connection = connection
3130 self .share = "C$"
32-
33- host = f"{ connection .hostname } .{ connection .domain } "
34- domain = connection .domain
35- username = connection .username
36- kerberos = connection .kerberos
37- aesKey = connection .aesKey
38- use_kcache = getattr (connection , "use_kcache" , False )
39- password = getattr (connection , "password" , "" )
40- lmhash = getattr (connection , "lmhash" , "" )
41- nthash = getattr (connection , "nthash" , "" )
42-
43- target = Target .create (
44- domain = domain ,
45- username = username ,
46- password = password ,
47- target = host ,
48- lmhash = lmhash ,
49- nthash = nthash ,
50- do_kerberos = kerberos ,
51- aesKey = aesKey ,
52- use_kcache = use_kcache ,
53- )
54-
55- dploot_conn = self .upgrade_connection (target = target , connection = connection .conn )
56-
57- output_path = f"nxc_snipped_{ connection .host } "
58- context .log .debug ("Getting all user folders" )
31+
32+ output_base_dir = join (NXC_PATH , "modules" , "snipped" , "screenshots" )
33+ os .makedirs (output_base_dir , exist_ok = True )
34+
35+ context .log .info ("Getting all user folders" )
5936 try :
60- user_folders = dploot_conn .listPath (self .share , "\\ Users\\ *" )
37+ user_folders = connection . conn .listPath (self .share , "\\ Users\\ *" )
6138 except Exception as e :
6239 context .log .fail (f"Failed to list user folders: { e } " )
6340 return
6441
65- context .log .debug (f"User folders: { user_folders } " )
42+ context .log .info (f"User folders: { [ folder . get_longname () for folder in user_folders ] } " )
6643 if not user_folders :
6744 context .log .fail ("No User folders found!" )
6845 return
6946 else :
70- context .log .display ("Attempting to download screenshots if existent." )
47+ context .log .info ("Attempting to download screenshots if they exist." )
48+
49+ total_files_downloaded = 0
50+ host_output_path = None
7151
7252 for user_folder in user_folders :
73- if not user_folder .is_directory ():
74- continue
7553 folder_name = user_folder .get_longname ()
76- if folder_name in ["." , ".." , "All Users" , "Default" , "Default User" , "Public" ]:
77- continue
78- if self .users and folder_name not in self .users :
79- continue
80-
81- screenshot_path = ntpath .normpath (join (r"Users" , folder_name , self .screenshot_path_stub ))
82- try :
83- screenshot_files = dploot_conn .listPath (self .share , screenshot_path + "\\ *" )
84- except Exception as e :
85- context .log .debug (f"Screenshot folder { screenshot_path } not found for user { folder_name } : { e } " )
86- continue
87-
88- if not screenshot_files :
89- context .log .debug (f"No screenshots found in { screenshot_path } for user { folder_name } " )
90- continue
91-
92- user_output_dir = join (output_path , folder_name )
93- if not exists (user_output_dir ):
94- makedirs (user_output_dir )
95-
96- context .log .display (f"Downloading screenshots for user { folder_name } " )
97- downloaded_count = 0
98- for file in screenshot_files :
99- if file .is_directory ():
54+ if folder_name .lower () not in ["." , ".." , "all users" , "default" , "default user" , "public" ]:
55+ normalized_name = folder_name .lower ()
56+ if self .users and normalized_name not in self .users :
57+ continue
58+
59+ context .log .info (f"Searching for Screenshots folder in { folder_name } 's home directory" )
60+ screenshots_folders = self .find_screenshots_folders (folder_name )
61+ if not screenshots_folders :
62+ context .log .debug (f"No Screenshots folder found for user { folder_name } . Skipping." )
10063 continue
101- remote_file_path = ntpath .join (screenshot_path , file .get_longname ())
102- local_file_path = join (user_output_dir , file .get_longname ())
103- with open (local_file_path , 'wb' ) as local_file :
64+
65+ for screenshot_path in screenshots_folders :
10466 try :
105- context .log .debug (f"Downloading { remote_file_path } to { local_file_path } " )
106- dploot_conn .readFile (self .share , remote_file_path , local_file .write )
107- downloaded_count += 1
67+ screenshot_files = connection .conn .listPath (self .share , screenshot_path + "\\ *" )
10868 except Exception as e :
109- context .log .debug (f"Failed to download { remote_file_path } for user { folder_name } : { e } " )
69+ context .log .debug (f"Screenshot folder { screenshot_path } not found for user { folder_name } : { e } " )
11070 continue
11171
112- context .log .success (f"{ downloaded_count } screenshots for user { folder_name } downloaded to { user_output_dir } " )
72+ if not screenshot_files :
73+ context .log .debug (f"No screenshots found in { screenshot_path } for user { folder_name } " )
74+ continue
11375
114- def upgrade_connection (self , target : Target , connection = None ):
115- conn = DPLootSMBConnection (target )
116- if connection is not None :
117- conn .smb_session = connection
118- else :
119- conn .connect ()
120- return conn
76+ user_output_dir = join (output_base_dir , connection .host )
77+ os .makedirs (user_output_dir , exist_ok = True )
78+ host_output_path = user_output_dir
79+
80+ for file in screenshot_files :
81+ if not file .is_directory ():
82+ remote_file_name = file .get_longname ()
83+
84+ if remote_file_name .lower () in self .excluded_files :
85+ context .log .debug (f"Excluding file { remote_file_name } ." )
86+ continue
87+
88+ remote_file_path = ntpath .join (screenshot_path , remote_file_name )
89+ sanitized_path = screenshot_path .replace ("\\ " , "_" ).replace ("/" , "_" )
90+ local_file_name = f"{ folder_name } _{ sanitized_path } _{ remote_file_name } "
91+ local_file_path = join (user_output_dir , local_file_name )
92+
93+ try :
94+ with open (local_file_path , "wb" ) as local_file :
95+ context .log .debug (f"Downloading { remote_file_path } to { local_file_path } " )
96+ connection .conn .getFile (self .share , remote_file_path , local_file .write )
97+
98+ if not exists (local_file_path ):
99+ context .log .error (f"Downloaded file { local_file_path } does not exist." )
100+ continue
101+
102+ file_size = getsize (local_file_path )
103+ if file_size == 0 :
104+ context .log .error (f"Downloaded file { local_file_path } is 0 bytes. Skipping." )
105+ os .remove (local_file_path )
106+ else :
107+ total_files_downloaded += 1
108+ except Exception as e :
109+ context .log .debug (f"Failed to download { remote_file_path } for user { folder_name } : { e } " )
110+
111+ if total_files_downloaded > 0 and host_output_path :
112+ context .log .success (f"{ total_files_downloaded } file(s) downloaded from host { connection .host } to { host_output_path } ." )
113+
114+
115+ def find_screenshots_folders (self , user_folder_name ):
116+ """
117+ Dynamically searches for all Screenshots folders in the user's home directory.
118+ Returns a list of paths.
119+ """
120+ base_path = ntpath .normpath (join (r"Users" , user_folder_name ))
121+ screenshots_folders = []
122+ try :
123+ subfolders = self .connection .conn .listPath (self .share , base_path + "\\ *" )
124+ for subfolder in subfolders :
125+ if subfolder .is_directory () and subfolder .get_longname () not in ["." , ".." ]:
126+ potential_path = ntpath .join (base_path , subfolder .get_longname (), "Screenshots" )
127+ try :
128+ if self .connection .conn .listPath (self .share , potential_path + "\\ *" ):
129+ screenshots_folders .append (potential_path )
130+ except Exception :
131+ continue
132+ except Exception as e :
133+ self .context .log .debug (f"Failed to list subfolders for { base_path } : { e } " )
134+ return screenshots_folders
0 commit comments