1818# Exclude files or directories:
1919# $ python3 log4j-finder.py / --exclude "/*/.dontgohere" --exclude "/home/user/*.war"
2020#
21+ import json
2122import os
2223import io
2324import sys
@@ -243,7 +244,15 @@ def check_vulnerable(fobj, path_chain, stats, has_jndilookup=True):
243244 status = bold (color (status .upper ()))
244245 md5sum = color (md5sum )
245246 comment = bold (color (comment ))
246- print (f"[{ now } ] { hostname } { status } : { path_chain } [{ md5sum } : { comment } ]" )
247+
248+ return {
249+ 'timestamp' : now ,
250+ 'hostname' : hostname ,
251+ 'status' : status ,
252+ 'path_chain' : path_chain ,
253+ 'md5sum' : md5sum ,
254+ 'comment' : comment
255+ }
247256
248257
249258def print_summary (stats ):
@@ -300,6 +309,13 @@ def main():
300309 help = "exclude files/directories by pattern (can be used multiple times)" ,
301310 metavar = 'PATTERN'
302311 )
312+ parser .add_argument (
313+ "-o" ,
314+ "--output" ,
315+ choices = ['text' , 'csv' , 'json' ],
316+ default = 'text' ,
317+ help = "choose output format"
318+ )
303319 args = parser .parse_args ()
304320 logging .basicConfig (
305321 format = "%(asctime)s %(levelname)s %(message)s" ,
@@ -316,6 +332,12 @@ def main():
316332 global NO_COLOR
317333 NO_COLOR = True
318334
335+ if 'text' not in args .output :
336+ NO_COLOR = True
337+ args .quiet = True
338+ args .no_banner = True
339+
340+ summary = []
319341 stats = collections .Counter ()
320342 start_time = time .monotonic ()
321343 hostname = magenta (HOSTNAME )
@@ -336,7 +358,7 @@ def main():
336358 if p .name .lower ().endswith ("JndiManager.class" .lower ()):
337359 lookup_path = p .parent .parent / "lookup/JndiLookup.class"
338360 has_lookup = lookup_path .exists ()
339- check_vulnerable (fobj , [p ], stats , has_lookup )
361+ summary . append ( check_vulnerable (fobj , [p ], stats , has_lookup ) )
340362 if p .suffix .lower () in JAR_EXTENSIONS :
341363 try :
342364 log .info (f"Found jar file: { p } " )
@@ -354,10 +376,25 @@ def main():
354376 has_lookup = zfile .open (lookup_path .as_posix ())
355377 except KeyError :
356378 has_lookup = False
357- check_vulnerable (zf , parents + [zpath ], stats , has_lookup )
379+ summary . append ( check_vulnerable (zf , parents + [zpath ], stats , has_lookup ) )
358380 except IOError as e :
359381 log .debug (f"{ p } : { e } " )
360382
383+ if 'text' in args .output :
384+ for line in summary :
385+ print (
386+ f"[{ line ['timestamp' ]} ] { line ['hostname' ]} { line ['status' ]} : { line ['path_chain' ]} [{ line ['md5sum' ]} : { line ['comment' ]} ]"
387+ )
388+ elif 'csv' in args .output :
389+ for line in summary :
390+ print (
391+ f"{ line ['timestamp' ]} ;{ line ['hostname' ]} ;{ line ['status' ]} ;{ line ['path_chain' ]} ;{ line ['md5sum' ]} ;{ line ['comment' ]} "
392+ )
393+ elif 'json' in args .output :
394+ print (json .dumps (summary , default = str ))
395+ else :
396+ raise NameError ('Unknown output parameter' )
397+
361398 elapsed = time .monotonic () - start_time
362399 now = datetime .datetime .utcnow ().replace (microsecond = 0 )
363400 if not args .quiet :
0 commit comments