Pennyw0rth / NetExec

The Network Execution Tool
https://netexec.wiki/
BSD 2-Clause "Simplified" License
3.26k stars 358 forks source link

Exception with ssh if channel is closed during interaction #264

Open nikaiw opened 7 months ago

nikaiw commented 7 months ago

Describe the bug Exception triggered while connected to an ssh server

To Reproduce Steps to reproduce the behavior i.e.: Command: netexec ssh target -u username -p password Resulted in:

[12:44:51] ERROR    Exception while calling proto_flow() on target target: Channel closed.                                                                                                                            connection.py:128
         │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/connection.py:123 in __init__                                                                                                 │                  
                    │                                                                                                                                                                                                     │                  
                    │   120 │   │   │   sleep(value)                                                                                                                                                                      │                  
                    │   121 │   │                                                                                                                                                                                         │                  
                    │   122 │   │   try:                                                                                                                                                                                  │                  
                    │ ❱ 123 │   │   │   self.proto_flow()                                                                                                                                                                 │                  
                    │   124 │   │   except Exception as e:                                                                                                                                                                │                  
                    │   125 │   │   │   if "ERROR_DEPENDENT_SERVICES_RUNNING" in str(e):                                                                                                                                  │                  
                    │   126 │   │   │   │   self.logger.error(f"Exception while calling proto_flow() on target                                                                                                            │                  
                    │       {self.host}: {e}")                                                                                                                                                                            │                  
                    │                                                                                                                                                                                                     │                  
                    │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/protocols/ssh.py:34 in proto_flow                                                                                             │                  
                    │                                                                                                                                                                                                     │                  
                    │    31 │   │   │   if self.remote_version == "Unknown SSH Version":                                                                                                                                  │                  
                    │    32 │   │   │   │   self.conn.close()                                                                                                                                                             │                  
                    │    33 │   │   │   │   return                                                                                                                                                                        │                  
                    │ ❱  34 │   │   │   if self.login():                                                                                                                                                                  │                  
                    │    35 │   │   │   │   if hasattr(self.args, "module") and self.args.module:                                                                                                                         │                  
                    │    36 │   │   │   │   │   self.call_modules()                                                                                                                                                       │                  
                    │    37 │   │   │   │   else:                                                                                                                                                                         │                  
                    │                                                                                                                                                                                                     │                  
                    │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/connection.py:483 in login                                                                                                    │                  
                    │                                                                                                                                                                                                     │                  
                    │   480 │   │   if not self.args.no_bruteforce:                                                                                                                                                       │                  
                    │   481 │   │   │   for secr_index, secr in enumerate(secret):                                                                                                                                        │                  
                    │   482 │   │   │   │   for user_index, user in enumerate(username):                                                                                                                                  │                  
                    │ ❱ 483 │   │   │   │   │   if self.try_credentials(domain[user_index], user, owned[user_index],                                                                                                      │                  
                    │       secr, cred_type[secr_index], data[secr_index]):                                                                                                                                               │                  
                    │   484 │   │   │   │   │   │   owned[user_index] = True                                                                                                                                              │                  
                    │   485 │   │   │   │   │   │   if not self.args.continue_on_success:                                                                                                                                 │                  
                    │   486 │   │   │   │   │   │   │   return True                                                                                                                                                       │                  
                    │                                                                                                                                                                                                     │                  
                    │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/connection.py:421 in try_credentials                                                                                          │                  
                    │                                                                                                                                                                                                     │                  
                    │   418 │   │   │   │   │   return self.plaintext_login(domain, username, secret)                                                                                                                     │                  
                    │   419 │   │   │   │   elif self.args.protocol == "ssh":                                                                                                                                             │                  
                    │   420 │   │   │   │   │   self.logger.debug("Trying to authenticate using plaintext over SSH")                                                                                                      │                  
                    │ ❱ 421 │   │   │   │   │   return self.plaintext_login(username, secret, data)                                                                                                                       │                  
                    │   422 │   │   │   │   else:                                                                                                                                                                         │                  
                    │   423 │   │   │   │   │   self.logger.debug("Trying to authenticate using plaintext")                                                                                                               │                  
                    │   424 │   │   │   │   │   return self.plaintext_login(username, secret)                                                                                                                             │                  
                    │                                                                                                                                                                                                     │                  
                    │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/protocols/ssh.py:258 in plaintext_login                                                                                       │                  
                    │                                                                                                                                                                                                     │                  
                    │   255 │   │   │   self.db.add_loggedin_relation(cred_id, host_id, shell=shell_access)                                                                                                               │                  
                    │   256 │   │   │                                                                                                                                                                                     │                  
                    │   257 │   │   │   if shell_access and self.server_os_platform == "Linux":                                                                                                                           │                  
                    │ ❱ 258 │   │   │   │   self.check_if_admin()                                                                                                                                                         │                  
                    │   259 │   │   │   │   if self.admin_privs:                                                                                                                                                          │                  
                    │   260 │   │   │   │   │   self.logger.debug(f"User {username} logged in successfully and is                                                                                                         │                  
                    │       root!")                                                                                                                                                                                       │                  
                    │   261 │   │   │   │   │   if self.args.key_file:                                                                                                                                                    │                  
                    │                                                                                                                                                                                                     │                  
                    │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/protocols/ssh.py:87 in check_if_admin                                                                                         │                  
                    │                                                                                                                                                                                                     │                  
                    │    84 │   │   # we could add in another method to check by piping in the password to sudo                                                                                                           │                  
                    │    85 │   │   # but that might be too much of an opsec concern - maybe add in a flag to do                                                                                                          │                  
                    │       more checks?                                                                                                                                                                                  │                  
                    │    86 │   │   self.logger.info("Determined user is root via `id; sudo -ln` command")                                                                                                                │                  
                    │ ❱  87 │   │   _, stdout, _ = self.conn.exec_command("id; sudo -ln 2>&1")                                                                                                                            │                  
                    │    88 │   │   stdout = stdout.read().decode(self.args.codec, errors="ignore")                                                                                                                       │                  
                    │    89 │   │   admin_flag = {                                                                                                                                                                        │                  
                    │    90 │   │   │   "(root)": [True, None],                                                                                                                                                           │                  
                    │                                                                                                                                                                                                     │                  
                    │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/paramiko/client.py:566 in exec_command                                                                                            │                  
                    │                                                                                                                                                                                                     │                  
                    │   563 │   │   chan.settimeout(timeout)                                                                                                                                                              │                  
                    │   564 │   │   if environment:                                                                                                                                                                       │                  
                    │   565 │   │   │   chan.update_environment(environment)                                                                                                                                              │                  
                    │ ❱ 566 │   │   chan.exec_command(command)                                                                                                                                                            │                  
                    │   567 │   │   stdin = chan.makefile_stdin("wb", bufsize)                                                                                                                                            │                  
                    │   568 │   │   stdout = chan.makefile("r", bufsize)                                                                                                                                                  │                  
                    │   569 │   │   stderr = chan.makefile_stderr("r", bufsize)                                                                                                                                           │                  
                    │                                                                                                                                                                                                     │                  
                    │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/paramiko/channel.py:70 in _check                                                                                                  │                  
                    │                                                                                                                                                                                                     │                  
                    │     67 │   │   │   or not self.active                                                                                                                                                               │                  
                    │     68 │   │   ):                                                                                                                                                                                   │                  
                    │     69 │   │   │   raise SSHException("Channel is not open")                                                                                                                                        │                  
                    │ ❱   70 │   │   return func(self, *args, **kwds)                                                                                                                                                     │                  
                    │     71 │                                                                                                                                                                                            │                  
                    │     72 │   return _check                                                                                                                                                                            │                  
                    │     73                                                                                                                                                                                              │                  
                    │                                                                                                                                                                                                     │                  
                    │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/paramiko/channel.py:255 in exec_command                                                                                           │                  
                    │                                                                                                                                                                                                     │                  
                    │    252 │   │   m.add_string(command)                                                                                                                                                                │                  
                    │    253 │   │   self._event_pending()                                                                                                                                                                │                  
                    │    254 │   │   self.transport._send_user_message(m)                                                                                                                                                 │                  
                    │ ❱  255 │   │   self._wait_for_event()                                                                                                                                                               │                  
                    │    256 │                                                                                                                                                                                            │                  
                    │    257 │   @open_only                                                                                                                                                                               │                  
                    │    258 │   def invoke_subsystem(self, subsystem):                                                                                                                                                   │                  
                    │                                                                                                                                                                                                     │                  
                    │ /home/user/.local/pipx/venvs/netexec/lib/python3.10/site-packages/paramiko/channel.py:1224 in _wait_for_event                                                                                       │                  
                    │                                                                                                                                                                                                     │                  
                    │   1221 │   │   e = self.transport.get_exception()                                                                                                                                                   │                  
                    │   1222 │   │   if e is None:                                                                                                                                                                        │                  
                    │   1223 │   │   │   e = SSHException("Channel closed.")                                                                                                                                              │                  
                    │ ❱ 1224 │   │   raise e                                                                                                                                                                              │                  
                    │   1225 │                                                                                                                                                                                            │                  
                    │   1226 │   def _set_closed(self):                                                                                                                                                                   │                  
                    │   1227 │   │   # you are holding the lock.   

Expected behavior Exception suppressed from output

NetExec info

mpgn commented 7 months ago

possible solution for fix https://github.com/deepmodeling/dpdispatcher/commit/3736b9c2b91c48635bc112ddca28c22eb9bd85ce

NeffIsBack commented 6 months ago

@nikaiw any idea how this could be replicated?

nikaiw commented 6 months ago

This is happening because the first command executed on some sshd may trigger a channel close in paramiko if it doesn't exist.

This should be partially fixed with https://github.com/Pennyw0rth/NetExec/pull/292 I will ask paramiko devs if they want to improve this behavior

nikaiw commented 6 months ago

paramiko issue opened there: https://github.com/paramiko/paramiko/issues/2391