Created
February 22, 2019 21:35
-
-
Save 3ch01c/9902dc0d2c8b09faea5ee3da866aa5ab to your computer and use it in GitHub Desktop.
bad hash
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/local/bin/python3 | |
import random | |
from string import ascii_lowercase | |
import sys | |
import requests | |
def secure_hash(p): | |
l = len(p) | |
#print("Get the length of the plaintext: l = len('{:s}') = {:d}".format(p,l)) | |
random.seed(ord(p[0])) | |
#print("Generate seed: ord(p[0]) = ord({:s}) = {:d}".format(p[0],ord(p[0]))) | |
h = "" | |
for _ in range(16): | |
c = random.randint(0,l-1) | |
#print("Pick a random number c 0-len(p): c = random.randint(0,{:d}) = {:d}".format(l, c)) | |
#print("Pick p[c], and asc2hex it: p[{:d}] = {:s}, ord({:s}) = {:d}, hex({:d})[2:].zfill(2) = {:s}".format(c,p[c],p[c],ord(p[c]),ord(p[c]),hex(ord(p[c]))[2:].zfill(2))) | |
h += hex(ord(p[c]))[2:].zfill(2) | |
#print("Append that hex to our hash: {:s}".format(h)) | |
return h | |
# converts hex string to ASCII byte array | |
def h2ba(h): | |
n = 2 | |
return [bytearray.fromhex(h[i:i+n]).decode() for i in range(0, len(h), n)] | |
# Gets index of first character in hash for first plaintext character c for length l | |
def get_first_index(l): | |
m = [] | |
for c in ascii_lowercase: | |
random.seed(ord(c)) | |
i = random.randint(0,l-1) | |
m.append(i) | |
return m | |
#print("Let's map some possible first indices (i.e., a-z)...") | |
#print("String length, index map (a-z)") | |
indices = [] | |
for l in range(1,64): | |
indices.append([l,get_first_index(l)]) | |
for l in indices: | |
print("{:d} {}".format(l[0], l[1])) | |
#print("Isn't that interesting?") | |
# Returns a valid plaintext p or False for first letter f, length l, hash hex string h | |
def hack_the_hash(f, l, h): | |
p = ['_'] * l # p is plaintext of length l. | |
p[0] = f # we only know the first letter so the rest is just blanks for now | |
random.seed(ord(p[0])) # seed is the first letter in p | |
ba = h2ba(h) # convert hash string to char array | |
for e in ba: # for character e in char array | |
c = random.randint(0,l-1) # e is cth letter in p | |
if (p[c] != "_" and p[c] != e): return False # solution must not alter any letters | |
else: p[c] = e # set p[c] to e | |
#if (all(str.__contains__(''.join(p), a) for a in set(ba))) return False # solution must contain the set of chars in ba (unnecessary check) | |
return ''.join(p) # solution must match the hash | |
h = "616563636377616174726174776f6561" # the known valid hash | |
ba = h2ba(h) # hash converted to char array | |
charset = set(ba) # set of characters in char array | |
print("Known hash found in the code: {:s}".format(h)) | |
print("Converted solution from hex string to char array: {}".format(ba)) | |
print("Rules:") | |
print("* Plaintext must be have at least {:d} characters because the hash has that many unique characters.".format(len(charset))) | |
print("* Password must start with the first letter we pick.") | |
n = int(sys.argv[1]) if (len(sys.argv) > 1) else 28 | |
solutions = [] | |
for l in range(len(charset),n): # try password lengths from len(charset) to n | |
for f in ascii_lowercase: # iterate first letter | |
solution = hack_the_hash(f, l, h) | |
if (solution): solutions.append(solution) # add solution to solution set if valid | |
def ericwaswrongify(s): | |
return s.replace("____________", "ericwaswrong") | |
# print out the valid solutions | |
for solution in solutions: | |
solution = ericwaswrongify(solution) | |
print("{:s}".format(solution)) | |
r = requests.get('https://acmsigsec.mst.edu/ctf/badhash/?password={:s}'.format(solution)) | |
print(r.text) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment