Automate the detection of potentially malicious domains and associated emails targeting your organization

You can use dnstwist to find potentially malicious domains targeting your organization and automatically add them to a list in Sublime Security. We will create a detection rule in Sublime that uses this list to find any sender addresses or email body links related to those domains and flags them for review.

What is dnstwist?

dnstwist is a DNS fuzzer that generates a list of permutations on a given domain to find potentially malicious domains targeting your organization. It performs WHOIS checks to see if these domains are registered and when they were created. Additionally, it checks for A or MX records, which can provide insight into how an attacker might use the domain (e.g., sending emails or hosting malicious content).

Quick dnstwist Demo

Installation

$ python3 -m venv venv
$ source venv/bin/activate
$ pip install "dnstwist[full]"

Checking a Domain

Using axs.com as an example with low permutations, dnstwist will generate a list of permutations on that domain and check if they are registered using the following command:

❯ dnstwist --registered --whois axs.com

Output example:

started 12 scanner threads
permutations: 100.00% of 299 | found: 270 | eta: 0m 00s | speed: 30 qps
WHOIS: oxs.com (100.00%)

*original      axs.com     34.205.213.171 NS:ns-1047.awsdns-02.org MX:axs-com.mail.protection.outlook.com REGISTRAR:Network Solutions, LLC CREATED:1997-02-27
addition       axsj.com    !ServFail !ServFail NS:!ServFail REGISTRAR:Sav.com, LLC CREATED:2000-10-24
addition       axsd.com    103.238.226.248 NS:hkd001.ddddns.net REGISTRAR:DDD TECHNOLOGY PTE. LTD. CREATED:2001-01-27
addition       axst.com    104.247.81.51 NS:ns1.parkingcrew.net MX:mail.h-email.net REGISTRAR:BigRock Solutions Ltd CREATED:2005-03-19

Pro tip: grep on "CREATED:2024" (or current year) to show only newly-registered domains.

Workflow

List of Domains

While you should use your organization's domains, it's also a good idea to check pairings of other enterprise tools with your domain, as these are commonly abused:

domains = [
    "acmecorp.com",
    "acmecorp-microsoft.com",
    "acmecorp-apple.com",
    "acmecorp-google.com",
    "acmecorp-amazon.com",
    "acmecorp-okta.com",
    "acmecorp-aws.com",
    "acmecorp-azure.com",
    "acmecorp-gcp.com",
    "acmecorp-salesforce.com",
    "acmecorp-slack.com",
    "microsoft-acmecorp.com",
    "apple-acmecorp.com",
    "google-acmecorp.com",
    "amazon-acmecorp.com",
    "okta-acmecorp.com",
    "aws-acmecorp.com",
    "azure-acmecorp.com",
    "gcp-acmecorp.com",
    "slack-acmecorp.com"
]

Python API

It's not recommended to use the CLI for automated workflows. Instead, dnstwist has a Python API that can format results as JSON. Here’s a sample script:

import dnstwist
import time

def main(domain):
    start_time = time.time()
    data = dnstwist.run(domain=domain, whois=True, registered=True, threads=20, nameservers='1.1.1.1,8.8.8.8', format='json')
    end_time = time.time()
    execution_time = end_time - start_time
    return {"result": data, "execution_time": execution_time}

Adjust threads as needed

dnstwist returns an array of JSON objects that look something like this:

{
  "fuzzer": "vowel-swap",
  "domain": "ocmecorp.com",
  "dns_ns": ["ns1.asdf.com"],
  "dns_a": ["1.2.3.4"],
  "dns_mx": ["mail.asdf.net"],
  "whois_created": "2005-08-15",
  "whois_registrar": "GoDaddy.com, LLC"
}

Filtering and Adding to Sublime List

For this workflow, we care about newly-registered domains with A or MX records. Here’s some pseudocode logic to decide whether to add the domain to the Sublime list:

IF item has 'dns_mx' or 'dns_a' record
AND item whois_created within 3 months
THEN add to dnstwist_domains list in Sublime

Python Script Example

Here's a full example script that filters domains and sends qualifying ones to the dnstwist_domains list in Sublime:

✍️
Note: You will need to manually set your base URL and list ID. More on that below.
import dnstwist
import time
import datetime
import requests
import os

# Sublime API key
sublime_api_key = os.environ.get('SUBLIME_API_KEY')

# List of domains to process
domains = [
    "acmecorp.com",
    "acmecorp-microsoft.com",
    "acmecorp-apple.com",
    "acmecorp-google.com",
    "acmecorp-amazon.com",
    "acmecorp-okta.com",
    "acmecorp-aws.com",
    "acmecorp-azure.com",
    "acmecorp-gcp.com",
    "acmecorp-salesforce.com",
    "acmecorp-slack.com",
    "microsoft-acmecorp.com",
    "apple-acmecorp.com",
    "google-acmecorp.com",
    "amazon-acmecorp.com",
    "okta-acmecorp.com",
    "aws-acmecorp.com",
    "azure-acmecorp.com",
    "gcp-acmecorp.com",
    "slack-acmecorp.com"
]

# Function to process a single domain
def process_domain(domain):
    start_time = time.time()
    data = dnstwist.run(domain=domain, whois=True, registered=True, threads=20, nameservers='1.1.1.1,8.8.8.8', format='json')
    end_time = time.time()
    execution_time = end_time - start_time
    return {"result": data, "execution_time": execution_time}

# Function to check if a domain meets the criteria
def is_recently_created(whois_created):
    if whois_created:
        creation_date = datetime.datetime.strptime(whois_created, '%Y-%m-%dT%H:%M:%S')
        return (datetime.datetime.now() - creation_date).days <= 90
    return False

# Function to send a domain to Sublime
def add_to_sublime_list(domain):
    url = "https://[your_sublime_base_url]/v0/lists/[list_id]/entries/entry"
    payload = {"string": domain}
    headers = {"Content-Type": "application/json", "authorization": f"Bearer {sublime_api_key}"}
    response = requests.post(url, json=payload, headers=headers)
    return response.status_code

# Function to get current list entries
def get_sublime_entries():
    url = "https://[your_sublime_base_url]/v0/lists/[list_id]/entries"
    headers = {"Content-Type": "application/json", "authorization": f"Bearer {sublime_api_key}"}
    response = requests.get(url, headers=headers)
    return response.json()

# Main logic to process domains and filter based on criteria
entries = get_sublime_entries()

for domain in domains:
    result = process_domain(domain)
    data = result["result"]

    for item in data['domains']:
        if item['domain'] in entries['entries']:
            continue

        if 'dns_mx' in item or 'dns_a' in item:
            if is_recently_created(item.get('whois_created')):
                response_code = add_to_sublime_list(item['domain'])
                print(f"Sent {item['domain']} to Sublime list, response code: {response_code}")

print("Processing completed.")

Creating the List in Sublime

Create a new list in Sublime Security by navigating to Lists > Create New List. Name the list dnstwist_domains and set the list type to string. Retrieve the list ID using the Retrieve Lists endpoint and search for your list name to get the ID.

Create the Detection Rule in Sublime

Create a detection rule in Sublime with the following MQL:

type.inbound

and

// dnstwist list matches

1 of (
  any(body.links, .href_url.domain.root_domain in $dnstwist_domains),
  sender.email.domain.root_domain in $dnstwist_domains
)

// add any exclusions found through backtesting below

This rule searches for email body links or sender addresses that match the domains within the dnstwist_domains list. You could take the Sublime rule even further by checking attachment links against the dnstwist list as well.

It’s highly recommended to backtest any new rule in Sublime and add necessary exclusions to avoid false positives (e.g., you would exclude the sender address/domain of a threat intel service that is sending you the same domains via email).

Summary

This workflow effectively uses dnstwist and Sublime Security together to automate the detection of potentially malicious domains and associated emails targeting your organization.

Ideally, you would run this workflow as a scheduled task on your preferred platform. If you're using Tines, you can run the process_domain function above in the Run Python Script action and parse out the rest of the logic into Tines actions. Keep in mind you might run into execution time limits depending on the amount of permutations generated on a domain.