From b9deab601c40d15deb7aa59d6b7573421c80c343 Mon Sep 17 00:00:00 2001 From: amironov Date: Mon, 20 Dec 2021 18:09:41 -0500 Subject: [PATCH 1/3] feature: Added text, csv, json ouput capability --- log4j-finder.py | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/log4j-finder.py b/log4j-finder.py index c2b6498..e2361b4 100755 --- a/log4j-finder.py +++ b/log4j-finder.py @@ -18,6 +18,7 @@ # Exclude files or directories: # $ python3 log4j-finder.py / --exclude "/*/.dontgohere" --exclude "/home/user/*.war" # +import json import os import io import sys @@ -243,7 +244,15 @@ def check_vulnerable(fobj, path_chain, stats, has_jndilookup=True): status = bold(color(status.upper())) md5sum = color(md5sum) comment = bold(color(comment)) - print(f"[{now}] {hostname} {status}: {path_chain} [{md5sum}: {comment}]") + + return { + 'timestamp': now, + 'hostname': hostname, + 'status': status, + 'path_chain': path_chain, + 'md5sum': md5sum, + 'comment': comment + } def print_summary(stats): @@ -300,6 +309,13 @@ def main(): help="exclude files/directories by pattern (can be used multiple times)", metavar='PATTERN' ) + parser.add_argument( + "-o", + "--output", + choices=['text', 'csv', 'json'], + default='text', + help="choose output format" + ) args = parser.parse_args() logging.basicConfig( format="%(asctime)s %(levelname)s %(message)s", @@ -316,6 +332,12 @@ def main(): global NO_COLOR NO_COLOR = True + if 'text' not in args.output: + NO_COLOR = True + args.quiet = True + args.no_banner = True + + summary = [] stats = collections.Counter() start_time = time.monotonic() hostname = magenta(HOSTNAME) @@ -336,7 +358,7 @@ def main(): if p.name.lower().endswith("JndiManager.class".lower()): lookup_path = p.parent.parent / "lookup/JndiLookup.class" has_lookup = lookup_path.exists() - check_vulnerable(fobj, [p], stats, has_lookup) + summary.append(check_vulnerable(fobj, [p], stats, has_lookup)) if p.suffix.lower() in JAR_EXTENSIONS: try: log.info(f"Found jar file: {p}") @@ -354,10 +376,25 @@ def main(): has_lookup = zfile.open(lookup_path.as_posix()) except KeyError: has_lookup = False - check_vulnerable(zf, parents + [zpath], stats, has_lookup) + summary.append(check_vulnerable(zf, parents + [zpath], stats, has_lookup)) except IOError as e: log.debug(f"{p}: {e}") + if 'text' in args.output: + for line in summary: + print( + f"[{line['timestamp']}] {line['hostname']} {line['status']}: {line['path_chain']} [{line['md5sum']}: {line['comment']}]" + ) + elif 'csv' in args.output: + for line in summary: + print( + f"{line['timestamp']};{line['hostname']};{line['status']};{line['path_chain']};{line['md5sum']};{line['comment']}" + ) + elif 'json' in args.output: + print(json.dumps(summary, default=str)) + else: + raise NameError('Unknown output parameter') + elapsed = time.monotonic() - start_time now = datetime.datetime.utcnow().replace(microsecond=0) if not args.quiet: From 3a38f8b3dd22726855e3cf3a9d0c40ae7a61ec58 Mon Sep 17 00:00:00 2001 From: amironov Date: Tue, 11 Jan 2022 22:11:55 -0500 Subject: [PATCH 2/3] added traces streaming + json_event type --- log4j-finder.py | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/log4j-finder.py b/log4j-finder.py index e2361b4..2df4ae8 100755 --- a/log4j-finder.py +++ b/log4j-finder.py @@ -269,6 +269,23 @@ def print_summary(stats): print(" Found {} unknown files".format(stats["unknown"])) +def process_traces(data, output_type, register): + if 'text' in output_type: + print( + f"[{data['timestamp']}] {data['hostname']} {data['status']}: {data['path_chain']} [{data['md5sum']}: {data['comment']}]" + ) + elif 'csv' in output_type: + print( + f"{data['timestamp']};{data['hostname']};{data['status']};{data['path_chain']};{data['md5sum']};{data['comment']}" + ) + elif 'json_event' in output_type: + print(json.dumps(data, default=str)) + elif 'json' in output_type: + register.append(data) + else: + raise NameError('Unknown output parameter') + + def main(): parser = argparse.ArgumentParser( description=f"%(prog)s v{__version__} - Find vulnerable log4j2 on filesystem (Log4Shell CVE-2021-4428, CVE-2021-45046, CVE-2021-45105)", @@ -312,7 +329,7 @@ def main(): parser.add_argument( "-o", "--output", - choices=['text', 'csv', 'json'], + choices=['text', 'csv', 'json_event', 'json'], default='text', help="choose output format" ) @@ -337,7 +354,7 @@ def main(): args.quiet = True args.no_banner = True - summary = [] + register = [] stats = collections.Counter() start_time = time.monotonic() hostname = magenta(HOSTNAME) @@ -358,7 +375,7 @@ def main(): if p.name.lower().endswith("JndiManager.class".lower()): lookup_path = p.parent.parent / "lookup/JndiLookup.class" has_lookup = lookup_path.exists() - summary.append(check_vulnerable(fobj, [p], stats, has_lookup)) + process_traces(check_vulnerable(fobj, [p], stats, has_lookup), args.output, register) if p.suffix.lower() in JAR_EXTENSIONS: try: log.info(f"Found jar file: {p}") @@ -376,24 +393,12 @@ def main(): has_lookup = zfile.open(lookup_path.as_posix()) except KeyError: has_lookup = False - summary.append(check_vulnerable(zf, parents + [zpath], stats, has_lookup)) + process_traces(check_vulnerable(zf, parents + [zpath], stats, has_lookup), args.output, register) except IOError as e: log.debug(f"{p}: {e}") - if 'text' in args.output: - for line in summary: - print( - f"[{line['timestamp']}] {line['hostname']} {line['status']}: {line['path_chain']} [{line['md5sum']}: {line['comment']}]" - ) - elif 'csv' in args.output: - for line in summary: - print( - f"{line['timestamp']};{line['hostname']};{line['status']};{line['path_chain']};{line['md5sum']};{line['comment']}" - ) - elif 'json' in args.output: - print(json.dumps(summary, default=str)) - else: - raise NameError('Unknown output parameter') + if register: + print(json.dumps(register, default=str)) elapsed = time.monotonic() - start_time now = datetime.datetime.utcnow().replace(microsecond=0) From a752a40db50081bc6441526e5984a0290a61c4dd Mon Sep 17 00:00:00 2001 From: amironov Date: Tue, 11 Jan 2022 22:31:45 -0500 Subject: [PATCH 3/3] Added --output key description to README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index bf4de57..ac6aae2 100644 --- a/README.md +++ b/README.md @@ -181,5 +181,8 @@ optional arguments: -e PATTERN, --exclude PATTERN exclude files/directories by pattern (can be used multiple times) (default: None) + -o FORMAT, --output FORMAT + output format for scan results: text, csv, json_event, + json (default: text) ``` Files are scanned recursively, both on disk and in (nested) Java Archive Files