示例#1
0
    def check_outlook_message_id(self, msg, target=None):
        message_id = msg.msg.get("Message-ID")
        if not message_id:
            return
        msg_regex = Regex(r"^<[0-9a-f]{4}([0-9a-f]{8})\$[0-9a-f]{8}\$["
                          r"0-9a-f]{8}\@")
        regex = msg_regex.search(message_id)
        if not regex:
            return False
        timetocken = int(regex.group(1), 16)

        date = msg.msg.get("Date")
        x = 0.0023283064365387
        y = 27111902.8329849
        mail_date = time.mktime(email.utils.parsedate(date))
        expected = int((mail_date * x) + y)
        if abs(timetocken - expected) < 250:
            return False
        received = msg.msg.get("Received")
        received_regex = Regex(r"(\s.?\d+ \S\S\S \d+ \d+:\d+:\d+ \S+).*?$")
        regex = received_regex.search(received)
        received_date = 0
        if regex:
            received_date = time.mktime(email.utils.parsedate(regex.group()))
        expected = int((received_date * x) + y)
        return abs(timetocken - expected) >= 250
示例#2
0
    def check_for_forged_yahoo_received_headers(self, msg, target=None):
        """Check for forged yahoo received headers"""
        from_addr = ''.join(msg.get_all_addr_header("From"))
        rcvd = ''.join(msg.get_decoded_header("Received"))
        if "yahoo.com" not in from_addr:
            return False
        if (msg.get_decoded_header("Resent-From") and
                msg.get_decoded_header("Resent-To")):
            xrcvd = ''.join(msg.get_decoded_header("X-Received"))
            rcvd = xrcvd if xrcvd else rcvd

        if self.gated_through_received_hdr_remover(msg):
            return False
        for relay in msg.untrusted_relays + msg.trusted_relays:
            rdns = relay.get("rdns")
            if rdns and "yahoo.com" in rdns:
                return False
        if Regex(r"by web\S+\.mail\S*\.yahoo\.com via HTTP").search(rcvd):
            return False
        if Regex(r"by smtp\S+\.yahoo\.com with SMTP").search(rcvd):
            return False
        yahoo_ip_re = Regex(
            r"from\s+\[{}\]\s+by\s+\S+\."
            r"(?:groups|scd|dcn)\.yahoo\.com\s+with\s+NNFMP".format(
                IP_ADDRESS.pattern), re.X)
        if yahoo_ip_re.search(rcvd):
            return False
        if (Regex(r"\bmailer\d+\.bulk\.scd\.yahoo\.com\b").search(rcvd) and
                    from_addr.rsplit("@", 1)[-1] == "reply.yahoo.com"):
            return False
        if Regex("by \w+\.\w+\.yahoo\.com \(\d+\.\d+\.\d+\/\d+\.\d+\.\d+\)"
                 "(?: with ESMTP)? id \w+").search(rcvd):
            return False
        return True
示例#3
0
    def check_for_to_in_subject(self, msg, test, target=None):
        """
        Check if to address is in Subject field.

        If it is called with 'address', check if full address is in subject,
        else if the parameter is 'user', then check if user name is in subject.
        """
        full_to = msg.get_all_addr_header('To')
        if not full_to:
            return False
        subject = msg.msg.get('Subject', "")
        for to in full_to:
            if test == "address":
                subject_regex = Regex(r".*" + re.escape(to) + r".*", re.I)
                if subject_regex.search(subject):
                    return True
            elif test == "user":
                regex = re.match("(\S+)@.*", to)
                if regex:
                    to = regex.group(1)
                    if Regex(r"^" + re.escape(to) + "$").search(subject):
                        return True
                    if Regex(r"(?:re|fw):\s*(?:\w+\s+)?" + re.escape(to) + "$")\
                            .search(subject):
                        return True
                    if Regex(r"\s*" + re.escape(to) + "[,:;!?-]$")\
                            .search(subject):
                        return True
                    if Regex(r"^" + re.escape(to) + "\s*[,:;!?-](\s).*")\
                            .search(subject):
                        return True
        return False
