Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dnsdmarc module, address #1626 #2044

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from

Conversation

colin-stubbs
Copy link
Contributor

@colin-stubbs colin-stubbs commented Nov 29, 2024

Adds dnsdmarc module, refer to #1626 for more info.

Addresses #1626, partial relevance to #1682

I feel this needs some review, particularly for the VULNERABILITY events that are emitted.

e.g.

  1. VULNERABILITY data content, and context field content/format
  2. VULNERABILITY events, e.g. some of my events are edging into misconfiguration situations, where there might be a potential to spoof the domain but only via a small sub-set of some intermediate mail servers and to some destination domains only.

For anyone reviewing, the following domains and sample scan outputs/events are worth considering.

Sample scans/events,

apple.com, RUA+RUF email addresses, no vulnerabilities.

[DNS_NAME]              apple.com       TARGET  (domain, in-scope, target)
[SCAN]                  test (SCAN:2b5a6fcf955753ec8b8e190ecafb97dd8dcc4e5d)    TARGET  (target)
[EMAIL_ADDRESS]         [email protected] dnsdmarc        (distance-1)
[EMAIL_ADDRESS]         [email protected] dnsdmarc        (distance-1)
[RAW_DNS_RECORD]        {"answer": "\"v=DMARC1; p=quarantine; sp=reject; rua=mailto:[email protected]; ruf=mailto:[email protected];\"", "host": "_dmarc.apple.com", "type": "TXT"}        dnsdmarc        (in-scope, subdomain)
[INFO] Finishing scan
[SCAN]                  test (SCAN:2b5a6fcf955753ec8b8e190ecafb97dd8dcc4e5d)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+---------------------------------------+----------------+
[INFO] aggregate: | Module   | Produced                              | Consumed       |
[INFO] aggregate: +==========+=======================================+================+
[INFO] aggregate: | dnsdmarc | 3 (2 EMAIL_ADDRESS, 1 RAW_DNS_RECORD) | 1 (1 DNS_NAME) |
[INFO] aggregate: +----------+---------------------------------------+----------------+

mastodon.social, RUA email only, sub-domains likely vulnerable to spoofing in some way,

[SCAN]                  test (SCAN:bc8d4c5e4cc25d93ab17cc1fcb5b7edc64568f1a)    TARGET  (target)
[DNS_NAME]              mastodon.social TARGET  (domain, in-scope, target)
[EMAIL_ADDRESS]         [email protected]    dnsdmarc        (distance-1)
[VULNERABILITY]         {"description": "DMARC subdomain policy is report-only", "host": "_dmarc.mastodon.social", "severity": "HIGH"}  dnsdmarc        (high, in-scope)
[VULNERABILITY]         {"description": "DMARC subdomain policy is report-only", "host": "_dmarc.mastodon.social", "severity": "HIGH"}  dnsdmarc        (high, in-scope)
[RAW_DNS_RECORD]        {"answer": "\"v=DMARC1; p=quarantine; pct=100; rua=mailto:[email protected]; sp=none; aspf=r;\"", "host": "_dmarc.mastodon.social", "type": "TXT"}  dnsdmarc        (in-scope, subdomain)
[INFO] Finishing scan
[SCAN]                  test (SCAN:bc8d4c5e4cc25d93ab17cc1fcb5b7edc64568f1a)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+-----------------------------------------+----------------+
[INFO] aggregate: | Module   | Produced                                | Consumed       |
[INFO] aggregate: +==========+=========================================+================+
[INFO] aggregate: | dnsdmarc | 3 (1 EMAIL_ADDRESS, 1 RAW_DNS_RECORD, 1 | 1 (1 DNS_NAME) |
[INFO] aggregate: |          | VULNERABILITY)                          |                |
[INFO] aggregate: +----------+-----------------------------------------+----------------+

mastodon.com ( a common mistake when trying to get to mastodon's web presence and what I'd use if I wanted to appear to be sending emails from "Mastodon" ;-) ), no DMARC policy, spoofability limited only by SPF.

[SCAN]                  test (SCAN:9107d239ea8b88b3eceeac7a442953dfbfc2a7bf)    TARGET  (target)
[DNS_NAME]              mastodon.com    TARGET  (domain, in-scope, target)
[VULNERABILITY]         {"description": "DMARC policy absent for this domain", "host": "_dmarc.mastodon.com", "severity": "HIGH"}       dnsdmarc        (high, in-scope)
[VULNERABILITY]         {"description": "DMARC policy absent for this domain", "host": "_dmarc.mastodon.com", "severity": "HIGH"}       dnsdmarc        (high, in-scope)
[INFO] Finishing scan
[SCAN]                  test (SCAN:9107d239ea8b88b3eceeac7a442953dfbfc2a7bf)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+---------------------+----------------+
[INFO] aggregate: | Module   | Produced            | Consumed       |
[INFO] aggregate: +==========+=====================+================+
[INFO] aggregate: | dnsdmarc | 1 (1 VULNERABILITY) | 1 (1 DNS_NAME) |
[INFO] aggregate: +----------+---------------------+----------------+

33across.com - totally default "report-only" policy except there's no RUA or RUF destination provided.

[DNS_NAME]              33across.com    TARGET  (domain, in-scope, target)
[SCAN]                  test (SCAN:bbc1f649de808be68227cea7b7314efaba738fdb)    TARGET  (target)
[RAW_DNS_RECORD]        {"answer": "\"v=DMARC1; p=none;\"", "host": "_dmarc.33across.com", "type": "TXT"}       dnsdmarc        (in-scope, subdomain)
[VULNERABILITY]         {"description": "DMARC policy action is valid but reporting destinations were not provided, DMARC policy is report-only, DMARC subdomain policy is report-only", "host": "_dmarc.33across.com", "severity": "HIGH"}    dnsdmarc        (high, in-scope)
[VULNERABILITY]         {"description": "DMARC policy action is valid but reporting destinations were not provided, DMARC policy is report-only, DMARC subdomain policy is report-only", "host": "_dmarc.33across.com", "severity": "HIGH"}    dnsdmarc        (high, in-scope)
[INFO] Finishing scan
[SCAN]                  test (SCAN:bbc1f649de808be68227cea7b7314efaba738fdb)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+---------------------------------------+----------------+
[INFO] aggregate: | Module   | Produced                              | Consumed       |
[INFO] aggregate: +==========+=======================================+================+
[INFO] aggregate: | dnsdmarc | 2 (1 RAW_DNS_RECORD, 1 VULNERABILITY) | 1 (1 DNS_NAME) |
[INFO] aggregate: +----------+---------------------------------------+----------------+

adriver.ru - wildcard TXT responses are also returned, dnsdmarc module correctly ignores them for anything other than RAW_DNS_RECORD events.

[DNS_NAME]              adriver.ru      TARGET  (domain, in-scope, target)
[SCAN]                  test (SCAN:fd54116763a850a499f2945becbfcd6cb35f83c7)    TARGET  (target)
[RAW_DNS_RECORD]        {"answer": "\"2020040312194959zvnhbfxebxmwxs7t6xe17fbx2sp0qlpruffxhtgzv3aa9soc\"", "host": "_dmarc.adriver.ru", "type": "TXT"}  dnsdmarc       (in-scope, subdomain)
[RAW_DNS_RECORD]        {"answer": "\"v=DMARC1; p=quarantine; adkim=s; aspf=s\"", "host": "_dmarc.adriver.ru", "type": "TXT"}   dnsdmarc        (in-scope, subdomain)
[RAW_DNS_RECORD]        {"answer": "\"google-site-verification=598_Ywu-Dtocax-loOFzuTXN8s8BxQ_vFvy5tFBJMRg\"", "host": "_dmarc.adriver.ru", "type": "TXT"}    dnsdmarc (in-scope, subdomain)
[RAW_DNS_RECORD]        {"answer": "\"MS=08039FDF681B72D2F0795C8D4D144EEA25D43FEE\"", "host": "_dmarc.adriver.ru", "type": "TXT"}       dnsdmarc        (in-scope, subdomain)
[VULNERABILITY]         {"description": "DMARC policy action is valid but reporting destinations were not provided", "host": "_dmarc.adriver.ru", "severity": "HIGH"}  dnsdmarc        (high, in-scope)
[VULNERABILITY]         {"description": "DMARC policy action is valid but reporting destinations were not provided", "host": "_dmarc.adriver.ru", "severity": "HIGH"}  dnsdmarc        (high, in-scope)
[INFO] Finishing scan
[SCAN]                  test (SCAN:fd54116763a850a499f2945becbfcd6cb35f83c7)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+---------------------------------------+----------------+
[INFO] aggregate: | Module   | Produced                              | Consumed       |
[INFO] aggregate: +==========+=======================================+================+
[INFO] aggregate: | dnsdmarc | 5 (4 RAW_DNS_RECORD, 1 VULNERABILITY) | 1 (1 DNS_NAME) |
[INFO] aggregate: +----------+---------------------------------------+----------------+

