Merge pull request #5 from crahan/setup

Support installing via setup.py
This commit is contained in:
RoninNakomoto 2022-02-27 04:53:27 +02:00 committed by GitHub
commit 2f2afbf79c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 197 additions and 115 deletions

View File

@ -13,7 +13,7 @@ ENV PATH=${PATH}:/Sublist3r2
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y build-essential libffi-dev libgit2-dev && \ apt-get install -y build-essential libffi-dev libgit2-dev && \
pip install -r /Sublist3r2/requirements.txt && \ pip install /Sublist3r2 && \
addgroup Sublist3r2 --force-badname && \ addgroup Sublist3r2 --force-badname && \
useradd -g Sublist3r2 -d /Sublist3r2 -s /bin/sh Sublist3r2 && \ useradd -g Sublist3r2 -d /Sublist3r2 -s /bin/sh Sublist3r2 && \
chown -R Sublist3r2:Sublist3r2 /Sublist3r2 && \ chown -R Sublist3r2:Sublist3r2 /Sublist3r2 && \
@ -24,6 +24,6 @@ RUN apt-get update && \
USER Sublist3r2 USER Sublist3r2
ENTRYPOINT ["sublist3r2.py"] ENTRYPOINT ["sublist3r2"]
CMD ["-h"] CMD ["-h"]

View File

