Skip to content

Instantly share code, notes, and snippets.

@3ch01c
Created February 21, 2019 03:30
Show Gist options
  • Save 3ch01c/1af4bda29b7da773815633dff8fd9127 to your computer and use it in GitHub Desktop.
Save 3ch01c/1af4bda29b7da773815633dff8fd9127 to your computer and use it in GitHub Desktop.
badhash
# For https://acmsigsec.mst.edu/ctf/badhash/
import random
from string import ascii_lowercase
import re
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
print("Let's map some possible first indices (i.e., a-z)...")
print("String length, index map (a-z)")
hashmap = []
for l in range(1,64):
m = []
for c in ascii_lowercase:
random.seed(ord(c))
i = random.randint(0,l-1)
m.append(i)
print("{:d}, {}".format(l, m))
hashmap.append([l, m])
#print(hashmap)
print("Isn't that interesting?")
ans = "616563636377616174726174776f6561"
print("We know the solution because there's a check for it: {:s}".format(ans))
# split the hext string into 2-char chunks, then hex2asc
n=2
ans2ba = [bytearray.fromhex(ans[i:i+n]).decode() for i in range(0, len(ans), n)]
print("Converted the hex string to char array: {}".format(ans2ba))
print("Now we're going to do an educated brute force...")
charset = set(ans2ba)
print("The password must be at least {:d} characters because we have that many unique characters in our hash.".format(len(charset)))
print("We're controlling the first letter in the password so if the unhash algorithm tries to change the first letter to something else, it's an invalid solution.")
print("If it doesn't put all of the letter back, it's an invalid solution.")
print("Any letter positions that don't get mapped, we'll just leave blank and see if we can fill in the blanks.")
print("Password length, [seed letter, password]")
unhashmap = []
n=16
# try password lengths from len(charset) to n
for l in range(len(charset),n):
#print("Let's assume {:d}-char password with our known letters {}...".format(l,charset))
#print("That's going to use the hash map {}".format(hashmap[7][1]))
m = []
# iterate starting letters
for seed in ascii_lowercase:
# p is our plaintext
p = ['_'] * l
# set the first letter in plaintext
p[0] = seed
# generate seed just like in the hash map
random.seed(ord(p[0]))
invalid = False
for enc in ans2ba:
# enc is the cth letter in p
c = random.randint(0,l-1)
# if enc is the 0th letter and it's not the same, it's an invalid solution
if (c == 0 and p[c] != enc):
invalid = True
break
else:
p[c] = enc
# check solution contains all the characters in hash
for a in charset:
if (not str.__contains__(''.join(p), a)):
invalid = True
if (not invalid):
# add the unhashed string to the list of possible solutions
m.append([seed,''.join(p)])
unhashmap.append([l,m])
# print out the solutions
for l in unhashmap:
print("Possible answers for {:d}-char password:".format(l[0]))
for p in l[1]:
print(" {}".format(p[1]))
'''
p = ''.join(ans2ba)
print("Let's try hashing {:s}...".format(p))
s = secure_hash(p)
print(s)
if s == ans:
print("correct!")
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment