Skip to content
This repository has been archived by the owner on Mar 18, 2021. It is now read-only.

Commit

Permalink
add source code
Browse files Browse the repository at this point in the history
  • Loading branch information
benthin committed Apr 19, 2017
1 parent 9c652a1 commit 8d9f8a6
Show file tree
Hide file tree
Showing 207 changed files with 12,289 additions and 0 deletions.
104 changes: 104 additions & 0 deletions alerts/alert_sender.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import smtplib
import ssl
import traceback
import config
import logger
import gnupg
from email.mime.text import MIMEText


class EmailSender:

def __init__(self):
self.host = config.get_smtp_server_host()
self.port = config.get_smtp_server_port()
self.user = config.get_smtp_user()
self.password = config.get_smtp_password()
self.sender = config.get_smtp_sender()
self.receiver = config.get_smtp_receiver()
self.smtp_client = None

def send(self, email_body, subject='IVA Alert'):
email = self.create_email(subject, email_body)
return self.send_email(email)

def create_email(self, subject, body):
msg = create_mime_obj(body)
msg['Subject'] = subject
msg['From'] = self.sender
msg['To'] = self.receiver
return msg

def send_email(self, email):
logger.info('SMTP - trying to send email')
try:
self.create_smtp_client()
self.smtp_login()
self.smtp_send(email)
self.smtp_client.quit()
logger.info('SMTP - email successfully sent')
return True
except Exception:
logger.error('SMTP - unable to send email')
logger.error('SMTP - ' + str(traceback.format_exc()))
return False

def create_smtp_client(self):
if config.is_smtps_enabled():
self.smtp_client = smtplib.SMTP_SSL(self.host, self.port, context=create_ssl_context())
else:
self.smtp_client = smtplib.SMTP(self.host, self.port)
self.starttls()

def starttls(self):
if config.is_smtp_starttls_enabled():
try:
self.smtp_client.ehlo()
self.smtp_client.starttls(context=create_ssl_context())
except smtplib.SMTPHeloError:
logger.error('SMTP - The server did not reply properly to the HELO greeting')
except smtplib.SMTPException:
logger.error('SMTP - The server does not support the STARTTLS extension')
except RuntimeError:
logger.error('SMTP - SSL/TLS support is not available to your Python interpreter')

def smtp_login(self):
self.smtp_client.login(self.user, self.password)

def smtp_send(self, email):
self.smtp_client.sendmail(self.sender, [self.receiver], email.as_string())


def create_ssl_context():
if config.is_verify_smtp_server_cert_enabled():
return ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=config.get_smtp_ca_cert_file())
return None


def create_mime_obj(body):
if config.is_gpg_encryption_enabled():
return MIMEText(encrypt_body(body))
return MIMEText(body)


def encrypt_body(body):
gnu = create_gpg_obj()
import_keys(gnu)
return encrypt(body, gnu)


def create_gpg_obj():
return gnupg.GPG(homedir=config.get_gpg_home_dir())


def encrypt(body, gpg):
return str(gpg.encrypt(body, get_pub_key_fingerprint(gpg)))


def import_keys(gnu):
with open(config.get_gpg_pub_key_file(), 'r') as f:
gnu.import_keys(f.read())


def get_pub_key_fingerprint(gnu):
return gnu.list_keys()[0].get('fingerprint')
201 changes: 201 additions & 0 deletions alerts/alerts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import logger
import datetime
from database import Database
from wfn.encoding import Decoder
from collections import namedtuple
from alerts.alert_sender import EmailSender
from inventory.inventory import INVENTORY_DB_COLLECTION
from alerts.alerts_logger import generate_log_entry_for_added_cve, generate_log_entry_for_new_alert
from alerts.alerts_logger import generate_log_entry_for_removed_cve, generate_log_entry_for_changed_alert_status

ALERTS_DB_COLLECTION = 'alerts'
STATUS = namedtuple('STATUS', ['new', 'sent', 'closed', 'removed'])('new', 'sent', 'closed', 'removed')


class Alerts:

def __init__(self):
self.db = Database()

def insert_alert(self, software_id, cve_id):
if not self.alert_for_software_exists(software_id):
self.insert_new_alert_for_inventory_item(software_id, cve_id)
else:
self.add_new_cve_to_alert(software_id, cve_id)

