commit 97e5dddc61ba7b904964dfd6dac7c2a4a18da281 Author: Sascha Rommelfangen Date: Thu Apr 27 13:58:49 2017 +0200 initial commit diff --git a/MUA/Apple/Mail/MISP Mail Rule Action.scptd b/MUA/Apple/Mail/MISP Mail Rule Action.scptd new file mode 120000 index 0000000..7650689 --- /dev/null +++ b/MUA/Apple/Mail/MISP Mail Rule Action.scptd @@ -0,0 +1 @@ +/Users/rommelfs/Library/Application Scripts/com.apple.mail/MISP Mail Rule Action.scptd \ No newline at end of file diff --git a/mail_to_misp.py b/mail_to_misp.py new file mode 100755 index 0000000..f4e77e5 --- /dev/null +++ b/mail_to_misp.py @@ -0,0 +1,126 @@ +#!/usr/bin/python + +import urlmarker +import sys +import re +from pyfaup.faup import Faup +from pymisp import PyMISP +from defang import refang +import dns.resolver +import mail_to_misp_config as config + +debug = config.debug +if debug: + debug_out_file = config.debug_out_file + target = open(debug_out_file, 'w') + target.write("New debug session opened") +try: + email_data = str(sys.argv[1]) + email_subject = str(sys.argv[2]) +except: + if debug: + target.write("FATAL ERROR: Not all required input received") + sys.exit(1) + +if debug: + target.write(email_subject) + target.write(email_data) + +misp_url = config.misp_url +misp_key = config.misp_key +misp_verifycert = config.misp_verifycert + +resolver = dns.resolver.Resolver(configure=False) +resolver.nameservers = config.nameservers + +excludelist = config.excludelist +externallist = config.externallist + +malwaretags = config.malwaretags +dependingtags = config.dependingtags + +# Ignore lines in body of message +email_data = re.sub(".*From: .*\n?","", email_data) +email_data = re.sub(".*Sender: .*\n?","", email_data) +email_data = re.sub(".*Sender IP: .*\n?","", email_data) +email_data = re.sub(".*Reply-To: .*\n?","", email_data) +email_data = re.sub(".*Registrar WHOIS Server: .*\n?","", email_data) +email_data = re.sub(".*Registrar: .*\n?","", email_data) +email_data = re.sub(".*Domain Status: .*\n?","", email_data) +email_data = re.sub(".*Registrant Email: .*\n?","", email_data) +email_data = re.sub(".*IP Location: .*\n?","", email_data) + +# Remove tags from subject +email_subject = re.sub("[\(\[].*?[\)\]]", "", email_subject) +# Remove "Re: " from subject +email_subject = re.sub("Re: ", "", email_subject) + + +def init(url, key): + return PyMISP(url, key, misp_verifycert, 'json') + +# Evaluate classification +tlptags = config.tlptags +for tag in tlptags: + for alternativetag in tlptags[tag]: + if alternativetag in email_data.lower(): + tlp_tag = tag + +# Create the MISP event +misp = init(misp_url, misp_key) +new_event = misp.new_event(info=email_subject, distribution=0, threat_level_id=3, analysis=1) +misp.add_tag(new_event, tlp_tag) + +# Add additional tags depending on others +for tag in dependingtags: + if tag in tlp_tag: + for dependingtag in dependingtags[tag]: + misp.add_tag(new_event, dependingtag) + +# Extract IOCs +email_data = refang(email_data) +urllist = re.findall(urlmarker.WEB_URL_REGEX,email_data) +urllist += re.findall(urlmarker.IP_REGEX,email_data) +if debug: + target.write(str(urllist)) + +# Init Faup +f = Faup() + +for malware in malwaretags: + if malware in email_subject.lower(): + for tag in malwaretags[malware]: + misp.add_tag(new_event, tag) + +# Add IOCs and expanded information to MISP +for entry in urllist: + f.decode(entry) + domainname = f.get_domain().lower() + if debug: + target.write(domainname + "\n") + if domainname not in excludelist: + if domainname in externallist: + misp.add_named_attribute(new_event, 'link', entry, category='External analysis', to_ids=False) + else: + if debug: + target.write(entry + "\n") + misp.add_url(new_event, entry, category='Network activity', to_ids=True) + hostname = f.get_host().lower() + if debug: + target.write(hostname + "\n") + port = f.get_port() + comment = "" + if port: + comment = "on port: " + str(port) + misp.add_hostname(new_event, hostname, comment=comment, category='Network activity', to_ids=True) + try: + for rdata in dns.resolver.query(hostname, 'A'): + if debug: + target.write(str(rdata) + "\n") + misp.add_ipdst(new_event, str(rdata), category='Network activity', to_ids=True, comment=hostname) + except: + if debug: + target.write("DNS unsuccessful\n") +if debug: + target.close() + diff --git a/mail_to_misp_config.py-example b/mail_to_misp_config.py-example new file mode 100644 index 0000000..e9e56b6 --- /dev/null +++ b/mail_to_misp_config.py-example @@ -0,0 +1,28 @@ +#!/usr/bin/python + +misp_url = 'YOUR_MISP_URL' +misp_key = 'YOUR_KEY_HERE' # The MISP auth key can be found on the MISP web interface under the automation section +misp_verifycert = True + +debug = True +debug_out_file = '/tmp/mail_to_misp-debug.txt' +nameservers = ['149.13.33.69'] + +excludelist = ('google.com', 'microsoft.com') +externallist = ('virustotal.com', 'malwr.com', 'hybrid-analysis.com', 'emergingthreats.net') + +# TLP tag setup +# Tuples contain different variations of spelling +tlptags = { 'tlp:white': [ 'tlp:white', 'tlp: white' ], + 'tlp:green': [ 'tlp:green', 'tlp: green' ], + 'tlp:amber': [ 'tlp:amber', 'tlp: amber' ] + } + +malwaretags = { 'locky': [ 'ecsirt:malicious-code="ransomware"', 'misp-galaxy:ransomware="Locky"' ], + 'dridex': [ 'misp-galaxy:tool="dridex"' ], + 'netwire': [ 'Netwire RAT' ] + } +# Tags to be set depending on the presence of other tags +dependingtags = { 'tlp:white': [ 'circl:osint-feed' ] + } + diff --git a/urlmarker.py b/urlmarker.py new file mode 100755 index 0000000..e0c6779 --- /dev/null +++ b/urlmarker.py @@ -0,0 +1,25 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +url matching regex +http://daringfireball.net/2010/07/improved_regex_for_matching_urls +""" + + +""" +The regex patterns in this gist are intended to match any URLs, +including "mailto:foo@example.com", "x-whatever://foo", etc. For a +pattern that attempts only to match web URLs (http, https), see: +https://gist.github.com/gruber/8891611 +""" +ANY_URL_REGEX = r"""(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""" + +""" +The regex patterns in this gist are intended only to match web URLs -- http, +https, and naked domains like "example.com". For a pattern that attempts to +match all URLs, regardless of protocol, see: https://gist.github.com/gruber/249502 +""" +WEB_URL_REGEX = r"""(?i)\b((?:https?:(?:/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?:com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)/)(?:[^\s()<>{}\[\]]+|\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\))+(?:\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?