def esSearch(es, begindateUTC=None, enddateUTC=None): resultsList = list() if begindateUTC is None: begindateUTC = toUTC(datetime.now() - timedelta(minutes=options.aggregationminutes)) if enddateUTC is None: enddateUTC = toUTC(datetime.now()) try: # search for events within the date range that haven't already been alerted (i.e. given an alerttimestamp) qDate = pyes.RangeQuery(qrange=pyes.ESRange( 'utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) q = pyes.ConstantScoreQuery(pyes.MatchAllQuery()) q = pyes.FilteredQuery(q, pyes.BoolFilter(must=[qDate])) q = q.search() qagg = pyes.aggs.TermsAgg(name='category', field='category') q.agg.add(qagg) results = es.search(query=q, indices=['events']) mozdefstats = dict(utctimestamp=toUTC(datetime.now()).isoformat()) mozdefstats['summary'] = 'Aggregated category counts' mozdefstats['processid'] = os.getpid() mozdefstats['processname'] = sys.argv[0] mozdefstats['details'] = dict(counts=list()) for bucket in results.aggs['category']['buckets']: entry = dict() entry[bucket['key']] = bucket['doc_count'] mozdefstats['details']['counts'].append(entry) return mozdefstats except pyes.exceptions.NoServerAvailable: logger.error( 'Elastic Search server could not be reached, check network connectivity' )
def searchESForBROAttackers(es, threshold): begindateUTC = toUTC(datetime.now() - timedelta(hours=2)) enddateUTC = toUTC(datetime.now()) qDate = pyes.RangeQuery(qrange=pyes.ESRange( 'utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) q = pyes.ConstantScoreQuery(pyes.MatchAllQuery()) qBro = pyes.QueryFilter(pyes.MatchQuery('category', 'bro_notice', 'phrase')) qErr = pyes.QueryFilter( pyes.MatchQuery('details.note', 'MozillaHTTPErrors::Excessive_HTTP_Errors_Attacker', 'phrase')) q = pyes.FilteredQuery(q, pyes.BoolFilter(must=[qBro, qErr])) results = es.search(q, size=1000, indices='events,events-previous') # grab results as native es results to avoid pyes iteration bug # and get easier access to es metadata fields rawresults = results._search_raw()['hits']['hits'] # Hit count is buried in the 'sub' field # as: 'sub': u'6 in 1.0 hr, eps: 0' # cull the records for hitcounts over the threshold before returning attackers = list() for r in rawresults: hitcount = int(r['_source']['details']['sub'].split()[0]) if hitcount > threshold: attackers.append(r) return attackers
def esCloudTrailSearch(es, begindateUTC=None, enddateUTC=None): resultsList = list() if begindateUTC is None: begindateUTC = toUTC(datetime.now() - timedelta(hours=160)) if enddateUTC is None: enddateUTC = toUTC(datetime.now()) try: #search for actions within the date range that haven't already been alerted (i.e. given an alerttimestamp) qDate = pyes.RangeQuery(qrange=pyes.ESRange( 'utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) qcloud = pyes.TermFilter('_type', 'cloudtrail') qEvents = pyes.TermsFilter( 'eventName', ['runinstances', 'stopinstances', 'startinstances']) qalerted = pyes.ExistsFilter('alerttimestamp') results = es.search(pyes.ConstantScoreQuery( pyes.BoolFilter(must=[qcloud, qDate, qEvents], must_not=[qalerted])), indices='events') #uncomment for debugging to recreate alerts for events that already have an alerttimestamp #results=es.search(pyes.ConstantScoreQuery(pyes.BoolFilter(must=[qcloud,qDate,qEvents]))) return (results._search_raw()['hits']['hits']) except pyes.exceptions.NoServerAvailable: logger.error( 'Elastic Search server could not be reached, check network connectivity' )
def esSearch(es, begindateUTC=None, enddateUTC=None): resultsList = list() if begindateUTC is None: begindateUTC = toUTC(datetime.now() - timedelta(minutes=options.aggregationminutes)) if enddateUTC is None: enddateUTC = toUTC(datetime.now()) try: # search for aggregated event stats summaries within the date range qDate = pyes.RangeQuery(qrange=pyes.ESRange('utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) q = pyes.ConstantScoreQuery(pyes.MatchAllQuery()) q = pyes.FilteredQuery(q,pyes.BoolFilter(must=[qDate, pyes.TermFilter('_type', 'mozdefstats')])) results=es.search(query=q,size=100,indices=['events','events-previous']) #avoid pyes iteration bug rawresults = results._search_raw() #examine the results #for each details.counts, append the count #as a list to the stats dict stats=dict() for r in rawresults['hits']['hits']: for i in r['_source']['details']['counts']: #print(i.values()[0]) if i.keys()[0] not in stats.keys(): stats[i.keys()[0]]=list() stats[i.keys()[0]].append(i.values()[0]) # make a dictionairy of user-defined # aggregation threshold percentages aggregationthresholds = dict(zip(options.aggregations, options.aggregationthresholds)) #for our running history of counts per category #do some simple stats math to see if we #should alert on anything for s in stats: alert = False smean=round(numpy.mean(stats[s])) sstd=round(numpy.std(stats[s])) stat = round((sstd/smean)*100, 2) if s in aggregationthresholds.keys(): if stat > aggregationthresholds[s]: alert = True elif stat > options.defaultthreshold: alert = True if alert: print('{0} {1}%: \n\t\t{2} \n\t\t{3} \n\t\t{4}'.format( s, stat, stats[s], smean, sstd ) ) except pyes.exceptions.NoServerAvailable: logger.error('Elastic Search server could not be reached, check network connectivity')
def filtersManual(self, date_timedelta, must=[], should=[], must_not=[]): """ Configure filters manually date_timedelta is a dict in timedelta format see https://docs.python.org/2/library/datetime.html#timedelta-objects must, should and must_not are pyes filter objects lists see http://pyes.readthedocs.org/en/latest/references/pyes.filters.html """ self.begindateUTC = toUTC(datetime.now() - timedelta(**date_timedelta)) self.enddateUTC = toUTC(datetime.now()) qDate = pyes.RangeQuery(qrange=pyes.ESRange('utctimestamp', from_value=self.begindateUTC, to_value=self.enddateUTC)) q = pyes.ConstantScoreQuery(pyes.MatchAllQuery()) #Don't fire on already alerted events if pyes.ExistsFilter('alerttimestamp') not in must_not: must_not.append(pyes.ExistsFilter('alerttimestamp')) must.append(qDate) q.filters.append(pyes.BoolFilter( must=must, should=should, must_not=must_not)) self.filter = q
def getFrontendStats(es): begindateUTC = toUTC(datetime.now() - timedelta(minutes=1)) enddateUTC = toUTC(datetime.now()) qDate = pyes.RangeQuery(qrange=pyes.ESRange( 'utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) qType = pyes.TermFilter('_type', 'mozdefhealth') qMozdef = pyes.TermsFilter('category', ['mozdef']) pyesresults = es.search(pyes.ConstantScoreQuery( pyes.BoolFilter(must=[qType, qDate, qMozdef])), indices='events') return pyesresults._search_raw()['hits']['hits']
def getESAlerts(es): begindateUTC = toUTC(datetime.now() - timedelta(minutes=50)) enddateUTC = toUTC(datetime.now()) qDate = pyes.RangeQuery(qrange=pyes.ESRange( 'utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) qType = pyes.TermFilter('_type', 'alert') q = pyes.ConstantScoreQuery(pyes.MatchAllQuery()) q.filters.append(pyes.BoolFilter(must=[qDate, qType])) results = es.search(q, size=10000, indices='alerts') # return raw search to avoid pyes iteration bug return results._search_raw()
def esBroXSSEvents(): begindateUTC = toUTC(datetime.now() - timedelta(minutes=30)) enddateUTC = toUTC(datetime.now()) qDate = pyes.RangeQuery(qrange=pyes.ESRange( 'utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) qType = pyes.TermFilter('_type', 'event') qEvents = pyes.TermFilter("category", "broxsslog") qalerted = pyes.ExistsFilter('alerttimestamp') q = pyes.ConstantScoreQuery(pyes.MatchAllQuery()) q.filters.append( pyes.BoolFilter(must=[qType, qDate, qEvents, pyes.ExistsFilter('uri')], must_not=[qalerted])) return q
def esSearch(es, begindateUTC=None, enddateUTC=None): resultsList = list() if begindateUTC is None: begindateUTC = toUTC(datetime.now() - timedelta(minutes=60)) if enddateUTC is None: enddateUTC = toUTC(datetime.now()) try: #search for events within the date range that haven't already been alerted (i.e. given an alerttimestamp) qDate = pyes.RangeQuery(qrange=pyes.ESRange( 'utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) qType = pyes.TermFilter('_type', 'event') qEvents = pyes.TermsFilter('category', ['brointel']) qalerted = pyes.ExistsFilter('alerttimestamp') qdetails = pyes.ExistsFilter('details') qindicator = pyes.ExistsFilter('seenindicator') pyesresults = es.search(pyes.ConstantScoreQuery( pyes.BoolFilter(must=[qType, qDate, qEvents, qdetails, qindicator], must_not=[qalerted])), size=1000) #uncomment for debugging to recreate alerts for events that already have an alerttimestamp #results=es.search(pyes.ConstantScoreQuery(pyes.BoolFilter(must=[qcloud,qDate,qEvents]))) #logger.debug(results.count()) #correlate any matches by the seenindicator field. #make a simple list of indicator values that can be counted/summarized by Counter resultsIndicators = list() #bug in pyes..capture results as raw list or it mutates after first access: #copy the hits.hits list as our resusts, which is the same as the official elastic search library returns. results = pyesresults._search_raw()['hits']['hits'] for r in results: resultsIndicators.append(r['_source']['details']['seenindicator']) #use the list of tuples ('indicator',count) to create a dictionary with: #indicator,count,es records #and add it to a list to return. indicatorList = list() for i in Counter(resultsIndicators).most_common(): idict = dict(indicator=i[0], count=i[1], events=[]) for r in results: if r['_source']['details']['seenindicator'].encode( 'ascii', 'ignore') == i[0]: idict['events'].append(r) indicatorList.append(idict) return indicatorList except pyes.exceptions.NoServerAvailable: logger.error( 'Elastic Search server could not be reached, check network connectivity' )
def esBroIntelEvents(): begindateUTC = toUTC(datetime.now() - timedelta(minutes=30)) enddateUTC = toUTC(datetime.now()) #search for events within the date range that haven't already been alerted (i.e. given an alerttimestamp) qDate = pyes.RangeQuery(qrange=pyes.ESRange( 'utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) qType = pyes.TermFilter('_type', 'event') qEvents = pyes.TermsFilter('category', ['brointel']) qalerted = pyes.ExistsFilter('alerttimestamp') q = pyes.ConstantScoreQuery(pyes.MatchAllQuery()) q.filters.append( pyes.BoolFilter( must=[qType, qDate, qEvents, pyes.ExistsFilter('seenindicator')], must_not=[qalerted])) return q
def esSearch(es, macassignments=None, begindateUTC=None, enddateUTC=None): ''' Search ES for an event that ties a username to a mac address This example searches for junos wifi correlations on authentication success Expecting an event like: user: [email protected]; mac: 5c:f9:38:b1:de:cf; author reason: roamed session; ssid: ANSSID; AP 46/2\n ''' usermacre=re.compile(r'''user: (?P<username>.*?); mac: (?P<macaddress>.*?); ''',re.IGNORECASE) correlations={} # list of dicts to populate hits we find if begindateUTC is None: begindateUTC = toUTC(datetime.now() - timedelta(minutes=options.correlationminutes)) if enddateUTC is None: enddateUTC = toUTC(datetime.now()) try: # search for events within the date range qDate = pyes.RangeQuery(qrange=pyes.ESRange('utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) q=pyes.ConstantScoreQuery(pyes.MatchAllQuery()) q.filters.append(pyes.BoolFilter(must=[ qDate, pyes.TermFilter("program","AUTHORIZATION-SUCCESS") ], must_not=[ pyes.QueryFilter( pyes.MatchQuery("summary","last-resort","phrase") ) ])) results = es.search(q, size=10000, indices=['events', 'events-previous']) rawresults=results._search_raw() for r in rawresults['hits']['hits']: fields = re.search(usermacre,r['_source']['summary']) if fields: if '{0} {1}'.format(fields.group('username'),fields.group('macaddress')) not in correlations.keys(): if fields.group('macaddress')[0:8].lower() in macassignments.keys(): entity=macassignments[fields.group('macaddress')[0:8].lower()] else: entity='unknown' correlations['{0} {1}'.format(fields.group('username'),fields.group('macaddress'))]=dict(username=fields.group('username'), macaddress=fields.group('macaddress'), entity=entity, utctimestamp=r['_source']['utctimestamp']) return correlations except pyes.exceptions.NoServerAvailable: logger.error('Elastic Search server could not be reached, check network connectivity')
def searchForSSHKeys(es): begindateUTC = toUTC(datetime.now() - timedelta(minutes=5)) enddateUTC = toUTC(datetime.now()) qDate = pyes.RangeQuery(qrange=pyes.ESRange( 'utctimestamp', from_value=begindateUTC, to_value=enddateUTC)) qType = pyes.TermFilter('_type', 'event') qEvents = pyes.TermFilter("program", "sshd") q = pyes.ConstantScoreQuery(pyes.MatchAllQuery()) q.filters.append( pyes.BoolFilter(must=[ qType, qDate, qEvents, pyes.QueryFilter( pyes.MatchQuery("summary", "found matching key accepted publickey", "boolean")) ])) results = es.search(q, size=10000, indices='events') # return raw search to avoid pyes iteration bug return results._search_raw()