def alert_for_software_exists(self, software_id):
return self.db.exist_doc_in_collection(get_id_as_dict(software_id), ALERTS_DB_COLLECTION)

def insert_new_alert_for_inventory_item(self, item_id, cve_id):
self.db.insert_document_in_collection(create_new_alert_dict(item_id, cve_id), ALERTS_DB_COLLECTION)

def add_new_cve_to_alert(self, item_id, new_cve):
alert = self.get_software_alert(item_id)
self.update_alert(item_id, generate_update_for_add_new_cve(alert, new_cve))
self.change_status_to_new(alert, item_id)

def change_status_to_new(self, alert, item_id):
if not is_status_new(alert):
self.change_alert_status(item_id, STATUS.new)

def remove_cve_from_alert(self, item_id, cve):
alert = self.get_software_alert(item_id)
self.update_alert(item_id, generate_update_for_remove_cve(alert, cve))
self.change_status_to_removed(alert, item_id)

def change_status_to_removed(self, alert, item_id):
if len(alert.get('cves')) == 0:
self.change_alert_status(item_id, STATUS.removed)

def change_alert_status(self, software_id, new_status):
alert = self.get_software_alert(software_id)
if can_status_be_changed(alert, new_status):
self.removed_cves_from_alert(software_id, alert, new_status)
self.update_alert(software_id, generate_update_for_change_status_alert(alert, new_status))
return False

def removed_cves_from_alert(self, software_id, alert, new_status):
if new_status == STATUS.removed:
for cve in alert.get('cves'):
self.remove_cve_from_alert(software_id, cve)

def update_alert(self, item_id, update):
self.db.update_document_in_collection(get_id_as_dict(item_id), update, ALERTS_DB_COLLECTION)

def get_software_alert(self, software_id):
return self.db.search_document_in_collection(get_id_as_dict(software_id), ALERTS_DB_COLLECTION)

def get_alerts(self):
alerts = []
alerts_status_new = self.get_alerts_of_status_sorted_by_date(STATUS.new)
alerts_status_sent = self.get_alerts_of_status_sorted_by_date(STATUS.sent)
alerts_status_closed = self.get_alerts_of_status_sorted_by_date(STATUS.closed)
alerts_status_removed = self.get_alerts_of_status_sorted_by_date(STATUS.removed)
alerts.extend(alerts_status_new)
alerts.extend(alerts_status_sent)
alerts.extend(alerts_status_closed)
alerts.extend(alerts_status_removed)
return alerts

def get_alerts_of_status_sorted_by_date(self, status):
return list(sort_alerts_by_date(self.db.search_documents_in_collection({'status': status}, ALERTS_DB_COLLECTION)))

def update_notes(self, software_id, notes):
self.db.update_document_in_collection(get_id_as_dict(software_id), {'notes': notes}, ALERTS_DB_COLLECTION)

def get_number_of_new_alerts(self):
return self.get_number_of_alerts_by_status(STATUS.new)

def get_number_of_sent_alerts(self):
return self.get_number_of_alerts_by_status(STATUS.sent)

def get_number_of_alerts_by_status(self, status):
return self.db.get_number_of_documents_in_collection(ALERTS_DB_COLLECTION, {'status': status})

def send_sw_alert_by_email(self, software_id):
software = self.get_software(software_id)
alert = self.get_software_alert(software_id)
sw_alert_email = create_sw_alert_email(alert, software)
return self.send(sw_alert_email, software)

def send(self, alert_mail, software):
sw_string = software.get('product') + ' ' + software.get('product') + ' ' + software.get('version')
logger.info('ALERTS - sending notification for ' + sw_string)
was_sent = EmailSender().send(alert_mail)
if was_sent:
logger.info('ALERTS - notification for ' + sw_string + ' successfully sent')
self.change_alert_status(software.get('id'), new_status=STATUS.sent)
return True
logger.error('ALERTS - failed to sent notification for ' + sw_string)
return False

def get_software(self, software_id):
return self.db.search_document_in_collection({'id': software_id}, INVENTORY_DB_COLLECTION)


def create_new_alert_dict(software_id, cve_id):
return {'generated_on': datetime.datetime.utcnow(),
'software_id': software_id,
'cves': [cve_id],
'status': STATUS.new,
'log': [generate_log_entry_for_new_alert(cve_id)],
'notes': ''}


def get_id_as_dict(item_id):
return {'software_id': item_id}


def update_log(alert, log_entry):
log = alert.get('log')
log.append(log_entry)
return log


def update_cves(alert, cve, option):
cves = alert.get('cves')
if option == 'append':
cves.append(cve)
elif option == 'remove':
cves.remove(cve)
return cves


def sort_alerts_by_date(alerts):
return alerts.sort('generated_on', 1)


def can_status_be_changed(alert, new_status):
if alert is not None:
if (new_status == 'new' and len(alert.get('cves')) == 0) and current_status_close_or_removed(alert.get('status')):
return False
return True
return False


def current_status_close_or_removed(status):
return status == STATUS.closed or status == STATUS.removed


def generate_update_for_add_new_cve(alert, new_cve):
return {'cves': update_cves(alert, new_cve, 'append'),
'log': update_log(alert, generate_log_entry_for_added_cve(new_cve))}


def generate_update_for_remove_cve(alert, cve):
return {'cves': update_cves(alert, cve, 'remove'),
'log': update_log(alert, generate_log_entry_for_removed_cve(cve))}


def generate_update_for_change_status_alert(alert, new_status):
return {'status': new_status,
'log': update_log(alert, generate_log_entry_for_changed_alert_status(alert.get('status'), new_status))}


def is_status_new(alert):
return alert.get('status') == STATUS.new


def create_sw_alert_email(alert, software):
email = 'Generated on: ' + str(alert.get('generated_on')) + '\n\n' \
'Software ID: ' + software.get('id') + '\n\n' \
'Product: ' + software.get('product') + '\n\n' \
'Vendor: ' + software.get('vendor') + '\n\n' \
'Version: ' + software.get('version') + '\n\n' \
'CPE: ' + get_software_cpe(software) + '\n\n' \
'CVEs: ' + str(alert.get('cves')) + '\n\n' \
'Status: ' + alert.get('status') + '\n\n' \
'Log:\n' + format_log(alert.get('log')) + '\n' \
'Notes: ' + alert.get('notes')
return email


def get_software_cpe(software):
return Decoder.decode_non_alphanumeric_characters((software.get('cpe').get('uri_binding')))


def format_log(log):
log_str = ''
for entry in log:
log_str += str(entry.get('date')) + ': '+entry.get('event')+'\n'
return log_str
27 changes: 27 additions & 0 deletions alerts/alerts_logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import datetime


def generate_log_entry_for_new_alert(cve):
return generate_log_entry('Alert generated due to ' + cve)


def generate_log_entry_for_added_cve(cve):
return generate_log_entry(cve + ' was added')


def generate_log_entry_for_removed_cve(cve):
return generate_log_entry(cve + ' was removed')


def generate_log_entry_for_changed_alert_status(old_status, new_status):
return generate_log_entry('Alert status changed: ' + old_status + ' to ' + new_status)


def generate_log_entry(event):
return {'date': get_date(), 'event': event}


def get_date():
return datetime.datetime.utcnow()


52 changes: 52 additions & 0 deletions config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[test-section]
test-option=test option

[database]
host=localhost
port=27017
name=iva
authentication=0
user=user
password=password

[inventory-database]
host=localhost
user=root
password=123
name=glpi

[frontend]
host=192.168.56.125
port=8080

[cve-search]
dir=/home/luis/iva_deb/iva/cve_search
db=cvedb
url=http://192.168.56.125:5000/cve/

[smtp]
host=172.17.0.2
port=25
user=test
password=123
sender=iva
receiver=test@localdomain
smtps=0
starttls=1
verify_server_cert=0
ca_cert_file=/usr/local/share/iva/ssl/smtp/ca_cert.pem

[gpg]
required=0
home_dir=/usr/local/share/iva/gpg
pub_key_file=/usr/local/share/iva/gpg/0xF4G24G5Q.asc

[ldap]
host=192.168.1.1
port=389
base_dn=ou=users,dc=honeynet,dc=de
tls=dsdsd
cacert=/path/to/cacert.pem

[logging]
file=iva.log
Loading

0 comments on commit 8d9f8a6

Please sign in to comment.