From af1e837ab7bae4271f617b37d493de034718e718 Mon Sep 17 00:00:00 2001 From: programmerchad Date: Wed, 25 Apr 2018 18:33:51 -0400 Subject: [PATCH 1/3] Converted from python2 to python3 --- ParseLogs.py | 262 ++++++++++++++++++++++++++------------------------- logalyzer.py | 261 +++++++++++++++++++++++++------------------------- 2 files changed, 267 insertions(+), 256 deletions(-) diff --git a/ParseLogs.py b/ParseLogs.py index c373266..94ac3b9 100644 --- a/ParseLogs.py +++ b/ParseLogs.py @@ -1,149 +1,159 @@ -import re import gzip +import re + # # ParseLogs.py -# Parsing component of Logalyzer. Compiled in Python 2.6 +# Parsing component of Logalyzer. Original: https://github.com/hatRiot/logalyzer +# Converted to python3.6 by @cdombrowski # -# log object +# log object # Stuck into a dictionary by user:Log, where log houses # logs, fails, successes, logged IPs, and commands used class Log: - # dump date of first log - def first_date(self): - if len(self.logs) > 0: - date = None - i = 0 - # sometimes the first few aren't right, so look - # until we find one - while i < len(self.logs) and date is None: - date = ParseDate(self.logs[i]) - i += 1 - return date - # dump date of last log - def last_date(self): - if len(self.logs) > 0: - return ParseDate(self.logs[len(self.logs) - 1]) - def __init__(self, usr): - self.usr = usr - self.logs = [] - self.fail_logs = [] - self.succ_logs = [] - self.ips = [] - self.commands = [] + # dump date of first log + def first_date(self): + if len(self.logs) > 0: + date = None + i = 0 + # sometimes the first few aren't right, so look + # until we find one + while i < len(self.logs) and date is None: + date = ParseDate(self.logs[i]) + i += 1 + return date + + # dump date of last log + def last_date(self): + if len(self.logs) > 0: + return ParseDate(self.logs[len(self.logs) - 1]) + + def __init__(self, usr): + self.usr = usr + self.logs = [] + self.fail_logs = [] + self.succ_logs = [] + self.ips = [] + self.commands = [] + # parse user from various lines def ParseUsr(line): - usr = None - if "Accepted password" in line: - usr = re.search(r'(\bfor\s)(\w+)', line) - elif "sudo:" in line: - usr = re.search(r'(sudo:\s+)(\w+)', line) - elif "authentication failure" in line: - usr = re.search(r'USER=\w+', line) - elif "for invalid user" in line: - usr = re.search(r'(\buser\s)(\w+)', line) - if usr is not None: - return usr.group(2) + usr = None + if "Accepted password" in line: + usr = re.search(r'(\bfor\s)(\w+)', line) + elif "sudo:" in line: + usr = re.search(r'(sudo:\s+)(\w+)', line) + elif "authentication failure" in line: + usr = re.search(r'USER=\w+', line) + elif "for invalid user" in line: + usr = re.search(r'(\buser\s)(\w+)', line) + if usr is not None: + return usr.group(2) + # parse an IP from a line def ParseIP(line): - ip = re.search(r'(\bfrom\s)(\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b)', line) - if ip is not None: - return ip.group(2) + ip = re.search(r'(\bfrom\s)(\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b)', line) + if ip is not None: + return ip.group(2) + # parse a date from the line def ParseDate(line): - date = re.search(r'^[A-Za-z]{3}\s*[0-9]{1,2}\s[0-9]{1,2}:[0-9]{2}:[0-9]{2}', line) - if date is not None: - return date.group(0) + date = re.search(r'^[A-Za-z]{3}\s*[0-9]{1,2}\s[0-9]{1,2}:[0-9]{2}:[0-9]{2}', line) + if date is not None: + return date.group(0) + # parse a command from a line def ParseCmd(line): - # parse command to end of line - cmd = re.search(r'(\bCOMMAND=)(.+?$)', line) - if cmd is not None: - return cmd.group(2) + # parse command to end of line + cmd = re.search(r'(\bCOMMAND=)(.+?$)', line) + if cmd is not None: + return cmd.group(2) + # begin parsing the passed LOG -def ParseLogs(LOG): - # initialize the dictionary - logs = {} - - # parse the log - f = None - try: - f = gzip.open(LOG, 'r') if '.gz' in LOG else open(LOG, 'r') - log = f.read() - except Exception, e: - print '[-] Error opening \'%s\': %s'%(LOG,e) - return None - finally: - if f is not None: f.close() - - for line in log.split('\n'): - # match a login - if "Accepted password for" in line: - usr = ParseUsr(line) - - # add 'em if they don't exist - if not usr in logs: - logs[usr] = Log(usr) - - ip = ParseIP(line) - # set info - if not ip in logs[usr].ips: - logs[usr].ips.append(ip) - logs[usr].succ_logs.append(line.rstrip('\n')) - logs[usr].logs.append(line.rstrip('\n')) - - # match a failed login - elif "Failed password for" in line: - # parse user - usr = ParseUsr(line) - - if not usr in logs: - logs[usr] = Log(usr) - - ip = ParseIP(line) - - if not ip in logs[usr].ips: - logs[usr].ips.append(ip) - logs[usr].fail_logs.append(line.rstrip('\n')) - logs[usr].logs.append(line.rstrip('\n')) - - # match failed auth - elif ":auth): authentication failure;" in line: - # so there are three flavors of authfail we care about; - # su, sudo, and ssh. Lets parse each. - usr = re.search(r'(\blogname=)(\w+)', line) - if usr is not None: - usr = usr.group(2) - # parse a fail log to ssh - if "(sshd:auth)" in line: - # ssh doesn't have a logname hurr - usr = ParseUsr(line) - if not usr in logs: - logs[usr] = Log(usr) - logs[usr].ips.append(ParseIP(line)) - # parse sudo/su fails - else: - if not usr in logs: - logs[usr] = Log(usr) - logs[usr].fail_logs.append(line.rstrip('\n')) - logs[usr].logs.append(line.rstrip('\n')) - # match commands - elif "sudo:" in line: - # parse user - usr = ParseUsr(line) - if not usr in logs: - logs[usr] = Log(usr) - - cmd = ParseCmd(line) - # append the command if it isn't there already - if cmd is not None: - if not cmd in logs[usr].commands: - logs[usr].commands.append(cmd) - logs[usr].logs.append(line.rstrip('\n')) - return logs +def ParseLogs(log): + # initialize the dictionary + logs = {} + + # parse the log + f = None + try: + f = gzip.open(log, 'r') if '.gz' in log else open(log, 'r') + log = f.read() + except Exception as e: + print('[-] Error opening \'%s\': %s' % (log, e)) + return None + finally: + if f is not None: + f.close() + + for line in log.split('\n'): + # match a login + if "Accepted password for" in line: + usr = ParseUsr(line) + + # add 'em if they don't exist + if usr not in logs: + logs[usr] = Log(usr) + + ip = ParseIP(line) + # set info + if ip not in logs[usr].ips: + logs[usr].ips.append(ip) + logs[usr].succ_logs.append(line.rstrip('\n')) + logs[usr].logs.append(line.rstrip('\n')) + + # match a failed login + elif "Failed password for" in line: + # parse user + usr = ParseUsr(line) + + if usr not in logs: + logs[usr] = Log(usr) + + ip = ParseIP(line) + + if ip not in logs[usr].ips: + logs[usr].ips.append(ip) + logs[usr].fail_logs.append(line.rstrip('\n')) + logs[usr].logs.append(line.rstrip('\n')) + + # match failed auth + elif ":auth): authentication failure;" in line: + # so there are three flavors of authfail we care about; + # su, sudo, and ssh. Lets parse each. + usr = re.search(r'(\blogname=)(\w+)', line) + if usr is not None: + usr = usr.group(2) + # parse a fail log to ssh + if "(sshd:auth)" in line: + # ssh doesn't have a logname hurr + usr = ParseUsr(line) + if usr not in logs: + logs[usr] = Log(usr) + logs[usr].ips.append(ParseIP(line)) + # parse sudo/su fails + else: + if usr not in logs: + logs[usr] = Log(usr) + logs[usr].fail_logs.append(line.rstrip('\n')) + logs[usr].logs.append(line.rstrip('\n')) + # match commands + elif "sudo:" in line: + # parse user + usr = ParseUsr(line) + if usr not in logs: + logs[usr] = Log(usr) + + cmd = ParseCmd(line) + # append the command if it isn't there already + if cmd is not None: + if cmd not in logs[usr].commands: + logs[usr].commands.append(cmd) + logs[usr].logs.append(line.rstrip('\n')) + return logs diff --git a/logalyzer.py b/logalyzer.py index eb66961..52e39ef 100755 --- a/logalyzer.py +++ b/logalyzer.py @@ -1,138 +1,139 @@ -#!/usr/bin/python - -import sys, stat, os +import os +import sys from optparse import OptionParser import ParseLogs -# -# Logalyzer. Compiled with python 2.6 + +# +# Logalyzer. Original: https://github.com/hatRiot/logalyzer +# Converted to python3.6 by @cdombrowski # # callback for the user flag def user_call(option, opt_str, value, parser): - if len(parser.rargs) is not 0: - value = parser.rargs[0] - else: - value = None - setattr(parser.values, option.dest, value) - -# entry -if __name__=="__main__": - - # default location - log = '/var/log/auth.log' - - # parsing options - parser = OptionParser(epilog= - "Combine flags to view user-specific information. \'-u test -i\' lists IP addresses " - "associated with user test") - parser.add_option("-u", help="Specify user. Blank lists all users.", action="callback", - callback=user_call, default=None, dest="user") - parser.add_option("--full", help="Full log dump for specified user", action="store_true", - default=False, dest="fullu") - parser.add_option("-l", help="Specify log file. Default is auth.log", default=None, dest="log") - parser.add_option("-f", help="List failures", action="store_true", default=False, dest="fail") - parser.add_option("-s", help="List success logs", action="store_true", default=False, dest="success") - parser.add_option("-c", help="List commands by user", action="store_true", default=False, dest="commands") - parser.add_option("-i", help="List IP Addresses", action="store_true", default=False, dest="ip") - - # get arguments - (options, args) = parser.parse_args() - - # if they're trying to access /var/log/auth.log without proper privs, bail - if not os.getuid() is 0 and options.log is None: - print "[-] Please run with SUDO" - sys.exit(1) - - # check if they specified another file - if options.log is not None: - log = options.log - - # parse logs - LOGS = ParseLogs.ParseLogs(log) - if LOGS is None: sys.exit(1) - - # validate the user - if options.user: - if not options.user in LOGS: - print "[-] User \'%s\' is not present in the logs."%options.user - sys.exit(1) - - # tag log location first - print '[!] Log file: ', log - - # output all commands - if options.commands and not options.user: - for i in LOGS: - for comms in LOGS[i].commands: - print "{0}:\t{1}".format(i, comms) - sys.exit(1) - - # output all failures - elif options.fail and not options.user: - for i in LOGS: - for fail in LOGS[i].fail_logs: - print "{0}:\t{1}".format(i, fail) - sys.exit(1) - - # output all logged IP addresses - elif options.ip and not options.user: - for i in LOGS: - for ip in LOGS[i].ips: - print "{0}:\t{1}".format(i, ip) - sys.exit(1) - - # output user-specific commands - if options.commands and options.user: - print "[+] Commands for user \'%s\'"%options.user - for com in LOGS[options.user].commands: - print "\t",com - - # output user-specific success logs - elif options.success and options.user: - print "[+] Successes logs for user \'%s\'"%options.user - for log in LOGS[options.user].succ_logs: - print "\t",log - - # output user-specific failures - elif options.fail and options.user: - print "[+] Failures for user \'%s\'"%options.user - for fail in LOGS[options.user].fail_logs: - print "\t",fail - - # output user-specific ip addresses - elif options.ip and options.user: - print "[+] Logged IPs for user \'%s\'"%options.user - for i in LOGS[options.user].ips: - print "\t", i - - # print out all information regarding specified user - elif options.user is not None: - print "[!] Logs associated with user \'%s\'"%options.user - print '[+] First log: ', LOGS[options.user].first_date() - print '[+] Last log: ', LOGS[options.user].last_date() - print "[!] Failure Logs" - for fail in LOGS[options.user].fail_logs: - print "\t", fail - print "[!] Success Logs" - for succ in LOGS[options.user].succ_logs: - print "\t", succ - print "[!] Associated IPs" - for ip in LOGS[options.user].ips: - print "\t", ip - print "[!] Commands" - for comm in LOGS[options.user].commands: - print "\t", comm - - # dump the full log for the user if specified - if options.fullu and options.user: - print "[!] Full Log" - for log in LOGS[options.user].logs: - print log - - # if they supplied us with an empty user, dump all of the logged users - elif options.user is None: - if len(LOGS) > 0: - for i in LOGS: - print i + if len(parser.rargs) is not 0: + value = parser.rargs[0] + else: + value = None + setattr(parser.values, option.dest, value) + + +if __name__ == "__main__": + + # default location + log = '/var/log/auth.log' + + # parsing options + parser = OptionParser(epilog= + "Combine flags to view user-specific information. \'-u test -i\' lists IP addresses " + "associated with user test") + parser.add_option("-u", help="Specify user. Blank lists all users.", action="callback", + callback=user_call, default=None, dest="user") + parser.add_option("--full", help="Full log dump for specified user", action="store_true", + default=False, dest="fullu") + parser.add_option("-l", help="Specify log file. Default is auth.log", default=None, dest="log") + parser.add_option("-f", help="List failures", action="store_true", default=False, dest="fail") + parser.add_option("-s", help="List success logs", action="store_true", default=False, dest="success") + parser.add_option("-c", help="List commands by user", action="store_true", default=False, dest="commands") + parser.add_option("-i", help="List IP Addresses", action="store_true", default=False, dest="ip") + + # get arguments + (options, args) = parser.parse_args() + + # if they're trying to access /var/log/auth.log without proper privs, bail + if not os.getuid() is 0 and options.log is None: + print("[-] Please run with SUDO") + sys.exit(1) + + # check if they specified another file + if options.log is not None: + log = options.log + + # parse logs + LOGS = ParseLogs.ParseLogs(log) + if LOGS is None: sys.exit(1) + + # validate the user + if options.user: + if not options.user in LOGS: + print(f"[-] User \'{options.user}\' is not present in the logs.") + sys.exit(1) + + # tag log location first + print('[!] Log file: ', log) + + # output all commands + if options.commands and not options.user: + for i in LOGS: + for comms in LOGS[i].commands: + print(f"{i}:\t{comms}") + sys.exit(1) + + # output all failures + elif options.fail and not options.user: + for i in LOGS: + for fail in LOGS[i].fail_logs: + print(f"{i}:\t{fail}") + sys.exit(1) + + # output all logged IP addresses + elif options.ip and not options.user: + for i in LOGS: + for ip in LOGS[i].ips: + print(f"{i}:\t{ip}") + sys.exit(1) + + # output user-specific commands + if options.commands and options.user: + print(f"[+] Commands for user \'{options.user}\'") + for com in LOGS[options.user].commands: + print("\t", com) + + # output user-specific success logs + elif options.success and options.user: + print(f"[+] Successes logs for user \'{options.user}\'") + for log in LOGS[options.user].succ_logs: + print("\t", log) + + # output user-specific failures + elif options.fail and options.user: + print(f"[+] Failures for user \'{options.user}\'") + for fail in LOGS[options.user].fail_logs: + print("\t", fail) + + # output user-specific ip addresses + elif options.ip and options.user: + print(f"[+] Logged IPs for user \'{options.user}\'") + for i in LOGS[options.user].ips: + print("\t", i) + + # print out all information regarding specified user + elif options.user is not None: + print(f"[!] Logs associated with user \'{options.user}\'") + print('[+] First log: ', LOGS[options.user].first_date()) + print('[+] Last log: ', LOGS[options.user].last_date()) + print("[!] Failure Logs") + for fail in LOGS[options.user].fail_logs: + print("\t", fail) + print("[!] Success Logs") + for succ in LOGS[options.user].succ_logs: + print("\t", succ) + print("[!] Associated IPs") + for ip in LOGS[options.user].ips: + print("\t", ip) + print("[!] Commands") + for comm in LOGS[options.user].commands: + print("\t", comm) + + # dump the full log for the user if specified + if options.fullu and options.user: + print("[!] Full Log") + for log in LOGS[options.user].logs: + print(log) + + # if they supplied us with an empty user, dump all of the logged users + elif options.user is None: + if len(LOGS) > 0: + for i in LOGS: + print(i) From 79db18514669b5a39ada7b5600f68d7c1c0da49a Mon Sep 17 00:00:00 2001 From: programmerchad Date: Wed, 25 Apr 2018 18:35:24 -0400 Subject: [PATCH 2/3] Update ParseLogs.py --- ParseLogs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParseLogs.py b/ParseLogs.py index 94ac3b9..01abbcc 100644 --- a/ParseLogs.py +++ b/ParseLogs.py @@ -5,7 +5,7 @@ # # ParseLogs.py # Parsing component of Logalyzer. Original: https://github.com/hatRiot/logalyzer -# Converted to python3.6 by @cdombrowski +# Converted to python3.6 by @programmerchad # # log object From f833d257f0069c255add6647bcec408dc26e0661 Mon Sep 17 00:00:00 2001 From: programmerchad Date: Wed, 25 Apr 2018 18:35:54 -0400 Subject: [PATCH 3/3] Update logalyzer.py --- logalyzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logalyzer.py b/logalyzer.py index 52e39ef..115fd8c 100755 --- a/logalyzer.py +++ b/logalyzer.py @@ -7,7 +7,7 @@ # # Logalyzer. Original: https://github.com/hatRiot/logalyzer -# Converted to python3.6 by @cdombrowski +# Converted to python3.6 by @programmerchad # # callback for the user flag