示例#4
0
 def check_for_msn_groups_headers(self, msg, target=None):
     """Check if the email's destination is a msn group"""
     to = ''.join(msg.get_decoded_header('To'))
     if not Regex(r"<(\S+)\@groups\.msn\.com>").search(to):
         return False
     listname = Regex(r"<(\S+)\@groups\.msn\.com>").match(to).groups()[0]
     server_rgx = Regex(r"from mail pickup service by "
                        r"((?:p\d\d\.)groups\.msn\.com)\b")
     server = ''
     for rcvd in msg.get_decoded_header('Received'):
         if server_rgx.search(rcvd):
             server = server_rgx.search(rcvd).groups()[0]
             break
     if not server:
         return False
     message_id = ''.join(msg.get_decoded_header('Message-Id'))
     if listname == "notifications":
         if not Regex(r"^<\S+\@{0}".format(server)).search(message_id):
             return False
     else:
         msn_addr = Regex(r"^<{0}-\S+\@groups\.msn\.com>".format(listname))
         if not msn_addr.search(message_id):
             return False
         msn_addr = "{0}[email protected]".format(listname)
         if msg.sender_address != msn_addr:
             return False
     return True
示例#5
0
 def hostname_to_domain(hostname):
     if not Regex(r"[a-zA-Z]").match(hostname):
         return hostname
     parts = hostname.split(".")
     if len(parts) > 1 and Regex(r"(?:\S{3,}|ie|fr|de)").match(parts[-1]):
         return ".".join(parts[-2:])
     elif len(parts) > 2:
         return ".".join(parts[-3:])
     else:
         return hostname
示例#6
0
 def check_unresolved_template(self, msg, target=None):
     message = msg.raw_msg
     headers = message.split("\n")
     for header in headers:
         if Regex(r"%[A-Z][A-Z_-]").search(header) and not \
                 Regex(r"^(?:x-vms-to|x-uidl|x-face|to|cc|from|subject|"
                       r"references|in-reply-to|(?:x-|resent-|"
                       r"x-original-)?message-id):").search(header.lower()):
             return True
     return False
示例#7
0
 def check_for_fake_aol_relay_in_rcvd(self, msg, target=None):
     """Check for common AOL fake received header."""
     for recv in msg.get_decoded_header("Received"):
         if not Regex(r" rly-[a-z][a-z]\d\d\.", re.I).search(recv):
             continue
         if Regex(r"\/AOL-\d+\.\d+\.\d+\)").search(recv):
             continue
         if Regex(r"ESMTP id (?:RELAY|MAILRELAY|MAILIN)").search(recv):
             continue
         return True
     return False
示例#8
0
 def check_ratware_name_id(self, msg, target=None):
     """Check if message-id is ratware or not."""
     message_id = msg.msg.get("Message-Id")
     from_header = msg.msg.get("From")
     if not message_id and not from_header:
         return False
     regex = Regex(r"<[A-Z]{28}\.([^>]+?)>").search(message_id)
     if regex:
         if Regex(r"\"[^\"]+\"\s*<" + regex.group(1) + ">").search(
                 from_header):
             return True
     return False
示例#9
0
 def check_messageid_not_usable(self, msg, target=None):
     list_unsubscribe = msg.msg.get("List-Unsubscribe")
     if list_unsubscribe:
         if Regex(r"<mailto:(?:leave-\S+|\S+-unsubscribe)\@\S+>$").search(
                 list_unsubscribe):
             return True
     if self.gated_through_received_hdr_remover(msg):
         return True
     received = msg.msg.get("Received")
     if Regex(r"/CWT/DCE\)").search(received):
         return True
     if Regex(r"iPlanet Messaging Server").search(received):
         return True
     return False
示例#10
0
 def _get_authors(self, msg):
     self.author_addresses = msg.get_addr_header("From")
     for header in self.author_addresses:
         match_domain = Regex("@([^@]+?)[ \t]*$").search(header)
         if match_domain:
             domain = match_domain.group(1)
             self.author_domains.append(domain.encode())