@ -1,2 +1,2 @@
include LICENSE README.md include LICENSE README.md
include aiodnsbrute/*.txt include sublist3r2/aiodnsbrute/*.txt

View File

@ -1,4 +1,8 @@
argparse argparse
dnspython dnspython
requests requests
aiodnsbrute asyncio
uvloop
tqdm
aiodns
click

50
setup.py Normal file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env python
import os
from setuptools import setup, find_packages
def read(fname: str) -> str:
"""Open files relative to package."""
return open(os.path.join(os.path.dirname(__file__), fname)).read()
setup(
name='sublist3r2',
version='1.0.1',
python_requires='>=3.6',
description='Subdomains enumeration tool for penetration testers',
long_description=read('README.md'),
long_description_content_type='text/markdown',
keywords='subdomain dns detection',
url='https://github.com/RoninNakomoto/Sublist3r2',
license='GPL-2.0',
packages=find_packages(),
include_package_data=True,
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Intended Audience :: Information Technology',
'Intended Audience :: System Administrators',
'Intended Audience :: Telecommunications Industry',
'License :: OSI Approved :: GNU General Public License v2',
'Operating System :: POSIX :: Linux',
'Operating System :: MacOS',
'Programming Language :: Python :: 3',
'Topic :: Security',
],
install_requires=[
'argparse',
'dnspython',
'requests',
'asyncio',
'uvloop',
'tqdm',
'aiodns',
'click',
],
entry_points={
'console_scripts': [
'sublist3r2 = sublist3r2:interactive',
],
},
)

View File

@ -2,41 +2,28 @@
# coding: utf-8 # coding: utf-8
# Sublist3r2 v1.0 # Sublist3r2 v1.0
# Builtin modules
# modules in standard library
import re
import sys
import os
import argparse import argparse
import time
import hashlib import hashlib
import random
import multiprocessing
import threading
import socket
import json import json
import multiprocessing
import os
import random
import re
import socket
import sys
import threading
import time
import urllib.parse as urlparse
from collections import Counter from collections import Counter
# external modules # External modules
import dns.resolver import dns.resolver
import requests import requests
from aiodnsbrute.cli import aioDNSBrute from sublist3r2.aiodnsbrute.cli import aioDNSBrute
# Python 2.x and 3.x compatiablity # Version info
if sys.version > '3': __version__ = '1.0.1'
import urllib.parse as urlparse
import urllib.parse as urllib
else:
import urlparse
import urllib
# In case you cannot install some of the required development packages
# there's also an option to disable the SSL warning:
try:
import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()
except:
pass
# Check if we are running this on windows platform # Check if we are running this on windows platform
is_windows = sys.platform.startswith('win') is_windows = sys.platform.startswith('win')
@ -50,15 +37,14 @@ if is_windows:
R = '\033[91m' # red R = '\033[91m' # red
W = '\033[0m' # white W = '\033[0m' # white
try: try:
import win_unicode_console , colorama import colorama
import win_unicode_console
win_unicode_console.enable() win_unicode_console.enable()
colorama.init() colorama.init()
#Now the unicode will work ^_^ # Now the unicode will work ^_^
except: except Exception:
print("[!] Error: Coloring libraries not installed, no coloring will be used [Check the readme]") print("[!] Error: Coloring libraries not installed, no coloring will be used [Check the readme]")
G = Y = B = R = W = G = Y = B = R = W = '' G = Y = B = R = W = ''
else: else:
G = '\033[92m' # green G = '\033[92m' # green
Y = '\033[93m' # yellow Y = '\033[93m' # yellow
@ -66,6 +52,7 @@ else:
R = '\033[91m' # red R = '\033[91m' # red
W = '\033[0m' # white W = '\033[0m' # white
def no_color(): def no_color():
global G, Y, B, R, W global G, Y, B, R, W
G = Y = B = R = W = '' G = Y = B = R = W = ''
@ -73,13 +60,13 @@ def no_color():
def banner(): def banner():
print("""%s print("""%s
____ _ _ _ _ _____ _ ____ ____ _ _ _ _ _____ ______
/ ___| _ _| |__ | (_)___| |_|___ / _ __\ __ | Sublist3r2 v1.0 / ___| _ _| |__ | (_)___| |_|___ / _ __\ __ | Sublist3r2 v%s
\___ \| | | | '_ \| | / __| __| |_ \| '__| / / a subdomains enum tool originally by @aboul3la \___ \| | | | '_ \| | / __| __| |_ \| '__| / / a subdomains enum tool originally by @aboul3la
___) | |_| | |_) | | \__ \ |_ ___) | | / /_ maintained by Ronin Nakomoto ___) | |_| | |_) | | \__ \ |_ ___) | | / /_ maintained by Ronin Nakomoto
|____/ \__,_|_.__/|_|_|___/\__|____/|_| /____|%s%s https://github.com/RoninNakomoto/Sublist3r2 |____/ \__,_|_.__/|_|_|___/\__|____/|_| /____|%s https://github.com/RoninNakomoto/Sublist3r2
""" % (R, W, Y)) """ % (R, __version__, Y)) # noqa
def parser_error(errmsg): def parser_error(errmsg):
@ -258,7 +245,10 @@ class enumratorBase(object):
class enumratorBaseThreaded(multiprocessing.Process, enumratorBase): class enumratorBaseThreaded(multiprocessing.Process, enumratorBase):
def __init__(self, base_url, engine_name, domain, subdomains=None, q=None, silent=False, verbose=True): def __init__(self, base_url, engine_name, domain, subdomains=None, q=None, silent=False, verbose=True):
subdomains = subdomains or [] subdomains = subdomains or []
enumratorBase.__init__(self, base_url, engine_name, domain, subdomains, silent=silent, verbose=verbose) enumratorBase.__init__(
self, base_url, engine_name, domain, subdomains,
silent=silent, verbose=verbose
)
multiprocessing.Process.__init__(self) multiprocessing.Process.__init__(self)
self.q = q self.q = q
return return
@ -276,13 +266,16 @@ class GoogleEnum(enumratorBaseThreaded):
self.engine_name = "Google" self.engine_name = "Google"
self.MAX_DOMAINS = 11 self.MAX_DOMAINS = 11
self.MAX_PAGES = 200 self.MAX_PAGES = 200
super(GoogleEnum, self).__init__(base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) super(GoogleEnum, self).__init__(
base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
self.q = q self.q = q
return return
def extract_domains(self, resp): def extract_domains(self, resp):
links_list = list() links_list = list()
link_regx = re.compile('<cite.*?>(.*?)<\/cite>') link_regx = re.compile(r'<cite.*?>(.*?)<\/cite>')
try: try:
links_list = link_regx.findall(resp) links_list = link_regx.findall(resp)
for link in links_list: for link in links_list:
@ -299,7 +292,7 @@ class GoogleEnum(enumratorBaseThreaded):
return links_list return links_list
def check_response_errors(self, resp): def check_response_errors(self, resp):
if (type(resp) is str or type(resp) is unicode) and 'Our systems have detected unusual traffic' in resp: if (type(resp) is str) and 'Our systems have detected unusual traffic' in resp:
self.print_(R + "[!] Error: Google probably now is blocking our requests" + W) self.print_(R + "[!] Error: Google probably now is blocking our requests" + W)
self.print_(R + "[~] Finished now the Google Enumeration ..." + W) self.print_(R + "[~] Finished now the Google Enumeration ..." + W)
return False return False
@ -326,20 +319,23 @@ class YahooEnum(enumratorBaseThreaded):
self.engine_name = "Yahoo" self.engine_name = "Yahoo"
self.MAX_DOMAINS = 10 self.MAX_DOMAINS = 10
self.MAX_PAGES = 0 self.MAX_PAGES = 0
super(YahooEnum, self).__init__(base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) super(YahooEnum, self).__init__(
base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
self.q = q self.q = q
return return
def extract_domains(self, resp): def extract_domains(self, resp):
link_regx2 = re.compile('<span class=" fz-.*? fw-m fc-12th wr-bw.*?">(.*?)</span>') link_regx2 = re.compile(r'<span class=" fz-.*? fw-m fc-12th wr-bw.*?">(.*?)</span>')
link_regx = re.compile('<span class="txt"><span class=" cite fw-xl fz-15px">(.*?)</span>') link_regx = re.compile(r'<span class="txt"><span class=" cite fw-xl fz-15px">(.*?)</span>')
links_list = [] links_list = []
try: try:
links = link_regx.findall(resp) links = link_regx.findall(resp)
links2 = link_regx2.findall(resp) links2 = link_regx2.findall(resp)
links_list = links + links2 links_list = links + links2
for link in links_list: for link in links_list:
link = re.sub("<(\/)?b>", "", link) link = re.sub(r'<(\/)?b>', '', link)
if not link.startswith('http'): if not link.startswith('http'):
link = "http://" + link link = "http://" + link
subdomain = urlparse.urlparse(link).netloc subdomain = urlparse.urlparse(link).netloc
@ -377,13 +373,16 @@ class AskEnum(enumratorBaseThreaded):
self.engine_name = "Ask" self.engine_name = "Ask"
self.MAX_DOMAINS = 11 self.MAX_DOMAINS = 11
self.MAX_PAGES = 0 self.MAX_PAGES = 0
enumratorBaseThreaded.__init__(self, base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) enumratorBaseThreaded.__init__(
self, base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
self.q = q self.q = q
return return
def extract_domains(self, resp): def extract_domains(self, resp):
links_list = list() links_list = list()
link_regx = re.compile('<p class="web-result-url">(.*?)</p>') link_regx = re.compile(r'<p class="web-result-url">(.*?)</p>')
try: try:
links_list = link_regx.findall(resp) links_list = link_regx.findall(resp)
for link in links_list: for link in links_list:
@ -420,22 +419,25 @@ class BingEnum(enumratorBaseThreaded):
self.engine_name = "Bing" self.engine_name = "Bing"
self.MAX_DOMAINS = 30 self.MAX_DOMAINS = 30
self.MAX_PAGES = 0 self.MAX_PAGES = 0
enumratorBaseThreaded.__init__(self, base_url, self.engine_name, domain, subdomains, q=q, silent=silent) enumratorBaseThreaded.__init__(
self, base_url, self.engine_name, domain, subdomains,
q=q, silent=silent
)
self.q = q self.q = q
self.verbose = verbose self.verbose = verbose
return return
def extract_domains(self, resp): def extract_domains(self, resp):
links_list = list() links_list = list()
link_regx = re.compile('<li class="b_algo"><h2><a href="(.*?)"') link_regx = re.compile(r'<li class="b_algo"><h2><a href="(.*?)"')
link_regx2 = re.compile('<div class="b_title"><h2><a href="(.*?)"') link_regx2 = re.compile(r'<div class="b_title"><h2><a href="(.*?)"')
try: try:
links = link_regx.findall(resp) links = link_regx.findall(resp)
links2 = link_regx2.findall(resp) links2 = link_regx2.findall(resp)
links_list = links + links2 links_list = links + links2
for link in links_list: for link in links_list:
link = re.sub('<(\/)?strong>|<span.*?>|<|>', '', link) link = re.sub(r'<(\/)?strong>|<span.*?>|<|>', '', link)
if not link.startswith('http'): if not link.startswith('http'):
link = "http://" + link link = "http://" + link
subdomain = urlparse.urlparse(link).netloc subdomain = urlparse.urlparse(link).netloc
@ -465,7 +467,10 @@ class BaiduEnum(enumratorBaseThreaded):
self.engine_name = "Baidu" self.engine_name = "Baidu"
self.MAX_DOMAINS = 2 self.MAX_DOMAINS = 2
self.MAX_PAGES = 760 self.MAX_PAGES = 760
enumratorBaseThreaded.__init__(self, base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) enumratorBaseThreaded.__init__(
self, base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
self.querydomain = self.domain self.querydomain = self.domain
self.q = q self.q = q
return return
@ -474,11 +479,11 @@ class BaiduEnum(enumratorBaseThreaded):
links = list() links = list()
found_newdomain = False found_newdomain = False
subdomain_list = [] subdomain_list = []
link_regx = re.compile('<a.*?class="c-showurl".*?>(.*?)</a>') link_regx = re.compile(r'<a.*?class="c-showurl".*?>(.*?)</a>')
try: try:
links = link_regx.findall(resp) links = link_regx.findall(resp)
for link in links: for link in links:
link = re.sub('<.*?>|>|<|&nbsp;', '', link) link = re.sub(r'<.*?>|>|<|&nbsp;', '', link)
if not link.startswith('http'): if not link.startswith('http'):
link = "http://" + link link = "http://" + link
subdomain = urlparse.urlparse(link).netloc subdomain = urlparse.urlparse(link).netloc
@ -523,7 +528,10 @@ class NetcraftEnum(enumratorBaseThreaded):
subdomains = subdomains or [] subdomains = subdomains or []
self.base_url = 'https://searchdns.netcraft.com/?restriction=site+ends+with&host={domain}' self.base_url = 'https://searchdns.netcraft.com/?restriction=site+ends+with&host={domain}'
self.engine_name = "Netcraft" self.engine_name = "Netcraft"
super(NetcraftEnum, self).__init__(self.base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) super(NetcraftEnum, self).__init__(
self.base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
self.q = q self.q = q
return return
@ -541,7 +549,7 @@ class NetcraftEnum(enumratorBaseThreaded):
return return
def get_next(self, resp): def get_next(self, resp):
link_regx = re.compile('<a.*?href="(.*?)">Next Page') link_regx = re.compile(r'<a.*?href="(.*?)">Next Page')
link = link_regx.findall(resp) link = link_regx.findall(resp)
url = 'http://searchdns.netcraft.com' + link[0] url = 'http://searchdns.netcraft.com' + link[0]
return url return url
@ -551,7 +559,9 @@ class NetcraftEnum(enumratorBaseThreaded):
cookies_list = cookie[0:cookie.find(';')].split("=") cookies_list = cookie[0:cookie.find(';')].split("=")
cookies[cookies_list[0]] = cookies_list[1] cookies[cookies_list[0]] = cookies_list[1]
# hashlib.sha1 requires utf-8 encoded str # hashlib.sha1 requires utf-8 encoded str
cookies['netcraft_js_verification_response'] = hashlib.sha1(urllib.unquote(cookies_list[1]).encode('utf-8')).hexdigest() cookies['netcraft_js_verification_response'] = hashlib.sha1(
urlparse.unquote(cookies_list[1]).encode('utf-8')
).hexdigest()
return cookies return cookies
def get_cookies(self, headers): def get_cookies(self, headers):
@ -577,7 +587,7 @@ class NetcraftEnum(enumratorBaseThreaded):
def extract_domains(self, resp): def extract_domains(self, resp):
links_list = list() links_list = list()
link_regx = re.compile('<a class="results-table__host" href="(.*?)"') link_regx = re.compile(r'<a class="results-table__host" href="(.*?)"')
try: try:
links_list = link_regx.findall(resp) links_list = link_regx.findall(resp)
for link in links_list: for link in links_list:
@ -601,7 +611,10 @@ class DNSdumpster(enumratorBaseThreaded):
self.engine_name = "DNSdumpster" self.engine_name = "DNSdumpster"
self.q = q self.q = q
self.lock = None self.lock = None
super(DNSdumpster, self).__init__(base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) super(DNSdumpster, self).__init__(
base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
return return
def check_host(self, host): def check_host(self, host):
@ -616,7 +629,7 @@ class DNSdumpster(enumratorBaseThreaded):
self.print_("%s%s: %s%s" % (R, self.engine_name, W, host)) self.print_("%s%s: %s%s" % (R, self.engine_name, W, host))
is_valid = True is_valid = True
self.live_subdomains.append(host) self.live_subdomains.append(host)
except: except Exception:
pass pass
self.lock.release() self.lock.release()
return is_valid return is_valid
@ -636,7 +649,7 @@ class DNSdumpster(enumratorBaseThreaded):
return self.get_response(resp) return self.get_response(resp)
def get_csrftoken(self, resp): def get_csrftoken(self, resp):
csrf_regex = re.compile('<input type="hidden" name="csrfmiddlewaretoken" value="(.*?)">', re.S) csrf_regex = re.compile(r'<input type="hidden" name="csrfmiddlewaretoken" value="(.*?)">', re.S)
token = csrf_regex.findall(resp)[0] token = csrf_regex.findall(resp)[0]
return token.strip() return token.strip()
@ -654,8 +667,8 @@ class DNSdumpster(enumratorBaseThreaded):
return self.live_subdomains return self.live_subdomains
def extract_domains(self, resp): def extract_domains(self, resp):
tbl_regex = re.compile('<a name="hostanchor"><\/a>Host Records.*?<table.*?>(.*?)</table>', re.S) tbl_regex = re.compile(r'<a name="hostanchor"><\/a>Host Records.*?<table.*?>(.*?)</table>', re.S)
link_regex = re.compile('<td class="col-md-4">(.*?)<br>', re.S) link_regex = re.compile(r'<td class="col-md-4">(.*?)<br>', re.S)
links = [] links = []
try: try:
results_tbl = tbl_regex.findall(resp)[0] results_tbl = tbl_regex.findall(resp)[0]
@ -677,24 +690,25 @@ class Virustotal(enumratorBaseThreaded):
subdomains = subdomains or [] subdomains = subdomains or []
base_url = 'https://www.virustotal.com/api/v3/domains/{domain}/subdomains' base_url = 'https://www.virustotal.com/api/v3/domains/{domain}/subdomains'
self.engine_name = "Virustotal" self.engine_name = "Virustotal"
if os.getenv("VT_APIKEY") is None: self.apikey = os.getenv("VT_APIKEY")
VT_APIKEY=input(B + "[+] Enter VirusTotal API key, press Enter for none: " + W)
VT_APIKEY=VT_APIKEY.strip() if self.apikey is None:
if VT_APIKEY != "": vt_apikey = input(B + "[+] Enter VirusTotal API key, press Enter for none: " + W).strip()
os.environ["VT_APIKEY"]=(VT_APIKEY) if vt_apikey != "":
else: self.apikey = vt_apikey
VT_APIKEY = os.getenv("VT_APIKEY")
os.environ["VT_APIKEY"]=(VT_APIKEY)
self.apikey = os.getenv('VT_APIKEY', None)
self.q = q self.q = q
super(Virustotal, self).__init__(base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) super(Virustotal, self).__init__(
base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
self.url = self.base_url.format(domain=self.domain) self.url = self.base_url.format(domain=self.domain)
return return
# the main send_req need to be rewritten # the main send_req need to be rewritten
def send_req(self, url): def send_req(self, url):
try: try:
self.headers.update({'X-ApiKey':self.apikey}) self.headers.update({'X-ApiKey': self.apikey})
resp = self.session.get(url, headers=self.headers, timeout=self.timeout) resp = self.session.get(url, headers=self.headers, timeout=self.timeout)
except Exception as e: except Exception as e:
self.print_(e) self.print_(e)
@ -705,11 +719,10 @@ class Virustotal(enumratorBaseThreaded):
def enumerate(self): def enumerate(self):
if self.apikey: if self.apikey:
while self.url != '': while self.url != '':
#try:
resp = self.send_req(self.url) resp = self.send_req(self.url)
resp = json.loads(resp) resp = json.loads(resp)
if 'error' in resp: if 'error' in resp:
self.print_(R + "Error Code: {}".format(resp['error']["code"]) +W) self.print_(R + "Error Code: {}".format(resp['error']["code"]) + W)
self.print_(R + "Virus Total Server Message: {}".format(resp['error']["message"]) + W) self.print_(R + "Virus Total Server Message: {}".format(resp['error']["message"]) + W)
break break
if 'links' in resp and 'next' in resp['links']: if 'links' in resp and 'next' in resp['links']:
@ -719,8 +732,8 @@ class Virustotal(enumratorBaseThreaded):
self.extract_domains(resp) self.extract_domains(resp)
else: else:
self.print_(R + "[!] Error: VirusTotal API key environment variable not found. Skipping" + W) self.print_(R + "[!] Error: VirusTotal API key environment variable not found. Skipping" + W)
self.print_(R + "[!] set VT_APIKEY to your virus total API key using: export VT_APIKEY=Your_VT_API_KEY_VALUE" + W) self.print_(R + "[!] set VT_APIKEY to your virus total API key using: `export VT_APIKEY=Your_VT_API_KEY_VALUE`" + W)
self.print_(B + "[!] To get a VT APIKEY, register at https://www.virustotal.com/gui/join-us" +W) self.print_(B + "[!] To get a VT APIKEY, register at https://www.virustotal.com/gui/join-us" + W)
return self.subdomains return self.subdomains
def extract_domains(self, resp): def extract_domains(self, resp):
@ -745,7 +758,10 @@ class ThreatCrowd(enumratorBaseThreaded):
base_url = 'https://www.threatcrowd.org/searchApi/v2/domain/report/?domain={domain}' base_url = 'https://www.threatcrowd.org/searchApi/v2/domain/report/?domain={domain}'
self.engine_name = "ThreatCrowd" self.engine_name = "ThreatCrowd"
self.q = q self.q = q
super(ThreatCrowd, self).__init__(base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) super(ThreatCrowd, self).__init__(
base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
return return
def req(self, url): def req(self, url):
@ -783,7 +799,10 @@ class CrtSearch(enumratorBaseThreaded):
base_url = 'https://crt.sh/?q=%25.{domain}' base_url = 'https://crt.sh/?q=%25.{domain}'
self.engine_name = "SSL Certificates" self.engine_name = "SSL Certificates"
self.q = q self.q = q
super(CrtSearch, self).__init__(base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) super(CrtSearch, self).__init__(
base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
return return
def req(self, url): def req(self, url):
@ -802,7 +821,7 @@ class CrtSearch(enumratorBaseThreaded):
return self.subdomains return self.subdomains
def extract_domains(self, resp): def extract_domains(self, resp):
link_regx = re.compile('<TD>(.*?)</TD>') link_regx = re.compile(r'<TD>(.*?)</TD>')
try: try:
links = link_regx.findall(resp) links = link_regx.findall(resp)
for link in links: for link in links:
@ -818,7 +837,7 @@ class CrtSearch(enumratorBaseThreaded):
continue continue
if '@' in subdomain: if '@' in subdomain:
subdomain = subdomain[subdomain.find('@')+1:] subdomain = subdomain[subdomain.find('@') + 1:]
if subdomain not in self.subdomains and subdomain != self.domain: if subdomain not in self.subdomains and subdomain != self.domain:
if self.verbose: if self.verbose:
@ -828,13 +847,17 @@ class CrtSearch(enumratorBaseThreaded):
print(e) print(e)
pass pass
class PassiveDNS(enumratorBaseThreaded): class PassiveDNS(enumratorBaseThreaded):
def __init__(self, domain, subdomains=None, q=None, silent=False, verbose=True): def __init__(self, domain, subdomains=None, q=None, silent=False, verbose=True):
subdomains = subdomains or [] subdomains = subdomains or []
base_url = 'https://api.sublist3r.com/search.php?domain={domain}' base_url = 'https://api.sublist3r.com/search.php?domain={domain}'
self.engine_name = "PassiveDNS" self.engine_name = "PassiveDNS"
self.q = q self.q = q
super(PassiveDNS, self).__init__(base_url, self.engine_name, domain, subdomains, q=q, silent=silent, verbose=verbose) super(PassiveDNS, self).__init__(
base_url, self.engine_name, domain, subdomains,
q=q, silent=silent, verbose=verbose
)
return return
def req(self, url): def req(self, url):
@ -910,7 +933,7 @@ def main(domain, threads, savefile, ports, silent, verbose, enable_bruteforce, e
enable_bruteforce = True enable_bruteforce = True
# Validate domain # Validate domain
domain_check = re.compile("^(http|https)?[a-zA-Z0-9]+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,}$") domain_check = re.compile(r'^(http|https)?[a-zA-Z0-9]+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,}$')
if not domain_check.match(domain): if not domain_check.match(domain):
if not silent: if not silent:
print(R + "Error: Please enter a valid domain" + W) print(R + "Error: Please enter a valid domain" + W)
@ -927,18 +950,19 @@ def main(domain, threads, savefile, ports, silent, verbose, enable_bruteforce, e
if verbose and not silent: if verbose and not silent:
print(Y + "[-] verbosity is enabled, will show the subdomains results in realtime" + W) print(Y + "[-] verbosity is enabled, will show the subdomains results in realtime" + W)
supported_engines = {'baidu': BaiduEnum, supported_engines = {
'yahoo': YahooEnum, 'baidu': BaiduEnum,
'google': GoogleEnum, 'yahoo': YahooEnum,
'bing': BingEnum, 'google': GoogleEnum,
'ask': AskEnum, 'bing': BingEnum,
'netcraft': NetcraftEnum, 'ask': AskEnum,
'dnsdumpster': DNSdumpster, 'netcraft': NetcraftEnum,
'virustotal': Virustotal, 'dnsdumpster': DNSdumpster,
'threatcrowd': ThreatCrowd, 'virustotal': Virustotal,
'ssl': CrtSearch, 'threatcrowd': ThreatCrowd,
'passivedns': PassiveDNS 'ssl': CrtSearch,
} 'passivedns': PassiveDNS
}
chosenEnums = [] chosenEnums = []
@ -968,15 +992,16 @@ def main(domain, threads, savefile, ports, silent, verbose, enable_bruteforce, e
if enable_bruteforce: if enable_bruteforce:
if not silent: if not silent:
print(G + "[-] Starting bruteforce module now using aiodnsbrute.." + W) print(G + "[-] Starting bruteforce module now using aiodnsbrute.." + W)
record_type = False
path_to_file = os.path.dirname(os.path.realpath(__file__)) path_to_file = os.path.dirname(os.path.realpath(__file__))
subs = os.path.join(path_to_file, 'aiodnsbrute', 'subdomains-top1million-110000.txt') subs = os.path.join(path_to_file, 'aiodnsbrute', 'subdomains-top1million-110000.txt')
resolvers = os.path.join(path_to_file, 'aiodnsbrute', 'resolvers.txt') resolvers = os.path.join(path_to_file, 'aiodnsbrute', 'resolvers.txt')
wildcard=True wildcard = True
verify=True verify = True
query=True query = True
thread_count = threads thread_count = threads
bruteforce_list = aioDNSBrute.bruteforce_domain(parsed_domain.netloc, resolvers, subs, wildcard, verify, search_list, thread_count, query) bruteforce_list = aioDNSBrute.bruteforce_domain(
parsed_domain.netloc, resolvers, subs, wildcard, verify, thread_count, query
)
subdomains = search_list.union(bruteforce_list) subdomains = search_list.union(bruteforce_list)
if subdomains: if subdomains:
@ -1015,7 +1040,11 @@ def interactive():
if args.no_color: if args.no_color:
no_color() no_color()
banner() banner()
res = main(domain, threads, savefile, ports, silent=False, verbose=verbose, enable_bruteforce=enable_bruteforce, engines=engines) main(
domain, threads, savefile, ports,
silent=False, verbose=verbose, enable_bruteforce=enable_bruteforce, engines=engines
)
if __name__ == "__main__": if __name__ == "__main__":
interactive() interactive()

View File

@ -9,7 +9,7 @@ import click
import socket import socket
import sys import sys
from tqdm import tqdm from tqdm import tqdm
from aiodnsbrute.logger import ConsoleLogger from sublist3r2.aiodnsbrute.logger import ConsoleLogger
class aioDNSBrute(object): class aioDNSBrute(object):
@ -74,7 +74,7 @@ class aioDNSBrute(object):
if err_number == 4: if err_number == 4:
# This is domain name not found, ignore it # This is domain name not found, ignore it
pass pass
# elif err_number == 12: #elif err_number == 12:
# Timeout from DNS server # Timeout from DNS server
#self.logger.warn(f"Timeout for {name}") #self.logger.warn(f"Timeout for {name}")
elif err_number == 1: elif err_number == 1:
@ -118,7 +118,6 @@ class aioDNSBrute(object):
self.tasks.remove(future) self.tasks.remove(future)
if self.verbosity >= 1: if self.verbosity >= 1:
self.pbar.update() self.pbar.update()
async def _queue_lookups(self, wordlist, domain): async def _queue_lookups(self, wordlist, domain):
"""Takes a list of words and adds them to the async loop also passing the original """Takes a list of words and adds them to the async loop also passing the original
@ -137,19 +136,19 @@ class aioDNSBrute(object):
self.tasks.append(task) self.tasks.append(task)
await asyncio.gather(*self.tasks, return_exceptions=True) await asyncio.gather(*self.tasks, return_exceptions=True)
def bruteforce_domain(target, resolvers=None, wordlist="subdomains-top1million-110000.txt", wildcard=True, verify=True, found_subdomains=[], thread_count=7000, query=True): def bruteforce_domain(target, resolvers=None, wordlist="subdomains-top1million-110000.txt", wildcard=True, verify=True, thread_count=7000, query=True):
subdomains_list = [] subdomains_list = []
names_list = [] names_list = []
verbosity=1 verbosity = 1
if resolvers: if resolvers:
resolverfile = open(resolvers,'r') resolverfile = open(resolvers, 'r')
lines = resolverfile.read().splitlines() lines = resolverfile.read().splitlines()
resolvers = [x.strip() for x in lines if (x and not x.startswith("#"))] resolvers = [x.strip() for x in lines if (x and not x.startswith("#"))]
bf = aioDNSBrute(verbosity=verbosity, max_tasks=thread_count) bf = aioDNSBrute(verbosity=verbosity, max_tasks=thread_count)
subdomains_list = bf.run(wordlist, target, resolvers, wildcard, verify, query) subdomains_list = bf.run(wordlist, target, resolvers, wildcard, verify, query)
resolverfile.close() resolverfile.close()
for r in range(1, len(subdomains_list)): for r in range(1, len(subdomains_list)):
names_list.append(subdomains_list[r]['domain']) names_list.append(subdomains_list[r]['domain'])
return names_list return names_list