From ee0086114615adcd3c1f3633b4fd311fa5c86f24 Mon Sep 17 00:00:00 2001 From: Sean Whalen Date: Thu, 25 Oct 2018 01:51:03 -0400 Subject: [PATCH] 4.3.8 --- CHANGELOG.md | 9 ++++++++ parsedmarc/__init__.py | 46 ++++++++++++++++++++++++++++----------- parsedmarc/__version__.py | 2 +- parsedmarc/cli.py | 20 ++++++++++++++++- 4 files changed, 62 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a87b08..360f311 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +4.3.8 +----- + +- Fix decoding of attachments inside forensic samples +- Add CLI option `--imap-skip-certificate-verification` +- Add optional `ssl_context` argument for `get_dmarc_reports_from_inbox()` +and `watch_inbox()` +- Debug logging improvements + 4.3.7 ----- diff --git a/parsedmarc/__init__.py b/parsedmarc/__init__.py index cc1226f..cf4be2a 100644 --- a/parsedmarc/__init__.py +++ b/parsedmarc/__init__.py @@ -819,6 +819,7 @@ def get_dmarc_reports_from_inbox(host=None, connection=None, port=None, ssl=True, + ssl_context=None, move_supported=None, reports_folder="INBOX", archive_folder="Archive", @@ -838,6 +839,7 @@ def get_dmarc_reports_from_inbox(host=None, connection: An IMAPCLient connection to reuse port: The mail server port ssl (bool): Use SSL/TLS + ssl_context (SSLContext): A SSL context move_supported: Indicate if the IMAP server supports the MOVE command (autodetect if None) reports_folder: The IMAP folder where reports can be found @@ -882,9 +884,12 @@ def get_dmarc_reports_from_inbox(host=None, if connection: server = connection else: + if ssl_context is None: + ssl_context = create_default_context() server = imapclient.IMAPClient(host, port=port, ssl=ssl, + ssl_context=ssl_context, use_uid=True) server.login(user, password) @@ -925,7 +930,8 @@ def get_dmarc_reports_from_inbox(host=None, if not server.folder_exists(aggregate_reports_folder): server.create_folder(aggregate_reports_folder) logger.debug( - "Creating IMAP folder: {0}".format(archive_folder)) + "Creating IMAP folder: {0}".format( + aggregate_reports_folder)) except imapclient.exceptions.IMAPClientError: # Only replace / with . when . doesn't work # This usually indicates a dovecot IMAP server @@ -967,6 +973,7 @@ def get_dmarc_reports_from_inbox(host=None, server = imapclient.IMAPClient(host, port=port, ssl=ssl, + ssl_context=ssl_context, use_uid=True) server.login(user, password) server.select_folder(reports_folder) @@ -1030,6 +1037,7 @@ def get_dmarc_reports_from_inbox(host=None, server = imapclient.IMAPClient(host, port=port, ssl=ssl, + ssl_context=ssl_context, use_uid=True) server.login(user, password) server.select_folder(reports_folder) @@ -1060,10 +1068,13 @@ def get_dmarc_reports_from_inbox(host=None, logger.debug("IMAP error: {0}".format( error.__str__())) logger.debug("Reconnecting to IMAP") - server = imapclient.IMAPClient(host, - port=port, - ssl=ssl, - use_uid=True) + server = imapclient.IMAPClient( + host, + port=port, + ssl=ssl, + ssl_context=ssl_context, + use_uid=True + ) server.login(user, password) server.select_folder(reports_folder) move_messages([msg_uid], @@ -1095,10 +1106,12 @@ def get_dmarc_reports_from_inbox(host=None, logger.debug("IMAP error: {0}".format( error.__str__())) logger.debug("Reconnecting to IMAP") - server = imapclient.IMAPClient(host, - port=port, - ssl=ssl, - use_uid=True) + server = imapclient.IMAPClient( + host, + port=port, + ssl=ssl, + ssl_context=ssl_context, + use_uid=True) server.login(user, password) server.select_folder(reports_folder) move_messages([msg_uid], @@ -1116,6 +1129,7 @@ def get_dmarc_reports_from_inbox(host=None, connection=connection, port=port, ssl=ssl, + ssl_context=ssl_context, move_supported=move_supported, reports_folder=reports_folder, archive_folder=archive_folder, @@ -1340,9 +1354,10 @@ def email_results(results, host, mail_from, mail_to, port=0, def watch_inbox(host, username, password, callback, port=None, ssl=True, - reports_folder="INBOX", archive_folder="Archive", - delete=False, test=False, wait=30, nameservers=None, - dns_timeout=6.0, strip_attachment_payloads=False): + ssl_context=None, reports_folder="INBOX", + archive_folder="Archive", delete=False, test=False, wait=30, + nameservers=None, dns_timeout=6.0, + strip_attachment_payloads=False): """ Use an IDLE IMAP connection to parse incoming emails, and pass the results to a callback function @@ -1354,6 +1369,7 @@ def watch_inbox(host, username, password, callback, port=None, ssl=True, callback: The callback function to receive the parsing results port: The mail server port ssl (bool): Use SSL/TLS + ssl_context (SSLContext): A SSL context reports_folder: The IMAP folder where reports can be found archive_folder: The folder to move processed mail to delete (bool): Delete messages after processing them @@ -1369,7 +1385,11 @@ def watch_inbox(host, username, password, callback, port=None, ssl=True, af = archive_folder ns = nameservers dt = dns_timeout - server = imapclient.IMAPClient(host, port=port, ssl=ssl, use_uid=True) + if ssl_context is None: + ssl_context = create_default_context() + server = imapclient.IMAPClient(host, port=port, ssl=ssl, + ssl_context=ssl_context, + use_uid=True) try: server.login(username, password) diff --git a/parsedmarc/__version__.py b/parsedmarc/__version__.py index 557457d..5087b1d 100644 --- a/parsedmarc/__version__.py +++ b/parsedmarc/__version__.py @@ -2,7 +2,7 @@ import platform -__version__ = "4.3.7" +__version__ = "4.3.8" USER_AGENT = "Mozilla/5.0 ((0 {1})) parsedmarc/{2}".format( platform.system(), diff --git a/parsedmarc/cli.py b/parsedmarc/cli.py index 3ca25a1..b156dd3 100644 --- a/parsedmarc/cli.py +++ b/parsedmarc/cli.py @@ -9,6 +9,7 @@ from glob import glob import logging from collections import OrderedDict import json +from ssl import CERT_NONE, create_default_context from elasticsearch.exceptions import ElasticsearchException @@ -109,6 +110,10 @@ def _main(): arg_parser.add_argument("-u", "--user", help="IMAP user") arg_parser.add_argument("-p", "--password", help="IMAP password") arg_parser.add_argument("--imap-port", default=None, help="IMAP port") + arg_parser.add_argument("--imap-skip-certificate-verification", + action="store_true", + default=False, + help="Skip certificate verification for IMAP") arg_parser.add_argument("--imap-no-ssl", action="store_true", default=False, help="Do not use SSL/TLS when connecting to IMAP") @@ -290,11 +295,18 @@ def _main(): ns = args.nameservers sa = args.strip_attachment_payloads ssl = True + ssl_context = None + if args.imap_skip_certificate_verification: + logger.debug("Skipping IMAP certificate verification") + ssl_context = create_default_context() + ssl_context.check_hostname = False + ssl_context.verify_mode = CERT_NONE if args.imap_no_ssl: ssl = False reports = get_dmarc_reports_from_inbox(host=args.host, port=args.imap_port, ssl=ssl, + ssl_context=ssl_context, user=args.user, password=args.password, reports_folder=rf, @@ -339,12 +351,18 @@ def _main(): if args.host and args.watch: logger.info("Watching for email - Quit with ctrl-c") ssl = True + ssl_context = None + if args.imap_skip_certificate_verification: + logger.debug("Skipping IMAP certificate verification") + ssl_context = create_default_context() + ssl_context.check_hostname = False + ssl_context.verify_mode = CERT_NONE if args.imap_no_ssl: ssl = False try: sa = args.strip_attachment_payloads watch_inbox(args.host, args.user, args.password, process_reports, - port=args.imap_port, ssl=ssl, + port=args.imap_port, ssl=ssl, ssl_context=ssl_context, reports_folder=args.reports_folder, archive_folder=args.archive_folder, delete=args.delete, test=args.test, nameservers=args.nameservers,