mirror of
https://github.com/hashcat/hashcat.git
synced 2025-08-04 12:56:00 +00:00
Merge pull request #4005 from ventaquil/code-cleanup-virtualbox
VirtualBox tool code cleanup
This commit is contained in:
commit
def66c2098
@ -1,80 +1,125 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Based on "pyvboxdie-cracker" (https://github.com/axcheron/pyvboxdie-cracker) (MIT license)
|
#
|
||||||
|
# Author......: See docs/credits.txt
|
||||||
|
# License.....: MIT
|
||||||
|
#
|
||||||
|
|
||||||
# Author: Gabriele 'matrix' Gristina
|
import binascii
|
||||||
# Version: 1.0
|
import struct
|
||||||
# Date: Sat 17 Jul 2021 05:36:37 PM CEST
|
from argparse import ArgumentParser
|
||||||
# License: MIT
|
from base64 import b64decode
|
||||||
|
from collections import namedtuple
|
||||||
|
from struct import Struct
|
||||||
|
from sys import stderr
|
||||||
|
from xml.dom import minidom
|
||||||
|
|
||||||
import argparse
|
SIGNATURE = "$vbox$0$"
|
||||||
import xml.dom.minidom
|
|
||||||
import base64
|
|
||||||
from struct import *
|
|
||||||
from binascii import hexlify
|
|
||||||
|
|
||||||
keystore_struct = {
|
KEY_STORE_PROPERTY_NAME = "CRYPT/KeyStore"
|
||||||
'FileHeader': None,
|
|
||||||
'Version': None,
|
|
||||||
'EVP_Algorithm': None,
|
|
||||||
'PBKDF2_Hash': None,
|
|
||||||
'Key_Length': None,
|
|
||||||
'Final_Hash': None,
|
|
||||||
'KL2_PBKDF2': None,
|
|
||||||
'Salt2_PBKDF2' : None,
|
|
||||||
'Iteration2_PBKDF2': None,
|
|
||||||
'Salt1_PBKDF2': None,
|
|
||||||
'Iteration1_PBKDF2': None,
|
|
||||||
'EVP_Length': None,
|
|
||||||
'Enc_Password': None
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse_keystore(file):
|
KEY_STORE_STRUCT_FMT = "<4sxb32s32sI32sI32sI32sII64s"
|
||||||
keystore = None
|
KEY_STORE_STRUCT = Struct(KEY_STORE_STRUCT_FMT)
|
||||||
|
|
||||||
|
KeyStore = namedtuple(
|
||||||
|
"KeyStore",
|
||||||
|
[
|
||||||
|
"FileHeader",
|
||||||
|
"Version",
|
||||||
|
"EVP_Algorithm",
|
||||||
|
"PBKDF2_Hash",
|
||||||
|
"Key_Length",
|
||||||
|
"Final_Hash",
|
||||||
|
"KL2_PBKDF2",
|
||||||
|
"Salt2_PBKDF2",
|
||||||
|
"Iteration2_PBKDF2",
|
||||||
|
"Salt1_PBKDF2",
|
||||||
|
"Iteration1_PBKDF2",
|
||||||
|
"EVP_Length",
|
||||||
|
"Enc_Password",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def print_warning(msg):
|
||||||
|
print("Warning!", msg + ".", file=stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def print_error(msg):
|
||||||
|
print("Error!", msg + "!", file=stderr)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def process_hard_disk(hard_disk):
|
||||||
|
props = hard_disk.getElementsByTagName("Property")
|
||||||
|
props = filter(lambda prop: prop.getAttribute("name") == KEY_STORE_PROPERTY_NAME, props)
|
||||||
try:
|
try:
|
||||||
fh_vbox = xml.dom.minidom.parse(file)
|
prop = next(props) # assuming there is only one key store property per hard disk
|
||||||
except IOError:
|
key_store = process_property(prop)
|
||||||
print('[-] Cannot open:', file)
|
except StopIteration:
|
||||||
exit(1)
|
return None
|
||||||
|
return key_store
|
||||||
|
|
||||||
hds = fh_vbox.getElementsByTagName("HardDisk")
|
|
||||||
|
|
||||||
# TODO - Clean up & exceptions
|
def process_property(property):
|
||||||
if len(hds) == 0:
|
if not property.hasAttribute("value"):
|
||||||
print('[-] No hard drive found')
|
raise RuntimeWarning("Malformed key store property")
|
||||||
exit(1)
|
key_store = property.getAttribute("value")
|
||||||
else:
|
try:
|
||||||
for disk in hds:
|
key_store = b64decode(key_store)
|
||||||
is_enc = disk.getElementsByTagName("Property")
|
key_store = KEY_STORE_STRUCT.unpack(key_store)
|
||||||
if is_enc:
|
key_store = KeyStore(*key_store)
|
||||||
data = disk.getElementsByTagName("Property")[1]
|
int(key_store.Key_Length)
|
||||||
keystore = data.getAttribute("value")
|
return key_store
|
||||||
|
except binascii.Error as error:
|
||||||
|
raise RuntimeError("Malformed Base64 payload in key store property") from error
|
||||||
|
except (ValueError, struct.error) as error:
|
||||||
|
raise RuntimeError("Malformed payload in key store property") from error
|
||||||
|
|
||||||
raw_ks = base64.decodebytes(keystore.encode())
|
|
||||||
unpkt_ks = unpack('<4sxb32s32sI32sI32sI32sII64s', raw_ks)
|
|
||||||
|
|
||||||
idx = 0
|
|
||||||
ks = keystore_struct
|
|
||||||
for key in ks.keys():
|
|
||||||
ks[key] = unpkt_ks[idx]
|
|
||||||
idx += 1
|
|
||||||
|
|
||||||
return ks
|
|
||||||
|
|
||||||
def pyvboxdie(vbox):
|
|
||||||
keystore = parse_keystore(vbox)
|
|
||||||
print("$vbox$0$" + str(keystore['Iteration1_PBKDF2']) + "$" + hexlify(keystore['Salt1_PBKDF2']).decode() + "$" + str(int(keystore['Key_Length'] / 4)) + "$" + hexlify(keystore['Enc_Password'][0:keystore['Key_Length']]).decode() + "$" + str(keystore['Iteration2_PBKDF2']) + "$" + hexlify(keystore['Salt2_PBKDF2']).decode() + "$" + hexlify(keystore['Final_Hash'].rstrip(b'\x00')).decode())
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="virtualbox2hashcat extraction tool")
|
parser = ArgumentParser(description="virtualbox2hashcat extraction tool")
|
||||||
parser.add_argument('--vbox', required=True, help='set virtualbox vbox file from path', type=str)
|
parser.add_argument("path", type=str, help="path to VirtualBox file")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.vbox:
|
try:
|
||||||
pyvboxdie(args.vbox)
|
document = minidom.parse(args.path)
|
||||||
else:
|
except IOError as error:
|
||||||
parser.print_help()
|
print_error("Cannot read a file: " + error.strerror)
|
||||||
exit(1)
|
|
||||||
|
hds = document.getElementsByTagName("HardDisk")
|
||||||
|
if len(hds) == 0:
|
||||||
|
print_error("No configured hard drives detected!")
|
||||||
|
|
||||||
|
key_stores = []
|
||||||
|
for hd in hds:
|
||||||
|
try:
|
||||||
|
key_store = process_hard_disk(hd)
|
||||||
|
if key_store is not None:
|
||||||
|
key_stores.append(key_store)
|
||||||
|
except RuntimeWarning as warning:
|
||||||
|
print_warning(warning)
|
||||||
|
except RuntimeError as error:
|
||||||
|
print_error(error)
|
||||||
|
if len(key_stores) == 0:
|
||||||
|
print_error("No valid key store found")
|
||||||
|
for key_store in key_stores:
|
||||||
|
key_length = int(key_store.Key_Length)
|
||||||
|
hash = (
|
||||||
|
SIGNATURE
|
||||||
|
+ str(key_store.Iteration1_PBKDF2)
|
||||||
|
+ "$"
|
||||||
|
+ key_store.Salt1_PBKDF2.hex()
|
||||||
|
+ "$"
|
||||||
|
+ str(key_length // 4) # key_length in bits divided by sizeof(u32) to get the length in 32-bit words
|
||||||
|
+ "$"
|
||||||
|
+ key_store.Enc_Password[:key_length].hex()
|
||||||
|
+ "$"
|
||||||
|
+ str(key_store.Iteration2_PBKDF2)
|
||||||
|
+ "$"
|
||||||
|
+ key_store.Salt2_PBKDF2.hex()
|
||||||
|
+ "$"
|
||||||
|
+ key_store.Final_Hash.rstrip(b"\x00").hex()
|
||||||
|
)
|
||||||
|
print(hash)
|
||||||
|
Loading…
Reference in New Issue
Block a user