w55c.net - RFC non-compliant DMARC policy due to v=DMARC; instead of v=DMARC1; and extra " at end of TXT content.

[SCAN]                  test (SCAN:bd37b7cee0c02efa6e4e121053641b3f980cf6b7)    TARGET  (target)
[DNS_NAME]              w55c.net        TARGET  (domain, in-scope, target)
[RAW_DNS_RECORD]        {"answer": "\"v=DMARC; p=reject; rua=mailto:[email protected]; ruf=mailto:[email protected]; sp=reject; aspf=s; fo=0:1:d:s;\\\"\"", "host": "_dmarc.w55c.net", "type": "TXT"}    dnsdmarc        (in-scope, subdomain)
[VULNERABILITY]         {"description": "DMARC policy is not parsable and may not be utilised by third parties, domain may be spoofable to some destinations", "host": "_dmarc.w55c.net", "severity": "HIGH"}  dnsdmarc        (high, in-scope)
[VULNERABILITY]         {"description": "DMARC policy is not parsable and may not be utilised by third parties, domain may be spoofable to some destinations", "host": "_dmarc.w55c.net", "severity": "HIGH"}  dnsdmarc        (high, in-scope)
[INFO] Finishing scan
[SCAN]                  test (SCAN:bd37b7cee0c02efa6e4e121053641b3f980cf6b7)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+---------------------------------------+----------------+
[INFO] aggregate: | Module   | Produced                              | Consumed       |
[INFO] aggregate: +==========+=======================================+================+
[INFO] aggregate: | dnsdmarc | 2 (1 RAW_DNS_RECORD, 1 VULNERABILITY) | 1 (1 DNS_NAME) |
[INFO] aggregate: +----------+---------------------------------------+----------------+

onenote.net - wildcard SPF TXT response only, no DMARC policy.

[DNS_NAME]              onenote.net     TARGET  (domain, in-scope, target)
[SCAN]                  test (SCAN:4ff923028044a55d7b64d54f6c33df48ee3b740c)    TARGET  (target)
[RAW_DNS_RECORD]        {"answer": "\"v=spf1 -all\"", "host": "_dmarc.onenote.net", "type": "TXT"}      dnsdmarc        (in-scope, subdomain)
[VULNERABILITY]         {"description": "DMARC policy absent for this domain", "host": "_dmarc.onenote.net", "severity": "HIGH"}        dnsdmarc        (high, in-scope)
[VULNERABILITY]         {"description": "DMARC policy absent for this domain", "host": "_dmarc.onenote.net", "severity": "HIGH"}        dnsdmarc        (high, in-scope)
[INFO] Finishing scan
[SCAN]                  test (SCAN:4ff923028044a55d7b64d54f6c33df48ee3b740c)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+---------------------------------------+----------------+
[INFO] aggregate: | Module   | Produced                              | Consumed       |
[INFO] aggregate: +==========+=======================================+================+
[INFO] aggregate: | dnsdmarc | 2 (1 RAW_DNS_RECORD, 1 VULNERABILITY) | 1 (1 DNS_NAME) |
[INFO] aggregate: +----------+---------------------------------------+----------------+

themoviedb.org - totally invalid TXT/CNAME configuration...

;; ANSWER SECTION:
_dmarc.themoviedb.org.  264     IN      CNAME   v=dmarc1\;p=none\;rua=mailto:4lt6i9e8\@ag.dmarcian.com.
[SCAN]                  test (SCAN:7960aa40debaf786df1c3f87ec3fa5882636c9d7)    TARGET  (target)
[DNS_NAME]              themoviedb.org  TARGET  (domain, in-scope, target)
[VULNERABILITY]         {"description": "DMARC policy absent for this domain", "host": "_dmarc.themoviedb.org", "severity": "HIGH"}     dnsdmarc        (high, in-scope)
[VULNERABILITY]         {"description": "DMARC policy absent for this domain", "host": "_dmarc.themoviedb.org", "severity": "HIGH"}     dnsdmarc        (high, in-scope)
[INFO] Finishing scan
[SCAN]                  test (SCAN:7960aa40debaf786df1c3f87ec3fa5882636c9d7)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+---------------------+----------------+
[INFO] aggregate: | Module   | Produced            | Consumed       |
[INFO] aggregate: +==========+=====================+================+
[INFO] aggregate: | dnsdmarc | 1 (1 VULNERABILITY) | 1 (1 DNS_NAME) |
[INFO] aggregate: +----------+---------------------+----------------+

