diff --git a/smart/__init__.py b/smart/__init__.py index 2ad1b91..747ac8c 100644 --- a/smart/__init__.py +++ b/smart/__init__.py @@ -23,6 +23,28 @@ import shutil from datetime import datetime _cli = typer.Typer() + +@_cli.command(name='log-intruder') +def intrusion(path:str='/var/log/auth.log', year:int=datetime.now().year): + """ + This function + """ + _r = smart.logger.read(path=path,year=year) + if _r : + for _id in _r : + if hasattr(smart.logger,_id): + try: + _pointer = getattr(smart.logger,_id) + _df = _pointer(_r[_id]) + + post(_df,_id) + except Exception as e: + print (e) + pass + else: + print () + print ("Nothing out of the ordinary was found in") + print (f"{path}") @_cli.command(name='top') def apply_apps (app:str=None,user:str=None): """ diff --git a/smart/logger/__init__.py b/smart/logger/__init__.py index 88b329a..61c6ddd 100644 --- a/smart/logger/__init__.py +++ b/smart/logger/__init__.py @@ -1,52 +1,77 @@ +""" +This file looks into the logs to determine if there is any intrusion or provides means to assess logs +""" + import pandas as pd import numpy as np import transport import datetime import io import json -import requests +import re +from datetime import datetime -def subscribe (self,**args) : +_date = "(^[A-Z][a-z]{2}) ([0-9]{2}) ([0-9]{2})\:([0-9]){2}\:([0-9]{2})" +_ip = "\d+\.\d+\.\d+\.\d+" +_regex = { + 'login':{'pattern':f'{_date} .*Accepted password for ([a-z]+) from ({_ip})', 'columns':['month','day','hour','minute','second','user','ip']}, + 'attacks':{'pattern':f'{_date} .*Invalid user ([a-z,0-6]+) from ({_ip})','columns':['month','day','hour','minute','second','user','ip']}, + 'risk':{'pattern':f'{_date} .*Failed password for ([a-z,0-6]+) from ({_ip})','columns':['month','day','hour','minute','second','user','ip']} #-- accounts at risk + +} +_map = {'Jan':1,'Feb':2,'Mar':3,'Apr':4,'May':5,'Jun':6,'Jul':7,'Aug':8,'Sep':9,'Oct':10,'Nov':11,'Dec':12} +def risk (_content,_id='user'): """ - This function will subscribe an email to a given service (report,notification). If already susbcribed no further action will be performed - :email provide a valid email for the free plan. Upgrades will be done via the website - :id service identifier accepted values are GOOGLE_DRIVE,DROPBOX,BOX,ONE_DRIVE - + compute the risk associated with accounts given the counts, this should be indicated by the number of failed password attempts in a given time frame """ - url = "https://the-phi.com/store/smart-top/subscribe" - SERVICES=['GOOGLE','DROPBOX','BOX','ONE_DRIVE'] - if args['id'].upper() in SERVICES : - data = {"email":args['email']} - requests.post(url,data=data) - pass - -def log(**args) : + _df = pd.DataFrame(_content) + _g = _df.groupby([_id]).apply(lambda row: {'start_date':row.date.min(),'end_date':row.date.max() ,'count':row[_id].size} ) + _df = pd.DataFrame(_g.tolist()) + _df['user'] = _g.index + _df.start_date = _df.start_date.astype(str) + _df.end_date = _df.end_date.astype(str) + return _df +def attacks (_content): + """ + This function will compute counts associated with a given set of ip addresses. If behind a load balancer IP can be ignored and counts will reflect break-in attempts + """ + return risk(_content,'ip') +def login(_content): + return risk(_content,'user') +def read (**_args): """ - This function will write to a designated location provided a set of inputs - :store mongo,file,couch,api + :path path of the auth.log files to load """ + _year = _args['year'] if 'year' in _args else datetime.now().year + _path = _args['path'] + f = open(_path) + _content = f.read().split('\n') + f.close() + r = {} + for line in _content : + for _id in _regex : + _pattern = _regex[_id]['pattern'] + _columns = _regex[_id]['columns'] + + _out = re.search(_pattern,line) + if _out : + try: + _object = dict(zip(_columns,_out.groups()[:])) + if _id not in r : + r[_id] = [] + _month = _object['month'] + if _month in _map : + _object['month'] = _map[ _month ] + for field in ['day','month','hour','minute','second'] : + _object[field] = int (_object[field]) + _object['date'] = datetime ( year=_year,month=_object['month'], day=_object['day'], hour=_object['hour'],minute=_object['minute'],second=_object['second'])#'-'.join([str(_object['month']),str(_object['day'])]) + ' '+_object['time'] + # _object['date'] = np.datetime64(_object['date']) + r[_id].append(_object) + except Exception as e: + print(e) + pass # - # @TODO: Provide facility to write to a given cloud store (google,one-drive ...) - # This will have to be supported by some sort of subscription service + # At this point we have essential information formatted + # Summarizing this information will serve as a means to compress it # - STORE_MAP = {"mongo":"MongoWriter","disk":"DiskWriter","couch":"CouchWriter",'sqlite':'SQLiteWriter'} - if 'store' not in args : - _id = 'console' - else: - _id = 'disk' if args['store'] == 'file' else args['store'] - _id = 'disk' if _id == 'sqlite' else _id - if _id == 'console' : - """ - We are going to print whatever we have to the console ... using the tool in cli mode - """ - print() - print (args['data']) - print () - # stream = args['memory'] - # stream.write(json.dumps(args['row']) if isinstance(args['row'],dict) else args['row']) - # stream.write("\n") - else: - store_type = ".".join([args['store'],STORE_MAP[_id]]) - store_args = args['params'] - store = transport.factory.instance(type=store_type,args=store_args) - store.write( args['row']) + return r \ No newline at end of file