snippetpythonMinor
Python hash format converter
Viewed 0 times
formatconverterpythonhash
Problem
This program should convert a file containing Mana, Hashcat or John the Ripper NTLMv1 hashes to another file containing Hashcat or John the Ripper hashes. Do you have any suggestions on how to make the code cleaner? The hash format selection code feels kinda dirty.
```
#!/usr/bin/env python3
# Takes a file of NTLMv1 hashes in mana format and spits out a
# file of hashes in JtR or hashcat format.
import sys
import re
class Hash():
pass
class HashcatHash(Hash):
@staticmethod
def parse(line):
m = re.match("(.*?)::::([0-9a-f]{48}):([0-9a-f]{16})", line)
if m:
return {"username": m.group(1), "response": m.group(2), "challenge": m.group(3)}
else:
raise ValueError("Couldn't find hash in line")
@staticmethod
def format(d):
return "{username}::::{response}:{challenge}".format(
username=d["username"],
response=d["response"],
challenge=d["challenge"])
class JohnHash(Hash):
@staticmethod
def parse(line):
m = re.match("(.*?):\$NETNTLM\$([0-9a-f]{16})\$([0-9a-f]{48})", line)
if m:
return {"username": m.group(1), "response": m.group(3), "challenge": m.group(2)}
else:
raise ValueError("Couldn't find hash in line")
@staticmethod
def format(d):
return "{username}:$NETNTLM${challenge}${response}".format(
username=d["username"],
response=d["response"],
challenge=d["challenge"])
class ManaHash(Hash):
@staticmethod
def parse(line):
m = re.match("CHAP\|(.*?)\|([0-9a-f:]{23})\|([0-9a-f:]{71})", line)
if m:
return {"username": m.group(1), "response": remove_colons(m.group(3)), "challenge": remove_colons(m.group(2))}
else:
raise ValueError("Couldn't find hash in line")
@staticmethod
def format(d):
raise NotImplementedError
def print_usage():
print("Usage:")
print("exportlog.py ")
d
```
#!/usr/bin/env python3
# Takes a file of NTLMv1 hashes in mana format and spits out a
# file of hashes in JtR or hashcat format.
import sys
import re
class Hash():
pass
class HashcatHash(Hash):
@staticmethod
def parse(line):
m = re.match("(.*?)::::([0-9a-f]{48}):([0-9a-f]{16})", line)
if m:
return {"username": m.group(1), "response": m.group(2), "challenge": m.group(3)}
else:
raise ValueError("Couldn't find hash in line")
@staticmethod
def format(d):
return "{username}::::{response}:{challenge}".format(
username=d["username"],
response=d["response"],
challenge=d["challenge"])
class JohnHash(Hash):
@staticmethod
def parse(line):
m = re.match("(.*?):\$NETNTLM\$([0-9a-f]{16})\$([0-9a-f]{48})", line)
if m:
return {"username": m.group(1), "response": m.group(3), "challenge": m.group(2)}
else:
raise ValueError("Couldn't find hash in line")
@staticmethod
def format(d):
return "{username}:$NETNTLM${challenge}${response}".format(
username=d["username"],
response=d["response"],
challenge=d["challenge"])
class ManaHash(Hash):
@staticmethod
def parse(line):
m = re.match("CHAP\|(.*?)\|([0-9a-f:]{23})\|([0-9a-f:]{71})", line)
if m:
return {"username": m.group(1), "response": remove_colons(m.group(3)), "challenge": remove_colons(m.group(2))}
else:
raise ValueError("Couldn't find hash in line")
@staticmethod
def format(d):
raise NotImplementedError
def print_usage():
print("Usage:")
print("exportlog.py ")
d
Solution
First of all, you can improve on reading the command-line arguments and, instead of manually parsing the
The format selection logic can be simplified if you would use a dictionary:
And, as a side note about defining the
sys.argv, use argparse module. Something like:import argparse
def parse_args():
"""Parses command-line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument('infile', type=argparse.FileType('r'))
parser.add_argument('informat', action='store', choices=HASH_FORMATS)
parser.add_argument('outfile', type=argparse.FileType('w'))
parser.add_argument('outformat', action='store', choices=HASH_FORMATS)
return parser.parse_args()
if __name__ == '__main__':
args = parse_args()
# ...The format selection logic can be simplified if you would use a dictionary:
HASH_FORMATS = {
'john': JohnHash,
'hashcat': HashcatHash,
'mana': ManaHash
}
# get the input and output hash classes beforehand
input_hash_class = HASH_FORMATS[args.informat]
output_hash_class = HASH_FORMATS[args.outformat]
for line in args.infile:
parsed_line = input_hash_class.parse(line)
converted_line = output_hash_class.format(parsed_line)
args.outfile.write(converted_line)And, as a side note about defining the
Hash-based classes - I think you can make use of Abstract Base Classes with abstract methods which may lead to a cleaner object-oriented design.Code Snippets
import argparse
def parse_args():
"""Parses command-line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument('infile', type=argparse.FileType('r'))
parser.add_argument('informat', action='store', choices=HASH_FORMATS)
parser.add_argument('outfile', type=argparse.FileType('w'))
parser.add_argument('outformat', action='store', choices=HASH_FORMATS)
return parser.parse_args()
if __name__ == '__main__':
args = parse_args()
# ...HASH_FORMATS = {
'john': JohnHash,
'hashcat': HashcatHash,
'mana': ManaHash
}
# get the input and output hash classes beforehand
input_hash_class = HASH_FORMATS[args.informat]
output_hash_class = HASH_FORMATS[args.outformat]
for line in args.infile:
parsed_line = input_hash_class.parse(line)
converted_line = output_hash_class.format(parsed_line)
args.outfile.write(converted_line)Context
StackExchange Code Review Q#156460, answer score: 5
Revisions (0)
No revisions yet.