1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| ''' deepsound2john extracts password hashes from audio files containing encrypted data steganographically embedded by DeepSound (http://jpinsoft.net/deepsound/). This method is known to work with files created by DeepSound 2.0. Input files should be in .wav format. Hashes can be recovered from audio files even after conversion from other formats, e.g., ffmpeg -i input output.wav Usage: python3 deepsound2john.py carrier.wav > hashes.txt john hashes.txt This software is copyright (c) 2018 Ryan Govostes <rgovostes@gmail.com>, and it is hereby released to the general public under the following terms: Redistribution and use in source and binary forms, with or without modification, are permitted. '''
import logging import os import sys import textwrap
def decode_data_low(buf): return buf[::2]
def decode_data_normal(buf): out = bytearray() for i in range(0, len(buf), 4): out.append((buf[i] & 15) << 4 | (buf[i + 2] & 15)) return out
def decode_data_high(buf): out = bytearray() for i in range(0, len(buf), 8): out.append((buf[i] & 3) << 6 | (buf[i + 2] & 3) << 4 \ | (buf[i + 4] & 3) << 2 | (buf[i + 6] & 3)) return out
def is_magic(buf): return (buf[0] & 15) == (68 >> 4) and (buf[2] & 15) == (68 & 15) \ and (buf[4] & 15) == (83 >> 4) and (buf[6] & 15) == (83 & 15) \ and (buf[8] & 15) == (67 >> 4) and (buf[10] & 15) == (67 & 15) \ and (buf[12] & 15) == (70 >> 4) and (buf[14] & 15) == (70 & 15)
def is_wave(buf): return buf[0:4] == b'RIFF' and buf[8:12] == b'WAVE'
def process_deepsound_file(f): bname = os.path.basename(f.name) logger = logging.getLogger(bname)
buf = f.read(12) if not is_wave(buf): global convert_warn logger.error('file not in .wav format') convert_warn = True return f.seek(0, os.SEEK_SET)
hdrsz = 104 hdr = None
while True: off = f.tell() buf = f.read(hdrsz) if len(buf) < hdrsz: break
if is_magic(buf): hdr = decode_data_normal(buf) logger.info('found DeepSound header at offset %i', off) break
f.seek(-hdrsz + 1, os.SEEK_CUR)
if hdr is None: logger.warn('does not appear to be a DeepSound file') return
mode = hdr[4] encrypted = hdr[5]
modes = { 2: 'low', 4: 'normal', 8: 'high'} if mode in modes: logger.info('data is encoded in %s-quality mode', modes[mode]) else: logger.error('unexpected data encoding mode %i', modes[mode]) return
if encrypted == 0: logger.warn('file is not encrypted') return elif encrypted != 1: logger.error('unexpected encryption flag %i', encrypted) return
sha1 = hdr[6:6+20] print('%s:$dynamic_1529$%s' % (bname, sha1.hex()))
if __name__ == '__main__': import argparse
parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('files', nargs='+', metavar='file', type=argparse.FileType('rb', bufsize=4096)) args = parser.parse_args()
if args.verbose: logging.basicConfig(level=logging.INFO) else: logging.basicConfig(level=logging.WARN)
convert_warn = False
for f in args.files: process_deepsound_file(f)
if convert_warn: print(textwrap.dedent(''' --------------------------------------------------------------- Some files were not in .wav format. Try converting them to .wav and try again. You can use: ffmpeg -i input output.wav --------------------------------------------------------------- '''.rstrip()), file=sys.stderr)
|