summaryrefslogtreecommitdiffstats
path: root/lib/fuzzing/decode_ndr_X_crash
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fuzzing/decode_ndr_X_crash')
-rwxr-xr-xlib/fuzzing/decode_ndr_X_crash137
1 files changed, 137 insertions, 0 deletions
diff --git a/lib/fuzzing/decode_ndr_X_crash b/lib/fuzzing/decode_ndr_X_crash
new file mode 100755
index 0000000..63c3cd7
--- /dev/null
+++ b/lib/fuzzing/decode_ndr_X_crash
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+#
+# Interpret a file that crashes an fuzz_ndr_X binary.
+#
+# Copyright (C) Catalyst IT Ltd. 2019
+
+
+import sys
+import os
+from base64 import b64encode
+import struct
+import argparse
+import re
+
+TYPE_MASK = 3
+TYPES = ['struct', 'in', 'out']
+
+FLAGS = [
+ (4, 'ndr64', '--ndr64'),
+]
+
+
+def print_if_verbose(*args, **kwargs):
+ if verbose:
+ print(*args, **kwargs)
+
+
+def process_one_file(f):
+ print_if_verbose(f.name)
+ print_if_verbose('-' * len(f.name))
+
+ b = f.read()
+ flags, function = struct.unpack('<HH', b[:4])
+ if opnum is not None and opnum != function:
+ return
+
+ t = TYPES[flags & TYPE_MASK]
+ if ndr_type and ndr_type != t:
+ return
+
+ payload = b[4:]
+ data64 = b64encode(payload).decode('utf-8')
+
+ cmd = ['bin/ndrdump',
+ pipe,
+ str(function),
+ t,
+ '--base64-input',
+ '--input', data64,
+ ]
+
+ for flag, name, option in FLAGS:
+ if flags & flag:
+ print_if_verbose("flag: %s" % name)
+ cmd.append(option)
+
+ print_if_verbose("length: %d\n" % len(payload))
+ print(' '.join(cmd))
+ print_if_verbose()
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-p', '--pipe', default='$PIPE',
+ help='pipe name (for output command line)')
+ parser.add_argument('-t', '--type', default=None, choices=TYPES,
+ help='restrict to this type')
+ parser.add_argument('-o', '--opnum', default=None, type=int,
+ help='restrict to this function/struct number')
+ parser.add_argument('FILES', nargs='*', default=(),
+ help="read from these files")
+ parser.add_argument('-k', '--ignore-errors', action='store_true',
+ help='do not stop on errors')
+ parser.add_argument('-v', '--verbose', action='store_true',
+ help='say more')
+ parser.add_argument('-H', '--honggfuzz-file',
+ help="extract crashes from this honggfuzz report")
+ parser.add_argument('-f', '--crash-filter',
+ help="only print crashes matching this rexexp")
+
+ args = parser.parse_args()
+
+ global pipe, opnum, ndr_type, verbose
+ pipe = args.pipe
+ opnum = args.opnum
+ ndr_type = args.type
+ verbose = args.verbose
+
+ if not args.FILES and not args.honggfuzz_file:
+ parser.print_usage()
+ sys.exit(1)
+
+ for fn in args.FILES:
+ if args.crash_filter is not None:
+ if not re.search(args.crash_filter, fn):
+ print_if_verbose(f"skipping {fn}")
+ continue
+ try:
+ if fn == '-':
+ process_one_file(sys.stdin)
+ else:
+ with open(fn, 'rb') as f:
+ process_one_file(f)
+ except Exception:
+ print_if_verbose("Error processing %s\n" % fn)
+ if args.ignore_errors:
+ continue
+ raise
+
+ if args.honggfuzz_file:
+ print_if_verbose(f"looking at {args.honggfuzz_file}")
+ with open(args.honggfuzz_file) as f:
+ pipe = None
+ crash = None
+ for line in f:
+ m = re.match(r'^\s*fuzzTarget\s*:\s*bin/fuzz_ndr_(\w+)\s*$', line)
+ if m:
+ pipe = m.group(1).split('_TYPE_', 1)[0]
+ print_if_verbose(f"found pipe {pipe}")
+ m = re.match(r'^FUZZ_FNAME: (\S+)$', line)
+ if m:
+ crash = m.group(1)
+ if args.crash_filter is not None:
+ if not re.search(args.crash_filter, crash):
+ print_if_verbose(f"skipping {crash}")
+ pipe = None
+ crash = None
+ continue
+ print_if_verbose(f"found crash {crash}")
+ if pipe is not None and crash is not None:
+ with open(crash, 'rb') as f:
+ process_one_file(f)
+ pipe = None
+ crash = None
+
+
+main()