Merge pull request #5 from crahan/setup
Support installing via setup.py
This commit is contained in:
commit
2f2afbf79c
|
|
@ -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"]
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
include LICENSE README.md
|
include LICENSE README.md
|
||||||
include aiodnsbrute/*.txt
|
include sublist3r2/aiodnsbrute/*.txt
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
argparse
|
argparse
|
||||||
dnspython
|
dnspython
|
||||||
requests
|
requests
|
||||||
aiodnsbrute
|
asyncio
|
||||||
|
uvloop
|
||||||
|
tqdm
|
||||||
|
aiodns
|
||||||
|
click
|
||||||
|
|
@ -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',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
@ -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('<.*?>|>|<| ', '', link)
|
link = re.sub(r'<.*?>|>|<| ', '', 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()
|
||||||
|
|
@ -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:
|
||||||
|
|
@ -119,7 +119,6 @@ class aioDNSBrute(object):
|
||||||
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
|
||||||
lookup domain name; then attaches the processing callback to deal with the result.
|
lookup domain name; then attaches the processing callback to deal with the result.
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
Loading…
Reference in New Issue