webex.com - partial (in fact zero) enforcement,

[DNS_NAME]              webex.com       TARGET  (domain, in-scope, target)
[SCAN]                  test (SCAN:dce64941d25ba5da2d1d8968508484d5b2879576)    TARGET  (target)
[RAW_DNS_RECORD]        {"answer": "\"v=DMARC1; p=quarantine; pct=0; rua=mailto:[email protected]; ruf=mailto:[email protected]\"", "host": "_dmarc.webex.com", "type": "TXT"}   dnsdmarc        (in-scope, subdomain)
[EMAIL_ADDRESS]         [email protected]        dnsdmarc        (distance-1)
[VULNERABILITY]         {"description": "DMARC policy specifies partial enforcement (pct=0)", "host": "_dmarc.webex.com", "severity": "HIGH"}   dnsdmarc      (high, in-scope)
[VULNERABILITY]         {"description": "DMARC policy specifies partial enforcement (pct=0)", "host": "_dmarc.webex.com", "severity": "HIGH"}   dnsdmarc      (high, in-scope)
[INFO] Finishing scan
[SCAN]                  test (SCAN:dce64941d25ba5da2d1d8968508484d5b2879576)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+-----------------------------------------+----------------+
[INFO] aggregate: | Module   | Produced                                | Consumed       |
[INFO] aggregate: +==========+=========================================+================+
[INFO] aggregate: | dnsdmarc | 3 (1 EMAIL_ADDRESS, 1 RAW_DNS_RECORD, 1 | 1 (1 DNS_NAME) |
[INFO] aggregate: |          | VULNERABILITY)                          |                |
[INFO] aggregate: +----------+-----------------------------------------+----------------+

richaudience.com - invalid policy action due to typeo,

[SCAN]                  test (SCAN:e6121fa9f2249a14933f176f04583c3d05c6efaf)    TARGET  (target)
[DNS_NAME]              richaudience.com        TARGET  (domain, in-scope, target)
[EMAIL_ADDRESS]         [email protected]  dnsdmarc        (in-scope)
[RAW_DNS_RECORD]        {"answer": "\"v=DMARC1; p= reject; rua=mailto:[email protected]; adkim=s; aspf=s\"", "host": "_dmarc.richaudience.com", "type": "TXT"}    dnsdmarc        (in-scope, subdomain)
[VULNERABILITY]         {"description": "DMARC policy action invalid or not provided (p=' reject')", "host": "_dmarc.richaudience.com", "severity": "HIGH"}   dnsdmarc (high, in-scope)
[VULNERABILITY]         {"description": "DMARC policy action invalid or not provided (p=' reject')", "host": "_dmarc.richaudience.com", "severity": "HIGH"}   dnsdmarc (high, in-scope)
[INFO] Finishing scan
[SCAN]                  test (SCAN:e6121fa9f2249a14933f176f04583c3d05c6efaf)    TARGET
[SUCC] Scan test completed in 1 second with status FINISHED
[INFO] aggregate: +----------+-----------------------------------------+----------------+
[INFO] aggregate: | Module   | Produced                                | Consumed       |
[INFO] aggregate: +==========+=========================================+================+
[INFO] aggregate: | dnsdmarc | 3 (1 EMAIL_ADDRESS, 1 RAW_DNS_RECORD, 1 | 1 (1 DNS_NAME) |
[INFO] aggregate: |          | VULNERABILITY)                          |                |
[INFO] aggregate: +----------+-----------------------------------------+----------------+

Sample SIEM-friendly JSON event,