示例#11
0
 def _update_mime_text_info(self, msg, payload, part, text):
     charset = part.get_charset()
     text_count = self.get_local(msg, "mime_body_text_count")
     self.set_local(msg, "mime_body_text_count", text_count + 1)
     if part.get_content_subtype() == "plain":
         plain_characters_count = self.get_local(msg,
                                                 "plain_characters_count")
         self.set_local(msg, "plain_characters_count",
                        plain_characters_count + len(text))
         ascii_count = self.get_local(msg, "ascii_count")
         ascii_count += len(text)
         self.set_local(msg, "ascii_count", ascii_count)
         unicode_chars = Regex(r"(&\#x[0-9A-F]{4};)", re.X).search(text)
         unicode_count = 0
         if unicode_chars:
             unicode_count = self.get_local(msg, "unicode_count")
             unicode_count += len(unicode_chars.groups())
             self.set_local(msg, "unicode_count", unicode_count)
         # XXX This does not work properly anymore
         if not charset or charset == r"us-ascii":
             try:
                 payload.encode("ascii")
             except (UnicodeEncodeError, UnicodeDecodeError):
                 self.set_local(msg, "mime_ascii_text_illegal", True)
         if len(re.split("--", msg.raw_msg)) <= 4:
             self.set_local(msg, "mime_missing_boundary", True)
示例#12
0
    def _check_rbl(self, msg, rbl_server, qtype="A", subtest=None):
        """Checks all the IPs of this message on the specified
        list.

        :param msg: The message that we perform the check on.
        :param rbl_server: The RBL list to check
        :param qtype: The DNS record type to check
        :param subtest: If specified then an additional check
          is done on the result of the DNS lookup by matching
          this regular expression against the result.
        :return: True if there is a match and the subtest
          passes and False otherwise.
        """
        if self.ctxt.skip_rbl_checks:
            return False

        if subtest is not None:
            try:
                subtest = Regex(subtest)
            except re.error as e:
                self.ctxt.err("Invalid regex %s: %s", subtest, e)
                return False

        for ip in msg.get_untrusted_ips():
            rev = self.ctxt.dns.reverse_ip(ip)
            results = self.ctxt.dns.query("%s.%s" % (rev, rbl_server), qtype)

            if results and not subtest:
                return True

            for result in results:
                if subtest.match(str(result)):
                    return True
        return False
示例#13
0
 def gated_through_received_hdr_remover(self, msg, target=None):
     """Check if the email is gated through ezmlm"""
     txt = ''.join(msg.get_decoded_header("Mailing-List"))
     rcvd = ''.join(msg.get_decoded_header("Received"))
     if Regex(r"^contact \S+\@\S+\; run by ezmlm$").search(txt):
         dlto = ''.join(msg.get_decoded_header("Delivered-To"))
         mailing_list_re = Regex(r"^mailing list \S+\@\S+")
         qmail_re = Regex(r"qmail \d+ invoked (?:from "
                          r"network|by .{3,20})\); \d+ ... \d+")
         if mailing_list_re.search(dlto) and qmail_re.search(rcvd):
             return True
     if not rcvd:
         return True
     if Regex(r"from groups\.msn\.com \(\S+\.msn\.com ").search(rcvd):
         return True
     return False
示例#14
0
 def check_address_in_list(self, addresses, list_name):
     """Check if addresses match the regexes from list_name.
     """
     for address in addresses:
         for regex in self[list_name]:
             if Regex(regex).search(address):
                 return True
     return False
