From ac6e78ac349f0516c93a07c74d46883e1da2842e Mon Sep 17 00:00:00 2001 From: L1ghtn1ng Date: Sat, 19 Oct 2024 11:51:29 +0100 Subject: [PATCH 1/5] fix format --- dnsrecon/lib/crtenum.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dnsrecon/lib/crtenum.py b/dnsrecon/lib/crtenum.py index 2b8a190b..d7732319 100644 --- a/dnsrecon/lib/crtenum.py +++ b/dnsrecon/lib/crtenum.py @@ -28,7 +28,9 @@ def scrape_crtsh(dom): Function for enumerating subdomains by scraping crt.sh. """ results = [] - headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.3'} + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.3' + } url = f'https://crt.sh/?q=%25.{dom}' req = Request(url=url, headers=headers) From 577ab6ab3df23d4d76337cf2fafcdef41d19e412 Mon Sep 17 00:00:00 2001 From: L1ghtn1ng Date: Sat, 19 Oct 2024 12:09:38 +0100 Subject: [PATCH 2/5] Refactor logging and add log level argument Relocated logger configuration to respond to command line log level argument and refactored imports for readability. Added '--loglevel' argument to specify the logging level, defaulting to 'INFO'. This change enhances flexibility and control over the logging behavior based on user preferences. --- dnsrecon/cli.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dnsrecon/cli.py b/dnsrecon/cli.py index 18eb9826..e309237e 100755 --- a/dnsrecon/cli.py +++ b/dnsrecon/cli.py @@ -31,7 +31,7 @@ import os import sqlite3 import sys -from argparse import ArgumentParser, RawTextHelpFormatter, ArgumentError +from argparse import ArgumentError, ArgumentParser, RawTextHelpFormatter from concurrent import futures from pathlib import Path from random import SystemRandom @@ -1502,9 +1502,6 @@ def ds_zone_walk(res, domain, lifetime): def main(): - logger.remove() - logger.add(sys.stderr, format='{time} {level} {message}', level='DEBUG') - logger.add('~/.config/dnsrecon/dnsrecon.log', rotation='100 MB', compression='tar.gz') # # Option Variables # @@ -1607,6 +1604,15 @@ def main(): default=3.0, help='Time to wait for a server to respond to a query. default is 3.0', ) + + parser.add_argument( + '--loglevel', + type=str, + choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], + default='INFO', + help='Log level to use. default is INFO', + ) + parser.add_argument( '--tcp', dest='tcp', @@ -1665,6 +1671,9 @@ def main(): zonewalk: Perform a DNSSEC zone walk using NSEC records.""", ) arguments = parser.parse_args() + logger.remove() + logger.add(sys.stderr, format='{time} {level} {message}', level=arguments.loglevel) + logger.add('~/.config/dnsrecon/dnsrecon.log', rotation='100 MB', compression='tar.gz') except SystemExit: # Handle exit() from passing --help From 9821d20ede2077187d9572e66d8d7c8c86fc2b86 Mon Sep 17 00:00:00 2001 From: L1ghtn1ng Date: Sat, 19 Oct 2024 13:18:39 +0100 Subject: [PATCH 3/5] Rename variable '__name__' from 'cli.py' to 'cli' --- dnsrecon/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsrecon/cli.py b/dnsrecon/cli.py index e309237e..533e3b7d 100755 --- a/dnsrecon/cli.py +++ b/dnsrecon/cli.py @@ -18,7 +18,7 @@ __version__ = '1.3.0' __author__ = 'Carlos Perez, Carlos_Perez@darkoperator.com' -__name__ = 'cli.py' +__name__ = 'cli' __doc__ = """ DNSRecon https://www.darkoperator.com From be09ed8805bbfaf31b935c0df5f864fe972ebf25 Mon Sep 17 00:00:00 2001 From: L1ghtn1ng Date: Sat, 19 Oct 2024 13:19:10 +0100 Subject: [PATCH 4/5] Add new DNSRecon test cases using pytest and mocks Replaced old test cases with new ones using pytest and unittest.mock for better testing capabilities. New tests cover wildcard checks, IP range expansion, domain brute-forcing, and DNS enumeration functions. --- tests/test_dnsrecon.py | 114 +++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/tests/test_dnsrecon.py b/tests/test_dnsrecon.py index 1fc7b865..d0ea0e61 100644 --- a/tests/test_dnsrecon.py +++ b/tests/test_dnsrecon.py @@ -1,44 +1,72 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Unit test for DNSRecon main functions -# Author: Filippo Lauria (@filippolauria) -# -# Copyright (C) 2021 Carlos Perez -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; Applies version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - +import pytest +from unittest.mock import patch, MagicMock from dnsrecon import cli -from dnsrecon.lib.dnshelper import DnsHelper -import os - - -class Test_dnsrecon(): - - def test_in_cache(self): - namelist_filename = 'namelist.tmp' - namelist = ['localhost', 'test', 'www', 'mail'] - with open(namelist_filename, 'w') as fd: - fd.writelines([f"{name}\n" for name in namelist]) - helper = DnsHelper('zonetransfer.me') - ns = '81.4.108.41' - result = cli.in_cache(helper, namelist_filename, ns) - os.remove(namelist_filename) - assert len(result) == 1 and result[0]['type'] == 'A' - - def test_se_result_process(self): - helper = DnsHelper('zonetransfer.me') - hosts = ['www.megacorpone.com', 'www.zonetransfer.me'] - result = cli.se_result_process(helper, hosts) - assert len(result) >= 2 + + +def test_check_wildcard(): + with patch('dnsrecon.lib.dnshelper.DnsHelper') as mock_dns_helper: + mock_instance = mock_dns_helper.return_value + mock_instance.check_wildcard.return_value = (True, ["192.0.2.1"]) + result = cli.check_wildcard(mock_instance, "zonetransfer.me") + assert result == set() # The function returns an empty set + + +def test_expand_range(): + input_range = "192.0.2.0" + end_ip = "192.0.2.3" + result = cli.expand_range(input_range, end_ip) + assert len(result) == 4 + assert "192.0.2.0" in result + assert "192.0.2.3" in result + + +def test_brute_domain(): + with patch('dnsrecon.lib.dnshelper.DnsHelper') as mock_dns_helper, \ + patch('builtins.input', return_value='y'): # Mock user input + mock_instance = mock_dns_helper.return_value + mock_instance.get_a.return_value = ["192.0.2.1"] + mock_instance.get_aaaa.return_value = ["2001:db8::1"] + mock_instance.check_wildcard.return_value = (False, []) + + # Mock the generate_testname function to return a valid string + with patch('dnsrecon.cli.generate_testname', return_value='testname.zonetransfer.me'): + result = cli.brute_domain(mock_instance, "zonetransfer.me", ["subdomain"]) + + assert isinstance(result, list) + + +def test_general_enum(): + with patch('dnsrecon.lib.dnshelper.DnsHelper') as mock_dns_helper: + mock_instance = mock_dns_helper.return_value + mock_instance.get_a.return_value = ["192.0.2.1"] + mock_instance.get_aaaa.return_value = ["2001:db8::1"] + mock_instance.get_mx.return_value = ["mail.zonetransfer.me"] + mock_instance.get_txt.return_value = ["txt.zonetransfer.me"] + mock_instance.get_ns.return_value = ["ns.zonetransfer.me"] + mock_instance.get_soa.return_value = ["soa.zonetransfer.me"] + mock_instance.get_srv.return_value = ["srv.zonetransfer.me"] + mock_instance.get_spf.return_value = ["spf.zonetransfer.me"] + mock_instance.get_nsec.return_value = ["nsec.zonetransfer.me"] + mock_instance.get_nsec3.return_value = ["nsec3.zonetransfer.me"] + mock_instance.get_nsec3param.return_value = ["nsec3param.zonetransfer.me"] + mock_instance.get_ds.return_value = ["ds.zonetransfer.me"] + mock_instance.get_dnskey.return_value = ["dnskey.zonetransfer.me"] + mock_instance.get_rrsig.return_value = ["rrsig.zonetransfer.me"] + result = cli.general_enum(mock_instance, "zonetransfer.me", True, True, True, True, True, True, True, 5.0) + assert result is None # The function doesn't return anything + + +def test_get_nsec_type(): + with patch('dnsrecon.lib.dnshelper.DnsHelper') as mock_dns_helper: + mock_instance = mock_dns_helper.return_value + mock_instance._res = MagicMock() + mock_instance._res.nameservers = ["8.8.8.8"] + mock_instance._res.timeout = 2.0 + + mock_answer = MagicMock() + mock_answer.authority = [] + + with patch('dnsrecon.cli.get_a_answer', return_value=mock_answer): + result = cli.get_nsec_type("zonetransfer.me", mock_instance) + + assert result is None From bb0b189dfd6f4ae87a60e4af142f0dccc1341b13 Mon Sep 17 00:00:00 2001 From: L1ghtn1ng Date: Sat, 19 Oct 2024 13:20:46 +0100 Subject: [PATCH 5/5] remove un-needed import --- tests/test_dnsrecon.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_dnsrecon.py b/tests/test_dnsrecon.py index d0ea0e61..037de9f0 100644 --- a/tests/test_dnsrecon.py +++ b/tests/test_dnsrecon.py @@ -1,4 +1,3 @@ -import pytest from unittest.mock import patch, MagicMock from dnsrecon import cli