Skip to content

fix(ssh): handle channel closed exception during shell and privilege checks#1136

Open
Marshall-Hallenbeck wants to merge 3 commits intomainfrom
fix/ssh-channel-closed-exception
Open

fix(ssh): handle channel closed exception during shell and privilege checks#1136
Marshall-Hallenbeck wants to merge 3 commits intomainfrom
fix/ssh-channel-closed-exception

Conversation

@Marshall-Hallenbeck
Copy link
Collaborator

@Marshall-Hallenbeck Marshall-Hallenbeck commented Mar 5, 2026

Description

Fixes #264 — SSH check_shell() and check_linux_priv() call exec_command without exception handling. When an SSH server closes the channel mid-command (e.g. certain IoT devices, VShell servers, or servers that reject specific commands), paramiko raises SSHException("Channel closed.") which propagates as an unhandled traceback.

This PR wraps the exec_command calls in check_shell() and check_linux_priv() with SSHException handlers. When a channel close occurs, the connection is treated as "no shell access" (same as if the commands returned empty output) rather than crashing.

The upstream paramiko issue (paramiko#2391) remains open with no fix, so handling this in our code is the right approach regardless.

This PR was created with the assistance of AI (Claude Code / claude-opus-4-6 — code review, implementation, and PR drafting).

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Deprecation of feature or functionality
  • This change requires a documentation update
  • This requires a third party update (such as Impacket, Dploot, lsassy, etc)
  • This PR was created with the assistance of AI (list what type of assistance, tool(s)/model(s) in the description)

Setup guide for the review

Bug reproduction:
You need an SSH server that closes the channel during command execution. This can happen with:

  • Certain IoT/embedded SSH servers
  • VShell servers (as described in paramiko#2391)
  • SSH servers with restricted shells that reject the id or sudo -ln commands

To trigger the original bug:

netexec ssh <target> -u <user> -p <password>

If the server closes the channel during check_shell(), you'll see:

ERROR  Exception while calling proto_flow() on target <target>: Channel closed.

After this fix, the connection completes normally and is reported as authenticated (without shell access).

Test environment:

  • Kali Linux, Python 3.13.11
  • Tested against Windows Server 2016 Datacenter via SSH
  • All 13 SSH e2e tests passed
  • All 36 unit tests passed

Screenshots (if appropriate):

Checklist:

  • I have ran Ruff against my changes (poetry: poetry run ruff check ., use --fix to automatically fix what it can)
  • I have added or updated the tests/e2e_commands.txt file if necessary (new modules or features are required to be added to the e2e tests)
  • If reliant on changes of third party dependencies, such as Impacket, dploot, lsassy, etc, I have linked the relevant PRs in those projects
  • I have linked relevant sources that describes the added technique (blog posts, documentation, etc)
  • I have performed a self-review of my own code (not an AI review)
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (PR here: https://github.com/Pennyw0rth/NetExec-Wiki)

…checks

Catch SSHException in check_shell() and check_linux_priv() so that SSH
servers that close channels mid-command no longer cause unhandled
tracebacks. Instead, the connection is treated as "no shell access".

Closes #264
@Marshall-Hallenbeck
Copy link
Collaborator Author

This just wraps the potentially failing code in a try to catch the error.

@Marshall-Hallenbeck Marshall-Hallenbeck marked this pull request as ready for review March 5, 2026 13:37
Copilot AI review requested due to automatic review settings March 5, 2026 13:37
@Marshall-Hallenbeck Marshall-Hallenbeck self-assigned this Mar 5, 2026
@Marshall-Hallenbeck Marshall-Hallenbeck added the bug-fix This Pull Request fixes a bug label Mar 5, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the SSH protocol implementation to avoid unhandled Paramiko SSHException("Channel closed.") errors during post-auth shell/privilege detection, so a channel close is treated as “no shell access” instead of crashing the run.

Changes:

  • Wrap exec_command calls in check_shell() with SSHException handling to prevent tracebacks when the server closes the channel mid-command.
  • Wrap the privilege probe in check_linux_priv() with SSHException handling to avoid crashes during sudo -ln checks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@NeffIsBack
Copy link
Member

@Marshall-Hallenbeck here are a few AI responses as well that have to be dealt with in some form

@Marshall-Hallenbeck
Copy link
Collaborator Author

@NeffIsBack OK this is good. I just split up the Linux and Windows exception catches and caught all exceptions and printed it because it could be anything from timeout to any various SSH error and if it errors on these simple commands we should just log and continue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix This Pull Request fixes a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Exception with ssh if channel is closed during interaction

3 participants