示例#15
0
 def _check_for_forged_received(self, msg):
     mismatch_from = 0
     mismatch_ip_helo = 0
     hostname_re = Regex(r"^\w+(?:[\w.-]+\.)+\w+$")
     ip_re = Regex(r"^(\d+\.\d+)\.\d+\.\d+")
     for index, relay in enumerate(msg.untrusted_relays):
         from_ip = relay.get("ip")
         from_host = self.hostname_to_domain(relay.get("rdns"))
         by_host = self.hostname_to_domain(relay.get("by"))
         helo_host = self.hostname_to_domain(relay.get("helo"))
         if not by_host or not hostname_re.match(by_host):
             continue
         if from_host and from_ip == '127.0.0.1':
                 from_host = "undef"
         self.ctxt.log.debug("eval: forged-HELO: from=%s helo=%s by=%s" % (
             from_host if from_host else "(undef)",
             helo_host if helo_host else "(undef)",
             by_host if by_host else "(undef)"
         ))
         try:
             ip_netmask_16 = ipaddress.IPv4Network(from_ip).supernet(16)
         except ValueError:
             ip_netmask_16 = ""
         try:
             helo_netmask_16 = ipaddress.IPv4Network(helo_host).supernet(16)
         except ValueError:
             helo_netmask_16 = ""
         if ip_netmask_16 and helo_netmask_16 and from_ip != helo_host:
             if (ip_netmask_16 != helo_netmask_16 and
                     not IP_PRIVATE.match(helo_host)):
                 self.ctxt.log.debug("eval: forged-HELO: massive mismatch "
                                     "on IP-addr HELO: %s != %s" %
                                     (helo_host, from_ip))
                 mismatch_ip_helo += 1
         prev = msg.untrusted_relays[index - 1]
         if prev and index > 0:
             prev_from_host = prev.get("rdns")
             if (hostname_re.match(prev_from_host)
                 and by_host != prev_from_host
                 and not self._helo_forgery_whitelisted(by_host,
                                                        prev_from_host)):
                 self.ctxt.log.debug("eval: forged-HELO: mismatch on from: "
                                     "%s != %s" % (prev_from_host, by_host))
                 mismatch_from += 1
     self.set_global("mismatch_from", mismatch_from)
     self.set_global("mismatch_ip_helo", mismatch_ip_helo)
示例#16
0
 def check_ratware_envelope_from(self, msg, target=None):
     """Check if envelope-from address is ratware or not."""
     to_header = msg.msg.get("To")
     envelope_from = msg.sender_address
     if not to_header or not envelope_from:
         return False
     if Regex(r"^SRS\d=").search(envelope_from):
         return False
     regex = Regex(r"^([^@]+)@(.+)$").search(to_header)
     if regex:
         user = regex.group(1)
         dom = regex.group(2)
         if not self.is_domain_valid(dom):
             return False
         if Regex(r"\b" + dom + "." + user + "@").search(envelope_from):
             return True
     return False
示例#17
0
 def check_found_forged(self, address, found_forged):
     """If it is forged, check the address in list """
     if found_forged:
         wlist = self['parsed_whitelist_allow_relays']
         for addr in wlist:
             if Regex(addr).search(address):
                 found_forged = 0
                 break
     return found_forged
示例#18
0
    def check_freemail_header(self, msg, header, regex=None, target=None):
        """Check all possible 'from' headers to see if sender
        is freemail. It is possible to provide a regex
        rule to match against too.

        Returns True if it is or False otherwise
        """
        self.ctxt.log.debug("FreeMail::Plugin check_freemail_header"
                            " %s", 'with regex: ' + regex if regex else '')
        if not header:
            self.ctxt.log.warn("FreeMail::Plugin check_freemail_header"
                               " requires an argument")
            return False
        if regex:
            try:
                check_re = Regex(regex).compile()
            except re.error:
                self.ctxt.log.warn("FreeMail::Plugin check_freemail_header"
                                   " regex error")
                return False
        else:
            check_re = None
        if not msg.msg.get(header, None):
            self.ctxt.log.debug(
                "FreeMail::Plugin check_freemail_header"
                " header: %s not found", header)
            return False
        header_emails = self.get_global('email_re').findall(msg.msg[header])
        if not header_emails:
            self.ctxt.log.debug(
                "FreeMail::Plugin check_freemail_header"
                " no emails found in header: %s", header)
            return False
        for email in header_emails:
            if self._is_freemail(email):
                if check_re and not check_re.search(email):
                    return False
                elif check_re and check_re.search(email):
                    self.ctxt.log.debug(
                        "FreeMail::Plugin check_freemail_header"
                        " HIT! %s is freemail and matches regex", email)
                    result = ("Header " + header +
                              " is freemail and matches regex")
                    if self["freemail_add_describe_email"]:
                        _email = "(" + email.replace("@", "[at]") + ")"
                        result = result + "\n\t" + _email
                    return str(result)
                self.ctxt.log.debug(
                    "FreeMail::Plugin check_freemail_header"
                    " HIT! %s is freemail", email)
                result = "Header " + header + " is freemail"
                if self["freemail_add_describe_email"]:
                    _email = "(" + email.replace("@", "[at]") + ")"
                    result = result + "\n\t" + _email
                return str(result)
        return False
