Skip to content

Instantly share code, notes, and snippets.

@StoneSwine
Last active October 25, 2020 14:50
Show Gist options
  • Save StoneSwine/dfd5fab7fabc916c22f8237048f0ad66 to your computer and use it in GitHub Desktop.
Save StoneSwine/dfd5fab7fabc916c22f8237048f0ad66 to your computer and use it in GitHub Desktop.
Bruteforce resolving subdomains of a domain. I think it ignores wildcard domains, not sure if it works though.
import urllib.request
import argparse
import shutil
import string
import random
from pathlib import Path
from json import JSONDecodeError
import json
import os
import subprocess
import tempfile
import argparse
# ...
parser = argparse.ArgumentParser()
parser.add_argument(
"-d",
"--domain",
required=True,
action="append"
)
args = parser.parse_args()
domains=args.domain
program_path="massdns"
if shutil.which(program_path) is None:
print(f"[ERROR]: '{program_path}' needs to be installed or in path")
exit(1)
subdomain_wordlist = "wl.txt"
url = "https://gist.githubusercontent.com/StoneSwine/e2704c582c66ef350fb2ce965ed1b7ca/raw/afb633277399ddb9cc5009efdb7975ca391e47ed/subdomains_v1.txt"
urllib.request.urlretrieve(url, subdomain_wordlist)
tmp_dom=Path(tempfile.mkstemp()[1])
resolver_list = "rs.txt"
url = "https://raw.githubusercontent.com/TheRook/subbrute/master/resolvers.txt"
urllib.request.urlretrieve(url, resolver_list)
subdomain_list = []
for i in domains:
for word in open(subdomain_wordlist).readlines():
subdomain_list.append(f'{word.strip()}.{i}')
with open(tmp_dom, "w") as f:
f.writelines("\n".join(subdomain_list))
def has_type_a(i):
for j in i:
if j["type"] == "A":
return True
return False
def run_massdns_command(infile, outfile):
command = [
program_path,
'-s', '10000',
'-t', 'A',
'-o', 'J',
'-r', str(resolver_list),
'-w', str(outfile),
'--verify-ip', '-q',
str(infile)
]
subprocess.run(command, stdout=subprocess.DEVNULL)
massdns_out = Path(tempfile.mkstemp()[1])
massdns_in = tmp_dom
wildcard_in = Path(tempfile.mkstemp()[1])
wildcard_out = Path(tempfile.mkstemp()[1])
wildcard_list = []
wildcard = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(60))
wildcard_domains = [f"{wildcard}.{d}" for d in domains]
with open(wildcard_in, "a") as f:
f.writelines("\n".join(wildcard_domains))
run_massdns_command(wildcard_in, wildcard_out)
with open(str(wildcard_out), "r") as f:
for i in f.readlines():
try:
i = json.loads(i.strip())
if has_type_a(i["data"]["answers"]):
for j in i["data"]["answers"]:
if j['type'] == "A": # IPv4 DNS record
ans_rdata = j['data']
if ans_rdata not in wildcard_list:
wildcard_list.append(str(ans_rdata))
except (KeyError, JSONDecodeError):
pass
# Write the rest of the subdomains to the file created by bruteforce subdomains
with open(massdns_in, "a") as f:
f.writelines("\n".join(domains))
run_massdns_command(massdns_in, massdns_out)
with open(str(massdns_out), "r") as f:
for i in f.readlines():
try:
# Make sure a wildcard response is not in the line: This is essential to speed up the parsing process
if not any([True for wip in wildcard_list if wip in i]): # The goal here is for any to return false on empty array
i = json.loads(i.strip())
if has_type_a(i["data"]["answers"]):
for j in i["data"]["answers"]:
ans_type = j['type']
ans_rdat = j['data']
ans_rname = j['name'][:-1] if j['name'][-1] == "." else j['name']
if ans_type == "A" and any([i in ans_rname for i in domains]): # IPv4 DNS record
print(f"{ans_rname}:{ans_rdat}")
except (KeyError, JSONDecodeError):
pass
for f in [subdomain_wordlist, resolver_list]:
if os.path.exists(f):
os.remove(f)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment