1
0
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:
Jens Steube 2025-07-29 07:32:58 +02:00 committed by GitHub
commit def66c2098
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -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)