示例#19
0
    def check_freemail_from(self, msg, regex=None, target=None):
        """Check if in specified header gave as parameter
        is a freemail or no. It is possible to provide a regex
        rule to match against too.

        Returns True if it is or False otherwise
        """
        self.ctxt.log.debug(
            "FreeMail::Plugin Eval rule check_freemail_from"
            " %s", 'with regex: ' + regex if regex else '')
        all_from_headers = [
            'From', 'Envelope-Sender', 'Resent-Sender', 'X-Envelope-From',
            'EnvelopeFrom', 'Resent-From'
        ]
        header_emails = []
        if regex:
            try:
                check_re = Regex(regex)
            except re.error:
                self.ctxt.log.warn("FreeMail::Plugin check_freemail_from"
                                   " regex error")
                return False
        else:
            check_re = None

        header_emails = msg.get_all_from_headers_addr()
        header_emails = sorted(set(header_emails))

        if not header_emails:
            self.ctxt.log.debug(
                "FreeMail::Plugin check_freemail_from"
                " no emails found in from headers: %s", all_from_headers)
            return False
        for email in header_emails:
            if self._is_freemail(email):
                if check_re and not check_re.search(email):
                    return False
                elif check_re and check_re.search(email):
                    self.ctxt.log.debug(
                        "FreeMail::Plugin check_freemail_from"
                        " HIT! %s is freemail and matches regex", email)
                    result = "Sender address is freemail and matches regex"
                    if self["freemail_add_describe_email"]:
                        _email = "(" + email.replace("@", "[at]") + ")"
                        result = result + "\n\t" + _email
                    return str(result)
                self.ctxt.log.debug(
                    "FreeMail::Plugin check_freemail_from"
                    " HIT! %s is freemail", email)
                result = "Sender address is freemail"
                if self["freemail_add_describe_email"]:
                    _email = "(" + email.replace("@", "[at]") + ")"
                    result = result + "\n\t" + _email
                return str(result)
        return False
示例#20
0
 def check_for_forged_juno_received_headers(self, msg, target=None):
     from_addr = ''.join(msg.get_all_addr_header("From"))
     if not from_addr.rsplit("@", 1)[-1].endswith("juno.com"):
         return False
     if self.gated_through_received_hdr_remover(msg):
         return False
     xorig = ''.join(msg.get_decoded_header("X-Originating-IP"))
     xmailer = ''.join(msg.get_decoded_header("X-Mailer"))
     rcvd = ''.join(msg.get_decoded_header("Received"))
     if xorig != "":
         juno_re = Regex(r"from.*\b(?:juno|untd)\.com.*"
                         r"[\[\(]{0}[\]\)].*by".format(IP_ADDRESS.pattern), re.X)
         cookie_re = Regex(r" cookie\.(?:juno|untd)\.com ")
         if not juno_re.search(rcvd) and not cookie_re.search(rcvd):
             return True
         if "Juno " not in xmailer:
             return True
     else:
         mail_com_re = Regex(r"from.*\bmail\.com.*\[{}\].*by".format(
             IP_ADDRESS.pattern), re.X)
         untd_com_re = Regex(r"from\s+(webmail\S+\.untd"
                             r"\.com)\s+\(\1\s+\[{}\]\)\s+by".format(
             IP_ADDRESS.pattern), re.X)
         if mail_com_re.search(rcvd) and not Regex(r"\bmail\.com").search(
                 xmailer):
             return True
         elif untd_com_re.search(rcvd) and not Regex(
                 r"^Webmail Version \d").search(xmailer):
             return True
         else:
             return True
     return False