{
  "type": "VULNERABILITY",
  "id": "VULNERABILITY:26d5410a4c16fd2e43f62034d3f769f289122ca4",
  "uuid": "VULNERABILITY:7fc95082-3b76-4708-b54a-e59cc9e1e558",
  "scope_description": "in-scope",
  "netloc": "_dmarc.mastodon.com",
  "data": {
    "VULNERABILITY": {
      "host": "_dmarc.mastodon.com",
      "severity": "HIGH",
      "description": "DMARC policy absent for this domain"
    }
  },
  "host": "_dmarc.mastodon.com",
  "resolved_hosts": [],
  "dns_children": {},
  "web_spider_distance": 0,
  "scope_distance": 0,
  "scan": "SCAN:2222aff66432a64b7da77a24870368cfe8a94736",
  "timestamp": "2024-11-29T05:51:24.230972+00:00",
  "parent": "DNS_NAME:a902607a832e41d20f790f7ebb9a3b556099cb70",
  "parent_uuid": "DNS_NAME:e9ec1eeb-2cfb-4542-b169-379c384cdbf6",
  "tags": [
    "in-scope",
    "high"
  ],
  "module": "dnsdmarc",
  "module_sequence": "dnsdmarc",
  "discovery_context": "TXT requests against _dmarc.mastodon.com returned 0 answers, of which 0 were DMARC policies. The target domain can be spoofed.",
  "discovery_path": [
    "Scan test seeded with DNS_NAME: mastodon.com",
    "TXT requests against _dmarc.mastodon.com returned 0 answers, of which 0 were DMARC policies. The target domain can be spoofed."
  ],
  "parent_chain": [
    "DNS_NAME:e9ec1eeb-2cfb-4542-b169-379c384cdbf6",
    "VULNERABILITY:7fc95082-3b76-4708-b54a-e59cc9e1e558"
  ]
}

Another one,

{
  "type": "VULNERABILITY",
  "id": "VULNERABILITY:957d634f9584dfdf82b39605a291cbdc23cdb99b",
  "uuid": "VULNERABILITY:cb53cf92-4bf9-4258-96fc-8720d5697044",
  "scope_description": "in-scope",
  "netloc": "_dmarc.33across.com",
  "data": {
    "VULNERABILITY": {
      "host": "_dmarc.33across.com",
      "severity": "HIGH",
      "description": "DMARC policy action is valid but reporting destinations were not provided, DMARC policy is report-only, DMARC subdomain policy is report-only"
    }
  },
  "host": "_dmarc.33across.com",
  "resolved_hosts": [],
  "dns_children": {},
  "web_spider_distance": 0,
  "scope_distance": 0,
  "scan": "SCAN:bbc1f649de808be68227cea7b7314efaba738fdb",
  "timestamp": "2024-11-29T05:57:37.358823+00:00",
  "parent": "DNS_NAME:b5f6b4570a07977c5af962b9eff15eafdc5c4b6a",
  "parent_uuid": "DNS_NAME:ce2ba30d-4571-41d3-a85a-1f57d885da82",
  "tags": [
    "high",
    "in-scope"
  ],
  "module": "dnsdmarc",
  "module_sequence": "dnsdmarc",
  "discovery_context": "DMARC policy inspection against _dmarc.33across.com identified one or more vulnerabilities in answer 1 'v=DMARC1; p=none;'. Potential for domain spoofing exists.",
  "discovery_path": [
    "Scan test seeded with DNS_NAME: 33across.com",
    "DMARC policy inspection against _dmarc.33across.com identified one or more vulnerabilities in answer 1 'v=DMARC1; p=none;'. Potential for domain spoofing exists."
  ],
  "parent_chain": [
    "DNS_NAME:ce2ba30d-4571-41d3-a85a-1f57d885da82",
    "VULNERABILITY:cb53cf92-4bf9-4258-96fc-8720d5697044"
  ]
}

@TheTechromancer
Copy link
Collaborator

TheTechromancer commented Dec 9, 2024

@colin-stubbs nice work on this module. Also thanks for commenting and providing all those examples.

I think it's safe to say you went deeper on DMARC than we typically do at BLS (our approach is to yeet a spoofed email and see if it lands 😂).

A couple things:

  • The module is deduping events based on their parent domain, but acting on the original host. To keep things predictable, we should probably take the parent first thing in handle_event()
  • In BBOT we have a strict separation between FINDING and VULNERABILITY, which is that FINDING is anything interesting or probably vulnerable, while VULNERABILITY is reserved for things that are guaranteed-exploitable. Therefore I'd err on the side of making things a FINDING unless they would make spoofing a certainty. For example, I think that even if DMARC is misconfigured or nonexistent, SPF alone might prevent the spoofing of emails. Email is insanely complex and there are so many factors so it's hard to be sure about a specific domain, without testing it end-to-end.

Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants