This repository has been archived by the owner on Mar 18, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
benthin
committed
Apr 19, 2017
1 parent
9c652a1
commit 8d9f8a6
Showing
207 changed files
with
12,289 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.