示例#21
0
 def check_start(self, msg):
     """Verify that the domains are valid and separate wildcard
     domains from the rest."""
     domain_re = Regex(r'^[a-z0-9.*?-]+$')
     freemail_domains = self.get_global('freemail_domains')
     freemail_temp_wc = []
     for domain in freemail_domains[:]:
         if not domain_re.search(domain):
             freemail_domains.remove(domain)
             self.ctxt.log.warn(
                 "FreeMail::Plugin Invalid freemail domain: %s", domain)
         if '*' in domain:
             temp = domain.replace('.', '\.')
             temp = temp.replace('?', '.')
             temp = temp.replace('*', '[^.]*')
             freemail_temp_wc.append(temp)
     if freemail_temp_wc:
         wild_doms = r'\@(?:{0})$'.format('|'.join(freemail_temp_wc))
         self.set_global('freemail_domains_re', Regex(wild_doms))
     self.set_global('freemail_domains', freemail_domains)
     valid_tlds = (self.get_global('util_rb_tld') +
                   self.get_global('util_rb_2tld') +
                   self.get_global('util_rb_3tld'))
     tlds_re = r'(?:{0})'.format("|".join(valid_tlds))
     email_re = Regex(
         r"""
           (?=.{{0,64}}\@)				# limit userpart to 64 chars (and speed up searching?)
           (?<![a-z0-9!#\$%&'*+\/=?^_`{{|}}~-])	# start boundary
           (						# capture email
           [a-z0-9!#\$%&'*+\/=?^_`{{|}}~-]+		# no dot in beginning
           (?:\.[a-z0-9!#\$%&'*+\/=?^_`{{|}}~-]+)*	# no consecutive dots, no ending dot
           \@
           (?:[a-z0-9](?:[a-z0-9-]{{0,59}}[a-z0-9])?\.){{1,4}} # max 4x61 char parts (should be enough?)
           {tld}   # ends with valid tld
           )
           (?!(?:[a-z0-9-]|\.[a-z0-9]))		# make sure domain ends here
     """.format(tld=tlds_re), re.X | re.I)
     self.set_global('email_re', email_re)
     self.set_global('body_emails', set())
     self.set_global("check_if_parsed", False)
示例#22
0
    def check_for_unique_subject_id(self, msg, target=None):
        """Check if in subject appears an unique id"""
        subject = "".join(msg.get_decoded_header("Subject"))
        id = None
        unique_id_re_list = [
            r"[-_\.\s]{7,}([-a-z0-9]{4,})$",
            r"\s{10,}(?:\S\s)?(\S+)$",
            r"\s{3,}[-:\#\(\[]+([-a-z0-9]{4,})[\]\)]+$",
            r"\s{3,}[-:\#]([a-z0-9]{5,})$",
            r"[\s._]{3,}([^0\s._]\d{3,})$",
            r"[\s._]{3,}\[(\S+)\]$",

            # (7217vPhZ0-478TLdy5829qicU9-0@26) and similar
            r"\(([-\w]{7,}\@\d+)\)$",
            r"\b(\d{7,})\s*$",

            # stuff at end of line after "!" or "?" is usually an id
            r"[!\?]\s*(\d{4,}|\w+(-\w+)+)\s*$",

            # 9095IPZK7-095wsvp8715rJgY8-286-28 and similar
            # excluding 'Re:', etc and the first word
            r"(?:\w{2,3}:\s)?\w+\s+(\w{7,}-\w{7,}(-\w+)*)\s*$",

            # #30D7 and similar
            r"\s#\s*([a-f0-9]{4,})\s*$"
        ]
        for rgx in unique_id_re_list:
            match = Regex(rgx, re.I).search(subject)
            if match:
                id = match.group()
                break
        if not id:
            return False
        comercial_re = Regex(r"(?:item|invoice|order|number|confirmation)"
                             r".{1,6}%s\s*$" % id, re.X | re.I)
        if Regex(r"\d{5,}").search(id) and comercial_re.search(subject):
            return False
        return True
