Skip to content

Conversation

@handewo
Copy link
Contributor

@handewo handewo commented Jun 12, 2025

This is the default behavior when openssh client connect to openssh server.
It improves the security as openssh described in PROTOCOL:

2.2. connection: disallow additional sessions extension
     "[email protected]"

Most SSH connections will only ever request a single session, but a
attacker may abuse a running ssh client to surreptitiously open
additional sessions under their control. OpenSSH provides a global
request "[email protected]" to mitigate this attack.

When an OpenSSH client expects that it will never open another session
(i.e. it has been started with connection multiplexing disabled), it
will send the following global request:

       byte            SSH_MSG_GLOBAL_REQUEST
       string          "[email protected]"
       char            want-reply

On receipt of such a message, an OpenSSH server will refuse to open
future channels of type "session" and instead immediately abort the
connection.

Note that this is not a general defence against compromised clients
(that is impossible), but it thwarts a simple attack.

here is minimal demo:

use russh::client;
use russh::client::Config;
use russh::keys::ssh_key;
use russh::ChannelMsg;

use log::info;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    env_logger::builder()
        .filter_level(log::LevelFilter::Debug)
        .init();
    let addrs = ("192.168.1.1", 22);

    let config = Config::default();
    let mut session = client::connect(Arc::new(config), addrs, Client).await?;

    let auth_ok = session.authenticate_password("root", "password").await?;
    if auth_ok != client::AuthResult::Success {
        anyhow::bail!("login failed")
    }

    let mut channel = session.channel_open_session().await?;
    channel.exec(true, "id").await?;
    session.no_more_sessions(true).await?;
    loop {
        if let Some(ChannelMsg::ExitStatus { exit_status }) = channel.wait().await {
            info!("exit status: {}", exit_status);
            break;
        }
    }
   // open session again
    let _channel = session.channel_open_session().await?;

    Ok(())
}

struct Client;

// #[async_trait]
impl client::Handler for Client {
    type Error = russh::Error;

    async fn check_server_key(
        &mut self,
        _server_public_key: &ssh_key::PublicKey,
    ) -> Result<bool, Self::Error> {
        Ok(true)
    }
}

Since the demo open session twice after send '"[email protected]" request. the connection is aborted by openssh server.
here is debug log:

...
[2025-06-12T05:44:45Z DEBUG russh::client] disconnected: ReceivedDisconnect(RemoteDisconnectInfo { reason_code: ProtocolError, message: "Possible attack: attempt to open a session after additional sessions disabled", lang_tag: "" })
...

@Eugeny Eugeny merged commit cfe45e5 into Eugeny:main Jun 12, 2025
8 checks passed
@Eugeny
Copy link
Owner

Eugeny commented Jun 12, 2025

Thank you!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants