#seceng ### Automate the detection of potentially malicious domains and associated emails targeting your organization You can use [dnstwist](https://github.com/elceef/dnstwist?ref=akatz.org) to find potentially malicious domains targeting your organization and automatically add them to a list in [Sublime Security](https://sublime.security/?ref=akatz.org). 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 ```sh $ 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: ```sh ❯ 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 ``` > [!protip] 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: ```python 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: ```python 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: ```json { "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: ```python 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: > [!info] ✍️ Note: You will need to manually set your base URL and list ID. More on that below. ```python 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](https://docs.sublimesecurity.com/reference/getlists-1?ref=akatz.org) 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: ```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](https://www.tines.com/docs/actions/templates/templates/frequently-used-templates/run-python-script?ref=akatz.org) 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.