3 # Interpret a file that crashes an fuzz_ndr_X binary.
5 # Copyright (C) Catalyst IT Ltd. 2019
10 from base64 import b64encode
16 TYPES = ['struct', 'in', 'out']
19 (4, 'ndr64', '--ndr64'),
23 def print_if_verbose(*args, **kwargs):
25 print(*args, **kwargs)
28 def process_one_file(f):
29 print_if_verbose(f.name)
30 print_if_verbose('-' * len(f.name))
33 flags, function = struct.unpack('<HH', b[:4])
34 if opnum is not None and opnum != function:
37 t = TYPES[flags & TYPE_MASK]
38 if ndr_type and ndr_type != t:
42 data64 = b64encode(payload).decode('utf-8')
52 for flag, name, option in FLAGS:
54 print_if_verbose("flag: %s" % name)
57 print_if_verbose("length: %d\n" % len(payload))
63 parser = argparse.ArgumentParser()
64 parser.add_argument('-p', '--pipe', default='$PIPE',
65 help='pipe name (for output command line)')
66 parser.add_argument('-t', '--type', default=None, choices=TYPES,
67 help='restrict to this type')
68 parser.add_argument('-o', '--opnum', default=None, type=int,
69 help='restrict to this function/struct number')
70 parser.add_argument('FILES', nargs='*', default=(),
71 help="read from these files")
72 parser.add_argument('-k', '--ignore-errors', action='store_true',
73 help='do not stop on errors')
74 parser.add_argument('-v', '--verbose', action='store_true',
76 parser.add_argument('-H', '--honggfuzz-file',
77 help="extract crashes from this honggfuzz report")
78 parser.add_argument('-f', '--crash-filter',
79 help="only print crashes matching this rexexp")
81 args = parser.parse_args()
83 global pipe, opnum, ndr_type, verbose
87 verbose = args.verbose
89 if not args.FILES and not args.honggfuzz_file:
94 if args.crash_filter is not None:
95 if not re.search(args.crash_filter, fn):
96 print_if_verbose(f"skipping {fn}")
100 process_one_file(sys.stdin)
102 with open(fn, 'rb') as f:
105 print_if_verbose("Error processing %s\n" % fn)
106 if args.ignore_errors:
110 if args.honggfuzz_file:
111 print_if_verbose(f"looking at {args.honggfuzz_file}")
112 with open(args.honggfuzz_file) as f:
116 m = re.match(r'^\s*fuzzTarget\s*:\s*bin/fuzz_ndr_(\w+)\s*$', line)
118 pipe = m.group(1).split('_TYPE_', 1)[0]
119 print_if_verbose(f"found pipe {pipe}")
120 m = re.match(r'^FUZZ_FNAME: (\S+)$', line)
123 if args.crash_filter is not None:
124 if not re.search(args.crash_filter, crash):
125 print_if_verbose(f"skipping {crash}")
129 print_if_verbose(f"found crash {crash}")
130 if pipe is not None and crash is not None:
131 with open(crash, 'rb') as f: