Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,22 @@ RUN mv Corsy-1.0-rc Corsy
RUN mv Corsy /usr/bin
RUN rm -rf *

# Install massdns
RUN echo "Installing massdns"
RUN git clone https://github.com/blechschmidt/massdns.git /massdns
WORKDIR /massdns
RUN make
RUN mv bin/massdns /usr/bin/massdns
WORKDIR /
RUN rm -rf /massdns

# Install puredns
RUN echo "Installing puredns"
RUN wget https://github.com/d3mondev/puredns/releases/download/v2.1.1/puredns_2.0.1_linux_amd64.tar.gz
RUN tar -xzf puredns_2.1.1_linux_amd64.tar.gz
RUN mv puredns /usr/bin/puredns
RUN rm -rf puredns_2.1.1_linux_amd64.tar.gz

# Install Poetry
RUN pip install poetry==1.4.2

Expand Down
2 changes: 1 addition & 1 deletion configs/local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ workflow:
cmd: []
workflowConfig:
- moduleName : discovery
tools: ['Subfinder','Go_Virustotal','Go_Wayback']
tools: ['Subfinder','Go_Virustotal','Go_Wayback','Puredns']
order: 1
- moduleName: prerecon
tools: ['FindCDN', 'Naabu']
Expand Down
2 changes: 1 addition & 1 deletion mantis/db/db_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Assets(BaseModel):
active_hosts: Optional[list] = list()
stale: Optional[bool] = False
repositories: Optional[str] = Field(None)
tools_source: Optional[str] = Field(None)
tool_source: Optional[str] = Field(None)
others: Optional[dict] = dict()


Expand Down
44 changes: 44 additions & 0 deletions mantis/modules/discovery/Puredns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from mantis.constants import ASSET_TYPE_SUBDOMAIN
from mantis.utils.crud_utils import CrudUtils
from mantis.tool_base_classes.toolScanner import ToolScanner
from mantis.models.args_model import ArgsModel
from mantis.utils.tool_utils import get_assets_grouped_by_type
from mantis.constants import ASSET_TYPE_TLD

'''
puredns is a fast domain resolver and subdomain bruteforcing tool that can accurately filter out wildcard subdomains and DNS poisoned entries.
Output file: .txt separated by new line.
Each subdomain discovered is inserted into the database as a new asset.
'''


class Puredns(ToolScanner):

def __init__(self) -> None:
super().__init__()
super().download_required_file()


async def get_commands(self, args: ArgsModel):
self.org = args.org
self.base_command = 'puredns bruteforce configs/resources/best-dns-wordlist.txt {input_domain} -r configs/resources/resolvers.txt --write {output_file_path}'
self.outfile_extension = ".txt"
self.assets = await get_assets_grouped_by_type(self, args, ASSET_TYPE_TLD)
return super().base_get_commands(self.assets)

def parse_report(self, outfile):
output_dict_list = []
puredns_output = open(outfile).readlines()
for domain in puredns_output:
domain_dict = {}
domain_dict['_id'] = domain.rstrip('\n')
domain_dict['asset'] = domain.rstrip('\n')
domain_dict['asset_type'] = ASSET_TYPE_SUBDOMAIN
domain_dict['org'] = self.org
domain_dict['tool_source'] = "Puredns"
output_dict_list.append(domain_dict)

return output_dict_list

async def db_operations(self, tool_output_dict, asset=None):
await CrudUtils.insert_assets(tool_output_dict)
49 changes: 47 additions & 2 deletions mantis/tool_base_classes/toolScanner.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from mantis.utils.base_request import BaseRequestExecutor
from mantis.utils.common_utils import CommonUtils
from subprocess import Popen, PIPE, DEVNULL
from mantis.models.args_model import ArgsModel
import logging
import sys
import time
import asyncio
import os
import requests

class ToolScanner:

Expand Down Expand Up @@ -35,8 +38,50 @@ def base_get_commands(self, assets) :
command_list.append((self, command, outfile, every_asset))
self.commands_list = command_list
return command_list



def download_required_file(self):
# Define the download directory
download_dir = "configs/resources/"
os.makedirs(download_dir, exist_ok=True)

# Define URLs and corresponding filenames
files = {
"https://raw.githubusercontent.com/trickest/resolvers/main/resolvers.txt": "resolvers.txt", # https://github.com/trickest
"https://wordlists-cdn.assetnote.io/data/manual/best-dns-wordlist.txt": "best-dns-wordlist.txt" # https://www.assetnote.io/
}

for url, filename in files.items():
file_path = os.path.join(download_dir, filename)

try:
print(f"Downloading {filename}...")
response = requests.get(url, stream=True)
response.raise_for_status() # Raise an error for bad status codes (4xx, 5xx)

# Get the total file size from the headers
total_size = int(response.headers.get('content-length', 0))
downloaded_size = 0

# Download the file in chunks
with open(file_path, "wb") as file:
for chunk in response.iter_content(chunk_size=8192):
if chunk: # Filter out keep-alive chunks
file.write(chunk)
downloaded_size += len(chunk)
# Print download progress
if total_size > 0:
progress = (downloaded_size / total_size) * 100
print(f"Downloaded {downloaded_size}/{total_size} bytes ({progress:.2f}%)", end="\r")

print(f"\nDownloaded {filename} successfully.")

except requests.exceptions.RequestException as e:
print(f"Failed to download {filename}: {e}")
# Optionally, delete the partially downloaded file
if os.path.exists(file_path):
os.remove(file_path)
print(f"Deleted partially downloaded file: {filename}")

def parse_report(self, outfile):
raise NotImplementedError

Expand Down