def load_auth_data(self, **kwargs): def parse_auth(auth_type, line): items = filter(I, map(lambda x: x.strip(), line.split(' '))) tfmt = '%Y-%m-%d %H:%M:%S' time = items[0]+' '+items[1] time = datetime.strptime(time, tfmt) if auth_type == 'local': return{ 'user': items[8][1:len(items[8])-1], 'ip': None, 'time': time, } elif auth_type == 'ssh': return{ 'user': items[9], 'ip': items[11], 'time': time, } try: authf_local, bad = pcall('syslog -F \'$((Time)(J)) $Host $(Sender)[$(PID)]<$((Level)(str))>: $Message\' | grep \'Failed to authenticate\'') if bad: raise OSError() authf_ssh, bad = pcall('syslog -F \'$((Time)(J)) $Host $(Sender)[$(PID)]<$((Level)(str))>: $Message\' | grep \'PAM: authentication error\'') if bad: raise OSError() self.authf['local'] = [parse_auth('local',l) for l in authf_local] self.authf['ssh'] = [parse_auth('ssh',l) for l in authf_ssh] except OSError: raise Exception('`syslog` fails. Backend not supported.')
def __init__(self): out, err = pcall('which opensnoop') if not out: raise Exception('opensnoop not installed!') self.logs = [] out, err = pcall('dscl . -list /Users UniqueID') out = map(lambda l: filter(I, l.split(' ')), out) self.users = {int(uid): user for user, uid in out}
def snoop(self, timeout=10, output_file=None): """ Snoop open's for a while Args: timeout (int): how long to snoop output_file (optional[str]): if specified, save log to file. """ out, err = pcall('opensnoop -v', timeout) if len(err) > 0 and 'additional privileges' in err[0]: raise Exception(err[0]) if len(out) > 0: out = out[1:] self.logs = [] for line in out: line = filter(I, line.split(' ')) time = datetime.strptime(' '.join(line[:4]), '%Y %b %d %H:%M:%S') user = self.users[int(line[4])] # TODO: this is problematic for cmd/path with space in it cmd = line[6] fpath = line[-1] self.logs.append({ 'time': time, 'user': user, 'cmd': cmd, 'fpath': fpath, }) if output_file is not None: with open(output_file, 'w') as f: pickle.dump(self.logs, f)
def load(self, **kwargs): """ Load the system log It loads log(s) from default location. If they are not in the default location, specify in **kwargs. Args: **kwargs: specifies custom config for sys logs. None for this backend. """ def parse(line): items = filter(I, map(lambda x: x.strip(), line.split(' '))) # special case if items[1] == 'system' and items[2] == 'boot': items[1] = 'system boot' items.pop(2) # time format tfmt = '%a %b %d %H:%M:%S %Y' # parse tin if len(items[5]) == 1: items[5] = '0' + items[5] # pad zero before day tin = ' '.join(items[3:8]) tin = datetime.strptime(tin, tfmt) # parse tout if items[8] == '-': if len(items[10]) == 1: items[10] = '0' + items[10] if items[9] == 'crash': tout = None else: tout = ' '.join(items[9:14]) tout = datetime.strptime(tout, tfmt) else: tout = None return { 'user': items[0], 'terminal': items[1], 'ip': items[2], 'time_in': tin, 'time_out': tout, } try: last, bad = pcall('last -Fi') if bad: raise OSError() else: self.last = [parse(l) for l in last[:-1]] except OSError: raise Exception('`last -Fi` fails. Backend not supported.') try: lastb, bad = pcall('lastb -Fi') if bad: warnings.warn( '`lastb -Fi` fails, which requires sudo permission.' 'Continue if you don\'t need authfailures') else: self.lastb = [parse(l) for l in lastb[:-1]] except OSError: raise Exception('`lastb -Fi` fails. Backend not supported.')
def load(self, **kwargs): """ Load the system log It loads log(s) from default location. If they are not in the default location, specify in **kwargs. Args: **kwargs: specifies custom config for sys logs. None for this backend. """ def parse(line): items = filter(I, map(lambda x: x.strip(), line.split(' '))) if items[0] == 'reboot' or items[0] == 'shutdown': return # time format tfmt = '%a %b %d %H:%M' if len(items) == 10: # parse tin if len(items[5]) == 1: items[5] = '0' + items[5] # pad zero before day tin = ' '.join(items[3:7]) tin = datetime.strptime(tin, tfmt) now = datetime.now() now_month = now.month now_day = now.day tin = tin.replace(year=now.year) if tin.month > now_month: if tin.day > now_day: tin = tin - relativedelta(years = 1) # parse tout if items[7] == '-': if items[8] == 'shutdown' or items[8] == 'crash' : duration = items[9][1:-1] if '+' in duration: time = duration.split('+') hours_mins = time[1].split(':') tout = tin + timedelta(days=int(time[0]), hours=int(hours_mins[0]), seconds=int(hours_mins[1]) * 60) else: hours_mins = duration.split(':') tout = tin + timedelta(hours=int(hours_mins[0]), seconds=int(hours_mins[1]) * 60) else: duration = items[9][1:-1] # logout_time = items[8] # logout_time = datetime.strptime(logout_time, "%H:%M") if '+' in duration: time = duration.split('+') hours_mins = time[1].split(':') tout = tin + timedelta(days=int(time[0]), hours=int(hours_mins[0]), seconds=int(hours_mins[1]) * 60) else: hours_mins = duration.split(':') tout = tin + timedelta(hours=int(hours_mins[0]), seconds=int(hours_mins[1]) * 60) else: tout = None return { 'user': items[0], 'terminal': items[1], 'ip': items[2], 'time_in': tin, 'time_out': tout, } else: # parse tin if len(items[4]) == 1: items[4] = '0' + items[4] # pad zero before day tin = ' '.join(items[2:6]) tin = datetime.strptime(tin, tfmt) now = datetime.now() now_month = now.month now_day = now.day tin = tin.replace(year=now.year) if tin.month > now_month: if tin.day > now_day: tin = tin - relativedelta(years = 1) # parse tout if items[6] == '-': # tout = ' '.join(items[7:9]) if items[7] == 'shutdown' or items[7] == 'crash': duration = items[8][1:-1] if '+' in duration: time = duration.split('+') hours_mins = time[1].split(':') tout = tin + timedelta(days=int(time[0]), hours=int(hours_mins[0]), seconds=int(hours_mins[1]) * 60) else: hours_mins = duration.split(':') tout = tin + timedelta(hours=int(hours_mins[0]), seconds=int(hours_mins[1]) * 60) else: duration = items[8][1:-1] # logout_time = items[7] # logout_time = datetime.strptime(logout_time, "%H:%M") if '+' in duration: time = duration.split('+') hours_mins = time[1].split(':') tout = tin + timedelta(days=int(time[0]), hours=int(hours_mins[0]), seconds=int(hours_mins[1]) * 60) else: hours_mins = duration.split(':') tout = tin + timedelta(hours=int(hours_mins[0]), seconds=int(hours_mins[1]) * 60) else: tout = None return { 'user': items[0], 'terminal': items[1], 'ip': 'Local', 'time_in': tin, 'time_out': tout, } try: last, bad = pcall('last') if bad: raise OSError() else: self.last = filter(I, [parse(l) for l in last[:-1]]) self.load_auth_data() except OSError: raise Exception('`last` fails. Backend not supported.')
def load(self, **kwargs): """ Load the system log It loads log(s) from default location. If they are not in the default location, specify in **kwargs. Args: **kwargs: specifies custom config for sys logs. None for this backend. """ def parse(line): items = filter(I, map(lambda x: x.strip(), line.split(' '))) # special case if items[1] == 'system' and items[2] == 'boot': items[1] = 'system boot' items.pop(2) # time format tfmt = '%a %b %d %H:%M:%S %Y' # parse tin if len(items[5]) == 1: items[5] = '0' + items[5] # pad zero before day tin = ' '.join(items[3:8]) tin = datetime.strptime(tin, tfmt) # parse tout if items[8] == '-': if len(items[10]) == 1: items[10] = '0' + items[10] if items[9] == 'crash': tout = None else: tout = ' '.join(items[9:14]) tout = datetime.strptime(tout, tfmt) else: tout = None return { 'user': items[0], 'terminal': items[1], 'ip': items[2], 'time_in': tin, 'time_out': tout, } try: last, bad = pcall('last -Fi') if bad: raise OSError() else: self.last = [parse(l) for l in last[:-1]] except OSError: raise Exception('`last -Fi` fails. Backend not supported.') try: lastb, bad = pcall('lastb -Fi') if bad: warnings.warn('`lastb -Fi` fails, which requires sudo permission.' 'Continue if you don\'t need authfailures') else: self.lastb = [parse(l) for l in lastb[:-1]] except OSError: raise Exception('`lastb -Fi` fails. Backend not supported.')