1# 2# sshd.py 3# 4# Find number of ssh logins and authorised users (uses /var/log/auth.log) 5# 6# NOTE: This file is now deprecated in favour of the newer journald mechanism 7# used in sshd-journald.py. This parser is still functional but is slower and 8# has less features. Please switch over if possible. 9# 10 11import re 12 13from logparse.formatting import* 14from logparse.util import readlog, resolve 15from logparse import config 16from logparse.load_parsers import Parser 17 18classSshd(Parser): 19 20def__init__(self): 21super().__init__() 22 self.name ="sshd" 23 self.info ="Find number of ssh logins and authorised users (uses /var/log/auth.log)" 24 self.deprecated =True 25 self.successor ="sshd_journald" 26 27defparse_log(self): 28 29 logger.warning("NOTE: This sshd parser is now deprecated. Please use sshd-journald if possible.") 30 31 logger.debug("Starting sshd section") 32 section =Section("ssh") 33 logger.debug("Searching for matches in{0}".format(config.prefs.get("logs","auth"))) 34 matches = re.findall('.*sshd.*Accepted publickey for .* from .*',readlog(config.prefs.get("logs","auth")))# get all logins 35 logger.debug("Finished searching for logins") 36 37 logger.debug("Searching for matches in{0}".format(config.prefs.get("logs","auth"))) 38 authlog =readlog(config.prefs.get("logs","auth")) 39 40 matches = re.findall('.*sshd.*Accepted publickey for .* from .*', authlog)# get all logins 41 invalid_matches = re.findall(".*sshd.*Invalid user .* from .*", authlog) 42 root_matches = re.findall("Disconnected from authenticating user root", authlog) 43 logger.debug("Finished searching for logins") 44 45 users = []# list of users with format [username, number of logins] for each item 46 data = [] 47 num =len(matches)# total number of logins 48for match in matches: 49 entry = re.search('^.*publickey\sfor\s(\w*)\sfrom\s(\S*)', match)# [('user', 'ip')] 50 51 user = entry.group(1) 52 ip = entry.group(2) 53 54 userhost = user +'@'+resolve(ip, fqdn=config.prefs.get("sshd","sshd-resolve-domains")) 55 users.append(userhost) 56 logger.debug("Parsed list of authorised users") 57 58 auth_data =Data(subtitle=plural('login', num) +' from', items=users) 59 60if(len(auth_data.items) ==1):# if only one user, do not display no of logins for this user 61 logger.debug("found "+str(len(matches)) +" ssh logins for user "+ users[0]) 62 auth_data.subtitle +=' '+ auth_data.items[0] 63 auth_data.orderbyfreq() 64 auth_data.truncl(config.prefs.getint("logparse","maxlist")) 65 logger.debug("Found "+str(len(matches)) +" ssh logins for users "+str(data)) 66 section.append_data(auth_data) 67 68 invalid_users = [] 69for match in invalid_matches: 70 entry = re.search('^.*Invalid user (\S+) from (\S+).*', match)# [('user', 'ip')] 71 72try: 73 user = entry.group(1) 74 ip = entry.group(2) 75except:# blank user field 76continue 77 78 userhost = user +'@'+ ip 79 invalid_users.append(userhost) 80 logger.debug("Parsed list of invalid users") 81 invalid_data =Data(subtitle=plural("attempted login",len(invalid_matches)) +" from "+plural("invalid user",len(invalid_users), print_quantity=False), items=invalid_users) 82if(len(invalid_data.items) ==1):# if only one user, do not display no of logins for this user 83 logger.debug("Found "+str(len(invalid_matches)) +" SSH login attempts for invalid user "+ invalid_users[0]) 84 invalid_data.subtitle +=' '+ invalid_data.items[0] 85 invalid_data.orderbyfreq() 86 invalid_data.truncl(config.prefs.get("logparse","maxlist")) 87 logger.debug("Found "+str(len(invalid_matches)) +" SSH login attempts for invalid users "+str(data)) 88 section.append_data(invalid_data) 89 90 logger.debug("Found{0}attempted logins for root".format(str(len(root_matches)))) 91 92 section.append_data(Data(subtitle=plural("attempted login",str(len(root_matches))) +" for root")) 93 94 logger.info("Finished sshd section") 95return section