зеркало из https://github.com/mozilla/MozDef.git
143 строки
5.5 KiB
Python
Executable File
143 строки
5.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
#
|
|
# Contributors:
|
|
# Jeff Bryner jbryner@mozilla.com
|
|
|
|
import email.utils
|
|
import sys
|
|
import smtplib
|
|
import json
|
|
import logging
|
|
from collections import Counter
|
|
from configlib import getConfig, OptionParser
|
|
from datetime import datetime
|
|
from email.mime.text import MIMEText
|
|
from logging.handlers import SysLogHandler
|
|
|
|
import sys
|
|
import os
|
|
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../lib'))
|
|
from utilities.toUTC import toUTC
|
|
from elasticsearch_client import ElasticsearchClient, ElasticsearchBadServer
|
|
from query_models import SearchQuery, TermMatch, PhraseMatch, RangeMatch
|
|
|
|
|
|
logger = logging.getLogger(sys.argv[0])
|
|
|
|
def loggerTimeStamp(self, record, datefmt=None):
|
|
return toUTC(datetime.now()).isoformat()
|
|
|
|
|
|
def initLogger():
|
|
logger.level = logging.INFO
|
|
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
formatter.formatTime = loggerTimeStamp
|
|
if options.output == 'syslog':
|
|
logger.addHandler(SysLogHandler(address=(options.sysloghostname, options.syslogport)))
|
|
else:
|
|
sh = logging.StreamHandler(sys.stderr)
|
|
sh.setFormatter(formatter)
|
|
logger.addHandler(sh)
|
|
|
|
|
|
def esSearch(es):
|
|
search_query = SearchQuery(minutes=60)
|
|
search_query.add_must([
|
|
TermMatch('deviceproduct', 'webpay'),
|
|
PhraseMatch('details.dhost', 'marketplace.firefox.com'),
|
|
RangeMatch('details.severity', from_value=6)
|
|
])
|
|
search_query.add_must_not(PhraseMatch('details.dhost', 'marketplace-dev.allizom.org'))
|
|
|
|
try:
|
|
full_results = search_query.execute(es)
|
|
# correlate any matches
|
|
# make a simple list of indicator values that can be counted/summarized by Counter
|
|
resultsIndicators = list()
|
|
results = full_results['hits']
|
|
for r in results:
|
|
resultsIndicators.append(r['_source']['details']['request'])
|
|
|
|
# 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']['request'].encode('ascii', 'ignore') == i[0]:
|
|
idict['events'].append(r)
|
|
indicatorList.append(idict)
|
|
return indicatorList
|
|
|
|
except ElasticsearchBadServer:
|
|
logger.error('Elastic Search server could not be reached, check network connectivity')
|
|
|
|
def sendResults(indicatorCounts):
|
|
emailMessage = ''
|
|
|
|
for i in indicatorCounts:
|
|
emailMessage += ('Count: {0} Endpoint: {1:>20}\n'.format(i['count'], i['indicator']))
|
|
|
|
for event in i['events']:
|
|
emailMessage += ('{0:>10}:\n'.format('event'))
|
|
for k, v in event['_source'].iteritems():
|
|
|
|
#sys.stdout.write('\t\t{0}\n\n'.format(json.dumps(event['_source'], indent=4, sort_keys=True)))
|
|
if k == 'details':
|
|
emailMessage += ('{0:>20}:'.format('details'))
|
|
emailMessage += ('{0:>30}'.format(
|
|
json.dumps(v,
|
|
indent=16,
|
|
sort_keys=True)
|
|
.replace('{', '')
|
|
.replace('}', '')))
|
|
elif k not in ('utctimestamp', 'receivedtimestamp'):
|
|
emailMessage += ('{0:>20}: {1}\n'.format(k, v))
|
|
emailMessage += ('\n')
|
|
|
|
for r in options.recipients:
|
|
mimeMessage = MIMEText(emailMessage)
|
|
mimeMessage['To'] = email.utils.formataddr((r, r))
|
|
mimeMessage['From'] = email.utils.formataddr(('MozDef', options.sender))
|
|
mimeMessage['Date'] = toUTC(datetime.now()).isoformat()
|
|
mimeMessage['Subject'] = 'Marketplace Alert Summary'
|
|
|
|
smtpserver = smtplib.SMTP(host=options.smtpserver, port=25)
|
|
smtpserver.sendmail(options.sender, [r], mimeMessage.as_string())
|
|
smtpserver.quit()
|
|
|
|
def main():
|
|
logger.debug('starting')
|
|
logger.debug(options)
|
|
es = ElasticsearchClient((list('{0}'.format(s) for s in options.esservers)))
|
|
# see if we have matches.
|
|
indicatorCounts = esSearch(es)
|
|
if len(indicatorCounts) > 0:
|
|
sendResults(indicatorCounts)
|
|
logger.debug('finished')
|
|
|
|
|
|
def initConfig():
|
|
# logging settings
|
|
options.output = getConfig('output', 'stdout', options.configfile) # output our log to stdout or syslog
|
|
options.sysloghostname = getConfig('sysloghostname', 'localhost', options.configfile) # syslog hostname
|
|
options.syslogport = getConfig('syslogport', 514, options.configfile) # syslog port
|
|
# elastic search server settings
|
|
options.esservers = list(getConfig('esservers', 'http://localhost:9200', options.configfile).split(','))
|
|
# email settings
|
|
options.smtpserver = getConfig('smtpserver', 'localhost', options.configfile)
|
|
options.sender = getConfig('sender', 'donotreply@localhost.com', options.configfile)
|
|
options.recipients = list(getConfig('recipients', 'noone@localhost.com', options.configfile).split(','))
|
|
|
|
if __name__ == '__main__':
|
|
parser = OptionParser()
|
|
parser.add_option("-c", dest='configfile', default=sys.argv[0].replace('.py', '.conf'), help="configuration file to use")
|
|
(options, args) = parser.parse_args()
|
|
initConfig()
|
|
initLogger()
|
|
main()
|