示例#23
0
 def parse_config(self, key, value):
     """ Parse a config line, instead of using the regular
     `set_?_option` we need to use set_append_option because
     we need to append the setting to the current existing
     one instead of adding one more.
     """
     # Need to check if the option is a valid regular expression.
     if key in self.options:
         try:
             Regex(value.strip()).compile()
         except re.error:
             return
         self.set_append_option(key, value)
         self.inhibit_further_callbacks()
示例#24
0
    def _check_for_forged_hotmail_received_headers(self, msg):
        self.hotmail_addr_but_no_hotmail_received = 0
        self.hotmail_addr_with_forged_hotmail_received = 0
        rcvd = msg.msg.get("Received")
        if not rcvd:
            return False
        pickup_service_regex = Regex(r"from mail pickup service by hotmail"
                                     r"\.com with Microsoft SMTPSVC;")
        if pickup_service_regex.search(rcvd):
            return False
        if self.check_for_msn_groups_headers(msg):
            return False
        ip_header = msg.msg.get("X-ORIGINATING-IP")
        if ip_header and IP_ADDRESS.search(ip_header):
            FORGED_REGEX = Regex(
                r"from\s+(?:\S*\.)?hotmail.com\s+\(\S+\.hotmail("
                r"?:\.msn)?\.com[\)]|"
                r"from\s+\S*\.hotmail\.com\s+\(\[{IP_ADDRESS}\]|"
                r"from\s+\S+\s+by\s+\S+\.hotmail(?:\.msn)?\.com\s+with\s+ "
                r"HTTP\;|"
                r"from\s+\[66\.218.\S+\]\s+by\s+\S+\.yahoo\.com"
                r"".format(IP_ADDRESS=IP_ADDRESS.pattern), re.I | re.X)
            if FORGED_REGEX.search(rcvd):
                return False
        if self.gated_through_received_hdr_remover(msg):
            return False

        helo_hotmail_regex = Regex(r"(?:from |HELO |helo=)\S*hotmail\.com\b")
        if helo_hotmail_regex.search(rcvd):
            self.hotmail_addr_with_forged_hotmail_received = 1
        else:
            from_address = msg.msg.get("From")
            if not from_address:
                from_address = ""
            if "hotmail.com" not in from_address:
                return False
            self.hotmail_addr_but_no_hotmail_received = 1
示例#25
0
 def check_for_forged_eudoramail_received_headers(self, msg, target=None):
     """Check if the email has forged eudoramail received header"""
     from_addr = ''.join(msg.get_all_addr_header("From"))
     if from_addr.rsplit("@", 1)[-1] != "eudoramail.com":
         return False
     rcvd = ''.join(msg.get_decoded_header("Received"))
     ip = ''.join(msg.get_decoded_header("X-Sender-Ip"))
     if ip and IP_ADDRESS.search(ip):
         ip = True
     else:
         ip = False
     if self.gated_through_received_hdr_remover(msg):
         return False
     if Regex(r"by \S*whowhere.com\;").search(rcvd) and ip:
         return False
     return True
示例#26
0
 def check_for_forged_gw05_received_headers(self, msg, target=None):
     gw05_re = Regex(r"from\s(\S+)\sby\s(\S+)\swith\sESMTP\;\s+\S\S\S,"
                     r"\s+\d+\s+\S\S\S\s+\d{4}\s+\d\d:\d\d:\d\d\s+[-+]*"
                     r"\d{4}", re.X | re.I)
     for rcv in msg.get_decoded_header("Received"):
         h1 = ""
         h2 = ""
         try:
             match = gw05_re.match(rcv)
             if match:
                 h1, h2 = match.groups()
             if h1 and h2 and h2 != ".":
                 return True
         except IndexError:
             continue
     return False
