Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
2 changed files
with
284 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
""" | ||
Test of the code with Bcrypt hashes | ||
Almost exactly the same as the test_salted cases. | ||
But as Bcrypt deals with salts automagically, we dont really need to worry about that. | ||
""" | ||
|
||
import unittest | ||
import time | ||
import hashlib | ||
|
||
import bcrypt | ||
|
||
TARGETS = [b'$2b$12$CQdfZxhjQH83jY.RZNfGPegUWSL05J5Amekp5pmjXkAgvtuBynZzy', | ||
b'$2b$12$4YiyGckKJXQGKMkGwOqM5.JKTjJIMlwwdfHYHtLhfc38lFU9iZicK', | ||
b'$2b$12$8vMax8thp0D7G2yns8gY7unUmdZiiJKJrjhW7pRtoo.X4YDObRVCK', | ||
b'$2b$12$JE6BgAfbDdLgWNnMuaqyeuvhmXECqsnZPMXqO3Rv.pxrzT8Zn4wqy', | ||
b'$2b$12$YINaek/4qU8/k2egmjZxn.MYU7lVehNi8p94iEDFvM7MaS3BUlZKK'] | ||
|
||
CORRECT_WORDS = [b"coffee",b"azerty",b"spitfire", b"f00tball", b"1qazxsw23edc"] | ||
|
||
CORRECT_MATCHES = dict(zip(TARGETS, CORRECT_WORDS)) | ||
|
||
|
||
|
||
|
||
def crackHash_Salt(wordlist, target): | ||
""" | ||
This time we have a list of salted hashes. | ||
It means we can no longer take the approach we used before, of | ||
cracking all hashes and stashing in a dictionary. | ||
Instead we extract the salt, append it to each of the items in the wordlist | ||
Then check if we get a match | ||
""" | ||
|
||
|
||
#Go through the wordlist and get the hash for each item. | ||
for plaintext in wordlist: | ||
plaintext = plaintext.strip().encode() #Damn Bytestrings | ||
|
||
if bcrypt.checkpw(plaintext, target): | ||
return plaintext | ||
|
||
|
||
def crackList_Salt(wordlist, targets): | ||
""" | ||
Use the strategy above to crack a list of passowords that have been salted | ||
As we cant store we just iterate through the list, and collect the details | ||
""" | ||
|
||
matches = {} | ||
|
||
for item in targets: | ||
cracked = crackHash_Salt(wordlist, item) | ||
matches[item] = cracked | ||
|
||
return matches | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
class TestCases(unittest.TestCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
""" | ||
A bit of magic to keep the stats. | ||
Called the first time the class is run | ||
""" | ||
|
||
cls.statsDict = {} | ||
|
||
@classmethod | ||
def tearDownClass(cls): | ||
""" | ||
And a bit more magic to print the stats. | ||
""" | ||
|
||
print("\n\n{0} STATS (Bcrypt Salted) {0}".format("-"*20)) | ||
|
||
print("Crack Single Salted : {0}".format(cls.statsDict["singleSalt"])) | ||
print("Crack List of Salted: {0}".format(cls.statsDict["saltList"])) | ||
|
||
def setUp(self): | ||
""" | ||
Load the wordlist each time we run a test case | ||
Here we open the wordlist file, then store it as an array | ||
This lets us reuse the list multiple times | ||
""" | ||
|
||
with open("10-million-password-list-top-10000.txt") as fd: | ||
#Store as an array | ||
self.wordlist = fd.readlines() | ||
|
||
#SO I am going to cheat here and use a very abbreviated wordlist (Otherwis it takes forever) | ||
self.wordlist = ["foo","bar","coffee" ,"azerty","spitfire", "f00tball", "1qazxsw23edc"] | ||
|
||
def testSingle_ProperSalt(self): | ||
""" | ||
Check how long it takes to crack a single salted hash | ||
""" | ||
|
||
t1 = time.time() | ||
out = crackHash_Salt(self.wordlist, TARGETS[0]) | ||
t2 = time.time() | ||
out = out.decode() #Remember Bytes | ||
self.assertEqual(out, "coffee") #check we were successful (And remember Bytes here) | ||
self.statsDict["singleSalt"] = t2-t1 | ||
|
||
|
||
def testList_ProperSalt(self): | ||
""" | ||
And Crack a list of salted passwords | ||
""" | ||
t1 = time.time() | ||
out = crackList_Salt(self.wordlist, TARGETS) | ||
t2 = time.time() | ||
self.assertEqual(out, CORRECT_MATCHES) #check we were successful | ||
self.statsDict["saltList"] = t2-t1 | ||
|
||
|
||
|
||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
""" | ||
Test Cases and Demo code for Salted Hashed | ||
""" | ||
|
||
import unittest | ||
import time | ||
import hashlib | ||
|
||
TARGETS = ["rkKxLR$c35bf00b953186ec3be4916dd45deabc", | ||
"MyEtoS$b0a56a1df2353c7629509a12a17f5a2d", | ||
"kshhHk$9664b09bedf4ed95f1b7b024087cec12", | ||
"FMVbrf$6751d1e9a8ee57b383836596869cd94a", | ||
"wKBUOm$981132067d1a4ef9e943b8c300071a55" | ||
] | ||
|
||
CORRECT_WORDS = ["coffee","azerty","spitfire", "f00tball","1qazxsw23edc"] | ||
|
||
CORRECT_MATCHES = dict(zip(TARGETS, CORRECT_WORDS)) | ||
|
||
# CORRECT_MATCHES = {'283140d63e0937fb652ff7066bbf5c2f': 'coffee', | ||
# 'ba7c94b0431f30103c7eb5cdae180be6': 'azerty', | ||
# 'ff0e0cefdceb54618f47767d17b95a12': 'spitfire', | ||
# 'ef98a984f8ab1341039f9f3344d80298': 'f00tball', | ||
# '25e2262b5d8c95f7ece0bc4f30f5213d': '1qazxsw23edc'} | ||
|
||
|
||
|
||
def extractSalt(theHash): | ||
""" | ||
Break a Salted Hash into its compoenents. | ||
We are using the convention of <salt>$<hash> | ||
so can simply split on $ | ||
@return: Tuple of [salt, hash] | ||
""" | ||
|
||
return theHash.split("$") | ||
#And modify the function with lookups we used before | ||
|
||
|
||
def applySalt(plaintext, salt): | ||
""" | ||
Apply some Salt to the plaintext | ||
""" | ||
return "{0}{1}".format(plaintext, salt) | ||
|
||
def crackHash_Salt(wordlist, target): | ||
""" | ||
This time we have a list of salted hashes. | ||
It means we can no longer take the approach we used before, of | ||
cracking all hashes and stashing in a dictionary. | ||
Instead we extract the salt, append it to each of the items in the wordlist | ||
Then check if we get a match | ||
""" | ||
|
||
#Fetch the Salt from the first item | ||
theSalt, targetNoSalt = extractSalt(target) | ||
#print("Extract Salt {0} and Hash {1}".format(theSalt, targetNoSalt)) | ||
|
||
#Go through the wordlist and get the hash for each item. | ||
for plaintext in wordlist: | ||
plaintext = plaintext.strip() | ||
saltedText = applySalt(plaintext, theSalt) | ||
theHash = hashlib.md5(saltedText.encode()).hexdigest() | ||
#Store in the "Database" | ||
if theHash == targetNoSalt: | ||
return plaintext | ||
|
||
|
||
|
||
def crackList_Salt(wordlist, targets): | ||
""" | ||
Use the strategy above to crack a list of passowords that have been salted | ||
As we cant store we just iterate through the list, and collect the details | ||
""" | ||
|
||
matches = {} | ||
|
||
for item in targets: | ||
cracked = crackHash_Salt(wordlist, item) | ||
matches[item] = cracked | ||
|
||
return matches | ||
|
||
|
||
class TestCases(unittest.TestCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
""" | ||
A bit of magic to keep the stats. | ||
Called the first time the class is run | ||
""" | ||
|
||
cls.statsDict = {} | ||
|
||
@classmethod | ||
def tearDownClass(cls): | ||
""" | ||
And a bit more magic to print the stats. | ||
""" | ||
|
||
print("\n\n{0} STATS (Salted) {0}".format("-"*20)) | ||
|
||
print("Crack Single Salted : {0}".format(cls.statsDict["singleSalt"])) | ||
print("Crack List of Salted: {0}".format(cls.statsDict["saltList"])) | ||
|
||
def setUp(self): | ||
""" | ||
Load the wordlist each time we run a test case | ||
Here we open the wordlist file, then store it as an array | ||
This lets us reuse the list multiple times | ||
""" | ||
|
||
with open("10-million-password-list-top-10000.txt") as fd: | ||
#Store as an array | ||
self.wordlist = fd.readlines() | ||
|
||
|
||
def testSingle_ProperSalt(self): | ||
""" | ||
Check how long it takes to crack a single salted hash | ||
""" | ||
|
||
t1 = time.time() | ||
out = crackHash_Salt(self.wordlist, TARGETS[0]) | ||
t2 = time.time() | ||
self.assertEqual(out, "coffee") #check we were successful | ||
self.statsDict["singleSalt"] = t2-t1 | ||
|
||
|
||
def testList_ProperSalt(self): | ||
""" | ||
And Crack a list of salted passwords | ||
""" | ||
t1 = time.time() | ||
out = crackList_Salt(self.wordlist, TARGETS) | ||
t2 = time.time() | ||
self.assertEqual(out, CORRECT_MATCHES) #check we were successful | ||
self.statsDict["saltList"] = t2-t1 | ||
|
||
|
||
|