@@ -20,6 +20,8 @@ def __init__(self, args, db, host):
2020 self .protocol = "SSH"
2121 self .remote_version = "Unknown SSH Version"
2222 self .server_os_platform = "Linux"
23+ self .shell_access = False
24+ self .admin_privs = False
2325 self .uac = ""
2426 super ().__init__ (args , db , host )
2527
@@ -77,11 +79,118 @@ def create_conn_obj(self):
7779 except OSError :
7880 return False
7981
80- def check_if_admin (self ):
81- self .admin_privs = False
82+ def plaintext_login (self , username , password , private_key = "" ):
83+ self .username = username
84+ self .password = password
85+ try :
86+ if self .args .key_file or private_key :
87+ self .logger .debug (f"Logging { self .host } with username: { username } , keyfile: { self .args .key_file } " )
88+ self .conn .connect (
89+ self .host ,
90+ port = self .port ,
91+ username = username ,
92+ passphrase = password if password != "" else None ,
93+ pkey = private_key ,
94+ key_filename = self .args .key_file ,
95+ timeout = self .args .ssh_timeout ,
96+ look_for_keys = False ,
97+ allow_agent = False ,
98+ banner_timeout = self .args .ssh_timeout ,
99+ )
100+ # If we get the private key from the file, we need to load it into the database
101+ if self .args .key_file :
102+ with open (self .args .key_file ) as f :
103+ private_key = f .read ().rstrip ("\n " )
104+ cred_id = self .db .add_credential ("key" , username , password , key = private_key )
105+ else :
106+ self .logger .debug (f"Logging { self .host } with username: { self .username } , password: { self .password } " )
107+ self .conn .connect (
108+ self .host ,
109+ port = self .port ,
110+ username = username ,
111+ password = password ,
112+ timeout = self .args .ssh_timeout ,
113+ look_for_keys = False ,
114+ allow_agent = False ,
115+ banner_timeout = self .args .ssh_timeout ,
116+ )
117+ cred_id = self .db .add_credential ("plaintext" , username , password )
82118
119+ self .check_shell (cred_id )
120+
121+ secret = process_secret (self .password ) if not self .args .key_file else f"{ process_secret (self .password )} (keyfile: { self .args .key_file } )"
122+ display_shell_access = f"{ self .uac } { self .server_os_platform } { ' - Shell access!' if self .shell_access else '' } "
123+ self .logger .success (f"{ self .username } :{ process_secret (secret )} { self .mark_pwned ()} { highlight (display_shell_access )} " )
124+ return True
125+ except AuthenticationException as e :
126+ if "Private key file is encrypted" in str (e ):
127+ self .logger .fail (f"{ username } :{ process_secret (password )} Could not load private key, error: { e } " )
128+ else :
129+ self .logger .fail (f"{ username } :{ process_secret (password )} " )
130+ except SSHException as e :
131+ if "Invalid key" in str (e ):
132+ self .logger .fail (f"{ username } :{ process_secret (password )} Could not decrypt private key, invalid password" )
133+ elif "Error reading SSH protocol banner" in str (e ):
134+ self .logger .error (f"Internal Paramiko error for { username } :{ process_secret (password )} , { e } " )
135+ else :
136+ self .logger .exception (e )
137+ except Exception as e :
138+ self .logger .exception (e )
139+ self .conn .close ()
140+ return False
141+
142+ def check_shell (self , cred_id ):
143+ host_id = self .db .get_hosts (self .host )[0 ].id
144+
145+ # Some IOT devices will not raise exception in self.conn._transport.auth_password / self.conn._transport.auth_publickey
146+ # Check Linux
147+ stdout = self .conn .exec_command ("id" )[1 ].read ().decode (self .args .codec , errors = "ignore" )
148+ if stdout :
149+ self .server_os_platform = "Linux"
150+ self .logger .debug (f"Linux detected for user: { stdout } " )
151+ self .shell_access = True
152+ self .db .add_loggedin_relation (cred_id , host_id , shell = self .shell_access )
153+ self .check_linux_priv ()
154+ if self .admin_privs :
155+ self .logger .debug (f"User { self .username } logged in successfully and is root!" )
156+ if self .args .key_file :
157+ self .db .add_admin_user ("key" , self .username , self .password , host_id = host_id , cred_id = cred_id )
158+ else :
159+ self .db .add_admin_user ("plaintext" , self .username , self .password , host_id = host_id , cred_id = cred_id )
160+ return
161+
162+ # Check Windows
163+ stdout = self .conn .exec_command ("whoami /priv" )[1 ].read ().decode (self .args .codec , errors = "ignore" )
164+ if stdout :
165+ self .server_os_platform = "Windows"
166+ self .logger .debug ("Windows detected" )
167+ self .shell_access = True
168+ self .db .add_loggedin_relation (cred_id , host_id , shell = self .shell_access )
169+ self .check_windows_priv (stdout )
170+ if self .admin_privs :
171+ self .logger .debug (f"User { self .username } logged in successfully and is admin!" )
172+ if self .args .key_file :
173+ self .db .add_admin_user ("key" , self .username , self .password , host_id = host_id , cred_id = cred_id )
174+ else :
175+ self .db .add_admin_user ("plaintext" , self .username , self .password , host_id = host_id , cred_id = cred_id )
176+ return
177+
178+ # No shell access
179+ self .shell_access = False
180+ self .logger .debug (f"User: { self .username } can't get a basic shell" )
181+ self .server_os_platform = "Network Devices"
182+ self .db .add_loggedin_relation (cred_id , host_id , shell = self .shell_access )
183+
184+ def check_windows_priv (self , stdout ):
185+ if "SeDebugPrivilege" in stdout :
186+ self .admin_privs = True
187+ elif "SeUndockPrivilege" in stdout :
188+ self .admin_privs = True
189+ self .uac = "with UAC - "
190+
191+ def check_linux_priv (self ):
83192 if self .args .sudo_check :
84- self .check_if_admin_sudo ()
193+ self .check_linux_priv_sudo ()
85194 return
86195
87196 # we could add in another method to check by piping in the password to sudo
@@ -108,7 +217,7 @@ def check_if_admin(self):
108217 self .logger .display (tips )
109218 return
110219
111- def check_if_admin_sudo (self ):
220+ def check_linux_priv_sudo (self ):
112221 if not self .password :
113222 self .logger .error ("Check admin with sudo does not support using a private key" )
114223 return
@@ -184,103 +293,6 @@ def check_if_admin_sudo(self):
184293 self .logger .error ("Command: 'mkfifo' unavailable, running command with 'sudo' failed" )
185294 return
186295
187- def plaintext_login (self , username , password , private_key = "" ):
188- self .username = username
189- self .password = password
190- stdout = None
191- try :
192- if self .args .key_file or private_key :
193- self .logger .debug (f"Logging { self .host } with username: { username } , keyfile: { self .args .key_file } " )
194-
195- self .conn .connect (
196- self .host ,
197- port = self .port ,
198- username = username ,
199- passphrase = password if password != "" else None ,
200- key_filename = private_key if private_key else self .args .key_file ,
201- timeout = self .args .ssh_timeout ,
202- look_for_keys = False ,
203- allow_agent = False ,
204- banner_timeout = self .args .ssh_timeout ,
205- )
206-
207- cred_id = self .db .add_credential (
208- "key" ,
209- username ,
210- password if password != "" else "" ,
211- key = private_key ,
212- )
213-
214- else :
215- self .logger .debug (f"Logging { self .host } with username: { self .username } , password: { self .password } " )
216- self .conn .connect (
217- self .host ,
218- port = self .port ,
219- username = username ,
220- password = password ,
221- timeout = self .args .ssh_timeout ,
222- look_for_keys = False ,
223- allow_agent = False ,
224- banner_timeout = self .args .ssh_timeout ,
225- )
226- cred_id = self .db .add_credential ("plaintext" , username , password )
227-
228- # Some IOT devices will not raise exception in self.conn._transport.auth_password / self.conn._transport.auth_publickey
229- _ , stdout , _ = self .conn .exec_command ("id" )
230- stdout = stdout .read ().decode (self .args .codec , errors = "ignore" )
231- except AuthenticationException :
232- self .logger .fail (f"{ username } :{ process_secret (password )} " )
233- except SSHException as e :
234- if "Invalid key" in str (e ):
235- self .logger .fail (f"{ username } :{ process_secret (password )} Could not decrypt private key, error: { e } " )
236- if "Error reading SSH protocol banner" in str (e ):
237- self .logger .error (f"Internal Paramiko error for { username } :{ process_secret (password )} , { e } " )
238- else :
239- self .logger .exception (e )
240- except Exception as e :
241- self .logger .exception (e )
242- self .conn .close ()
243- return False
244- else :
245- shell_access = False
246- host_id = self .db .get_hosts (self .host )[0 ].id
247-
248- if not stdout :
249- _ , stdout , _ = self .conn .exec_command ("whoami /priv" )
250- stdout = stdout .read ().decode (self .args .codec , errors = "ignore" )
251- self .server_os_platform = "Windows"
252- if "SeDebugPrivilege" in stdout :
253- self .admin_privs = True
254- elif "SeUndockPrivilege" in stdout :
255- self .admin_privs = True
256- self .uac = "with UAC - "
257-
258- if not stdout :
259- self .logger .debug (f"User: { self .username } can't get a basic shell" )
260- self .server_os_platform = "Network Devices"
261- shell_access = False
262- else :
263- shell_access = True
264-
265- self .db .add_loggedin_relation (cred_id , host_id , shell = shell_access )
266-
267- if shell_access and self .server_os_platform == "Linux" :
268- self .check_if_admin ()
269- if self .admin_privs :
270- self .logger .debug (f"User { username } logged in successfully and is root!" )
271- if self .args .key_file :
272- self .db .add_admin_user ("key" , username , password , host_id = host_id , cred_id = cred_id )
273- else :
274- self .db .add_admin_user ("plaintext" , username , password , host_id = host_id , cred_id = cred_id )
275-
276- if self .args .key_file :
277- password = f"{ process_secret (password )} (keyfile: { self .args .key_file } )"
278-
279- display_shell_access = f"{ self .uac } { self .server_os_platform } { ' - Shell access!' if shell_access else '' } "
280- self .logger .success (f"{ username } :{ process_secret (password )} { self .mark_pwned ()} { highlight (display_shell_access )} " )
281-
282- return True
283-
284296 def put_file_single (self , sftp_conn , src , dst ):
285297 self .logger .display (f'Copying "{ src } " to "{ dst } "' )
286298 try :
@@ -325,6 +337,6 @@ def execute(self, payload=None, get_output=False):
325337 else :
326338 self .logger .success ("Executed command" )
327339 if get_output :
328- for line in stdout .split ("\n " ):
340+ for line in stdout .replace ( " \r \n " , " \n " ). rstrip ( " \n " ). split ("\n " ):
329341 self .logger .highlight (line .strip ("\n " ))
330342 return stdout
0 commit comments