示例#27
0
 def check_freemail_body(self, msg, regex=None, target=None):
     """
     Check if there are free emails in body parts
     of the message
     """
     self.ctxt.log.debug("FreeMail::Plugin check_freemail_body"
                         " %s", 'with regex: ' + regex if regex else '')
     body_emails = self.get_global('body_emails')
     if not len(body_emails):
         self.ctxt.log.debug("FreeMail::Plugin check_freemail_body "
                             "No emails found in body of the message")
         return False
     if regex:
         try:
             check_re = Regex(regex).compile()
         except re.error:
             self.ctxt.log.warn("FreeMail::Plugin check_freemail_from"
                                " regex error")
             return False
     else:
         check_re = None
     if not self._parse_body():
         return False
     if check_re:
         for email in self.get_global("freemail_body_emails"):
             if check_re.search(email):
                 self.ctxt.log.debug(
                     "FreeMail::Plugin check_freemail_body"
                     " HIT! %s is freemail and matches regex", email)
                 result = "Address from body is freemail and matches regex"
                 if self["freemail_add_describe_email"]:
                     _email = "(" + email.replace("@", "[at]") + ")"
                     result = result + "\n\t" + _email
                 return str(result)
     else:
         if len(self.get_global("freemail_body_emails")):
             emails = " ,".join(self.get_global("freemail_body_emails"))
             self.ctxt.log.debug(
                 "FreeMail::Plugin check_freemail_body"
                 " HIT! body has freemails: %s", emails)
             result = "Body has freemails"
             if self["freemail_add_describe_email"]:
                 _emails = "(" + emails.replace("@", "[at]") + ")"
                 result = result + "\n\t" + _emails
             return str(result)
     return False
示例#28
0
    def _update_base64_text_stats(self, msg, content_type,
                                  content_transfer_encoding,
                                  content_disposition, charset):

        text_charset_re = Regex(r"(us-ascii|ansi_x3\.4-1968|iso-ir-6|"
                                r"ansi_x3\.4-1986|iso_646\.irv:1991|"
                                r"ascii|iso646-us|us|ibm367|cp367|"
                                r"csascii)")

        charset_check = not charset or text_charset_re.search(charset)
        cdisposition_check = not (content_disposition
                                  and content_disposition.strip()
                                  in ("inline", "attachment"))

        if ("base64" in content_transfer_encoding and charset_check
                and cdisposition_check):
            self.set_local(msg, "mime_base64_encoded_text", True)
示例#29
0
 def check_in_list(self, msg, addresses, list_name):
     """Check if addresses match the regexes from list_name and modify
     "from_in_whitelist" msg value based on the list name
     """
     param = "from_in_whitelist"
     for address in addresses:
         for regex in self[list_name]:
             if Regex(regex).search(address):
                 self.set_local(msg, param, 1)
                 return True
         wh = self.check_whitelist_rcvd(msg, "parsed_whitelist_from_rcvd",
                                        address)
         if wh == 1:
             self.set_local(msg, param, 1)
             return True
         elif wh == -1:
             self.set_local(msg, param, -1)
     return False
示例#30
0
 def _update_quopri_stats(self, msg, part):
     max_line_len = 79
     qp_count = self.get_local(msg, "mime_qp_count")
     qp_bytes = self.get_local(msg, "qp_bytes")
     qp_chars = self.get_local(msg, "qp_chars")
     quoted_printables = Regex(r"=(?:09|3[0-9ABCEF]|[2456][0-9A-F]|7["
                               r"0-9A-E])").search(part.get_payload())
     qp_bytes += len(part.get_payload())
     self.set_local(msg, "qp_bytes", qp_bytes)
     if quoted_printables:
         qp_chars += len(quoted_printables.groups())
         self.set_local(msg, "qp_chars", qp_chars)
     self.set_local(msg, "mime_qp_count", qp_count + 1)
     raw = msg.translate_line_breaks(part.as_string())
     has_long_line = self.get_local(msg, "mime_qp_long_line")
     if not has_long_line:
         has_long_line = any(
             len("".join(line.split(":")[1:])) > max_line_len
             and not line.startswith("SPAM") for line in raw.splitlines())
         self.set_local(msg, "mime_qp_long_line", has_long_line)