Exception with ssh if channel is closed during interaction
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
- Version of nxc: 1.1.0 - nxc4u - 4e98f7b
possible solution for fix https://github.com/deepmodeling/dpdispatcher/commit/3736b9c2b91c48635bc112ddca28c22eb9bd85ce
@nikaiw any idea how this could be replicated?
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
paramiko issue opened there: https://github.com/paramiko/paramiko/issues/2391