From da686ceba87d7f1b0fd45e0e911dea281fad7bf3 Mon Sep 17 00:00:00 2001 From: Omar Santos Date: Fri, 31 Jul 2020 12:56:55 -0400 Subject: [PATCH] Create ParseLogs.py --- .../parsing_auth_log/ParseLogs.py | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 python_ruby_and_bash/parsing_auth_log/ParseLogs.py diff --git a/python_ruby_and_bash/parsing_auth_log/ParseLogs.py b/python_ruby_and_bash/parsing_auth_log/ParseLogs.py new file mode 100644 index 0000000..01abbcc --- /dev/null +++ b/python_ruby_and_bash/parsing_auth_log/ParseLogs.py @@ -0,0 +1,159 @@ +import gzip +import re + + +# +# ParseLogs.py +# Parsing component of Logalyzer. Original: https://github.com/hatRiot/logalyzer +# Converted to python3.6 by @programmerchad +# + +# 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 = [] + + +# 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) + + +# 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) + + +# 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) + + +# 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) + + +# 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 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