Skip to content

Instantly share code, notes, and snippets.

@korc
Created December 7, 2016 22:36
Show Gist options
  • Save korc/81358735de3b2fa8cf14f109453bb957 to your computer and use it in GitHub Desktop.
Save korc/81358735de3b2fa8cf14f109453bb957 to your computer and use it in GitHub Desktop.
~/.ssh/known_hosts bruteforcer
#!/usr/bin/python
import Crypto.Hash.SHA, Crypto.Hash.HMAC
import sys, re, os
import getopt
import time
kh_re=re.compile(r'^\|1\|(?P<salt>[a-zA-Z0-9/+]+=*)\|(?P<hash>[a-zA-Z0-9/+]+=*) (?P<keytype>\S+) (?P<hostkey>[a-zA-Z0-9/+]+=*)$')
def read_kh(fname):
ret=[]
with open(fname) as kh:
for idx,line in enumerate(kh):
match=kh_re.match(line)
if not match: continue
item=match.groupdict()
item["index"]=idx
item['hmac']=Crypto.Hash.HMAC.new(item["salt"].decode("base64"), digestmod=Crypto.Hash.SHA)
item["hmac_target"]=item["hash"].decode("base64")
ret.append(item)
return ret
def find_key(test_key, known_hosts):
for row in known_hosts:
hmac=row["hmac"].copy()
hmac.update(test_key)
if hmac.digest()==row["hmac_target"]:
return row
def charrange(start,end):
return ''.join(map(chr,range(ord(start),ord(end)+1)))
class CharGen(object):
__slots__=['alphabet','index','maxlen','maxindex','result_converter']
def __init__(self,alphabet=charrange('a','z'), maxlen=None, maxindex=None):
self.alphabet=alphabet
self.index=1
self.maxlen=maxlen
self.maxindex=maxindex
self.result_converter=self.join_str
def __iter__(self):
while True:
y=self.get_value_by_index(self.index)
if self.maxlen is not None and len(y)>self.maxlen: break
if self.maxindex is not None and self.index>self.maxindex: break
yield y
self.index+=1
def reset(self): self.index=0
def get_value(self): return self.get_value_by_index(self.index)
def set_value(self, v): self.index=int(v)
value=property(get_value, set_value)
@staticmethod
def join_str(val): return ''.join(val)
def get_value_by_index(self,i):
if i<1: raise ValueError,"Index must be a positive integer"
div=i
ret=[]
while True:
div=div-1
div,mod=divmod(div,len(self.alphabet))
ret.insert(0,self.alphabet[mod])
if div==0: break
return self.result_converter(ret)
class IPGen(object):
max_value=(1<<32)-1
def get_value(self):
return self.__value
def set_value(self, val):
if isinstance(val, basestring):
val=reduce(lambda a,b: (a<<8) + int(b), val.split("."), 0)
self.__value=val
value=property(get_value, set_value)
def __init__(self, init_value="1.0.0.0"):
self.value=init_value
def __str__(self):
return ".".join(map(lambda z: str(0xff&(self.value>>z)), [24, 16, 8, 0]))
def __iter__(self):
while True:
yield str(self)
self.value+=1
if self.value>self.max_value:
break
if __name__=='__main__':
opts,args=getopt.getopt(sys.argv[1:], "is:f:h?")
gen_cls=CharGen
gen_start=None
kh_fname=os.path.expanduser("~/.ssh/known_hosts")
for opt,arg in opts:
if opt=="-i": gen_cls=IPGen
elif opt=="-s": gen_start=arg
elif opt=="-f": kh_fname=arg
elif opt in ("-h", "-?"):
print """Usage: %s [-f <known_hosts>] [-i] [-s <start_ip>] [test_names..]
-i makes bruteforcer use IP addresses
"""%(os.path.basename(sys.argv[0],))
raise SystemExit(0)
kh=read_kh(kh_fname)
tests=args
if not tests:
tests=gen_cls()
if gen_start is not None:
tests.value=gen_start
tm_start=time.time()
for k in tests:
tm_diff=time.time()-tm_start
if tm_diff>1: print "\x1b[Ktesting: %r .."%(k),
m=find_key(k, kh)
if m:
print "found", repr(k), "at line", m["index"]+1, "hash:", m["hash"]
kh=filter(lambda x: not x["hash"]==m["hash"], kh)
if not kh:
print "End of known_hosts"
break
else:
if tm_diff>1:
print "not found\r",
sys.stdout.flush()
if tm_diff>1:
tm_start=time.time()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment