mirror of
https://github.com/aljazceru/recon-pipeline.git
synced 2025-12-19 23:34:27 +01:00
Dependency Checking (#75)
* Adds req testing methodology, needs fixes * Improves dependency exception handling * Better meets_requirements implementation Still need to adjust tests to fake installation * Changes to exception boolean to enable tool check tests and class variables modified for new tool check * Adjust test_get_scans to use appropriate variable * Adds Go requirement where relevant * Adds missing scan dependencies * Add clarification to error message
This commit is contained in:
@@ -298,10 +298,14 @@ class ReconShell(cmd2.Cmd):
|
|||||||
# get_scans() returns mapping of {classname: [modulename, ...]} in the recon module
|
# get_scans() returns mapping of {classname: [modulename, ...]} in the recon module
|
||||||
# each classname corresponds to a potential recon-pipeline command, i.e. AmassScan, GobusterScan ...
|
# each classname corresponds to a potential recon-pipeline command, i.e. AmassScan, GobusterScan ...
|
||||||
scans = get_scans()
|
scans = get_scans()
|
||||||
|
|
||||||
# command is a list that will end up looking something like what's below
|
# command is a list that will end up looking something like what's below
|
||||||
# luigi --module pipeline.recon.web.webanalyze WebanalyzeScan --target abc.com --top-ports 100 --interface eth0
|
# luigi --module pipeline.recon.web.webanalyze WebanalyzeScan --target abc.com --top-ports 100 --interface eth0
|
||||||
command = ["luigi", "--module", scans.get(args.scantype)[0]]
|
try:
|
||||||
|
command = ["luigi", "--module", scans.get(args.scantype)[0]]
|
||||||
|
except TypeError:
|
||||||
|
return self.poutput(
|
||||||
|
style(f"[!] {args.scantype} or one of its dependencies is not installed", fg="bright_red")
|
||||||
|
)
|
||||||
|
|
||||||
tgt_file_path = None
|
tgt_file_path = None
|
||||||
if args.target:
|
if args.target:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from luigi.contrib.sqla import SQLAlchemyTarget
|
|||||||
import pipeline.models.db_manager
|
import pipeline.models.db_manager
|
||||||
from ..tools import tools
|
from ..tools import tools
|
||||||
from .targets import TargetList
|
from .targets import TargetList
|
||||||
from .helpers import get_tool_state
|
from .helpers import meets_requirements
|
||||||
from ..models.target_model import Target
|
from ..models.target_model import Target
|
||||||
|
|
||||||
|
|
||||||
@@ -43,21 +43,14 @@ class AmassScan(luigi.Task):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
exempt_list = luigi.Parameter(default="")
|
exempt_list = luigi.Parameter(default="")
|
||||||
|
requirements = ["go", "amass"]
|
||||||
|
exception = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
||||||
self.results_subfolder = (Path(self.results_dir) / "amass-results").expanduser().resolve()
|
self.results_subfolder = (Path(self.results_dir) / "amass-results").expanduser().resolve()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def meets_requirements():
|
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["amass"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" AmassScan depends on TargetList to run.
|
""" AmassScan depends on TargetList to run.
|
||||||
|
|
||||||
@@ -66,6 +59,7 @@ class AmassScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
luigi.ExternalTask - TargetList
|
luigi.ExternalTask - TargetList
|
||||||
"""
|
"""
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {"target_file": self.target_file, "results_dir": self.results_dir, "db_location": self.db_location}
|
args = {"target_file": self.target_file, "results_dir": self.results_dir, "db_location": self.db_location}
|
||||||
return TargetList(**args)
|
return TargetList(**args)
|
||||||
|
|
||||||
@@ -89,7 +83,6 @@ class AmassScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
list: list of options/arguments, beginning with the name of the executable to run
|
list: list of options/arguments, beginning with the name of the executable to run
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.results_subfolder.mkdir(parents=True, exist_ok=True)
|
self.results_subfolder.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
hostnames = self.db_mgr.get_all_hostnames()
|
hostnames = self.db_mgr.get_all_hostnames()
|
||||||
|
|||||||
@@ -6,11 +6,29 @@ import pkgutil
|
|||||||
import importlib
|
import importlib
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from cmd2.ansi import style
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from ..recon.config import defaults
|
from ..recon.config import defaults
|
||||||
|
|
||||||
|
|
||||||
|
def meets_requirements(requirements, exception):
|
||||||
|
""" Determine if tools required to perform task are installed. """
|
||||||
|
tools = get_tool_state()
|
||||||
|
|
||||||
|
for tool in requirements:
|
||||||
|
if not tools.get(tool).get("installed"):
|
||||||
|
if exception:
|
||||||
|
raise RuntimeError(
|
||||||
|
style(f"[!!] {tool} is not installed, and is required to run this scan", fg="bright_red")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def get_tool_state() -> typing.Union[dict, None]:
|
def get_tool_state() -> typing.Union[dict, None]:
|
||||||
""" Load current tool state from disk. """
|
""" Load current tool state from disk. """
|
||||||
tools = Path(defaults.get("tools-dir")) / ".tool-dict.pkl"
|
tools = Path(defaults.get("tools-dir")) / ".tool-dict.pkl"
|
||||||
@@ -60,7 +78,9 @@ def get_scans():
|
|||||||
# final check, this ensures that the tools necessary to AT LEAST run this scan are present
|
# final check, this ensures that the tools necessary to AT LEAST run this scan are present
|
||||||
# does not consider upstream dependencies
|
# does not consider upstream dependencies
|
||||||
try:
|
try:
|
||||||
if not sub_obj.meets_requirements():
|
requirements = sub_obj.requirements
|
||||||
|
exception = False # let meets_req know we want boolean result
|
||||||
|
if not meets_requirements(requirements, exception):
|
||||||
continue
|
continue
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# some scan's haven't implemented meets_requirements yet, silently allow them through
|
# some scan's haven't implemented meets_requirements yet, silently allow them through
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from .amass import ParseAmassOutput
|
|||||||
from ..models.port_model import Port
|
from ..models.port_model import Port
|
||||||
from ..models.ip_address_model import IPAddress
|
from ..models.ip_address_model import IPAddress
|
||||||
|
|
||||||
from .helpers import get_tool_state
|
from .helpers import meets_requirements
|
||||||
from .config import top_tcp_ports, top_udp_ports, defaults, web_ports
|
from .config import top_tcp_ports, top_udp_ports, defaults, web_ports
|
||||||
|
|
||||||
|
|
||||||
@@ -58,21 +58,14 @@ class MasscanScan(luigi.Task):
|
|||||||
interface = luigi.Parameter(default=defaults.get("masscan-iface"))
|
interface = luigi.Parameter(default=defaults.get("masscan-iface"))
|
||||||
top_ports = luigi.IntParameter(default=0) # IntParameter -> top_ports expected as int
|
top_ports = luigi.IntParameter(default=0) # IntParameter -> top_ports expected as int
|
||||||
ports = luigi.Parameter(default="")
|
ports = luigi.Parameter(default="")
|
||||||
|
requirements = ["masscan"]
|
||||||
|
exception = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
||||||
self.results_subfolder = (Path(self.results_dir) / "masscan-results").expanduser().resolve()
|
self.results_subfolder = (Path(self.results_dir) / "masscan-results").expanduser().resolve()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def meets_requirements():
|
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["masscan"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def output(self):
|
def output(self):
|
||||||
""" Returns the target output for this task.
|
""" Returns the target output for this task.
|
||||||
|
|
||||||
@@ -91,6 +84,7 @@ class MasscanScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
list: list of options/arguments, beginning with the name of the executable to run
|
list: list of options/arguments, beginning with the name of the executable to run
|
||||||
"""
|
"""
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
if not self.ports and not self.top_ports:
|
if not self.ports and not self.top_ports:
|
||||||
# need at least one, can't be put into argparse scanner because things like amass don't require ports option
|
# need at least one, can't be put into argparse scanner because things like amass don't require ports option
|
||||||
logging.error("Must specify either --top-ports or --ports.")
|
logging.error("Must specify either --top-ports or --ports.")
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import logging
|
|||||||
import subprocess
|
import subprocess
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from shutil import which
|
||||||
|
from cmd2.ansi import style
|
||||||
|
|
||||||
import luigi
|
import luigi
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
@@ -13,10 +15,9 @@ from luigi.contrib.sqla import SQLAlchemyTarget
|
|||||||
import pipeline.models.db_manager
|
import pipeline.models.db_manager
|
||||||
from .masscan import ParseMasscanOutput
|
from .masscan import ParseMasscanOutput
|
||||||
from .config import defaults
|
from .config import defaults
|
||||||
from .helpers import get_ip_address_version, is_ip_address
|
from .helpers import get_ip_address_version, is_ip_address, meets_requirements
|
||||||
|
|
||||||
from ..tools import tools
|
from ..tools import tools
|
||||||
from .helpers import get_tool_state
|
|
||||||
from ..models.port_model import Port
|
from ..models.port_model import Port
|
||||||
from ..models.nse_model import NSEResult
|
from ..models.nse_model import NSEResult
|
||||||
from ..models.target_model import Target
|
from ..models.target_model import Target
|
||||||
@@ -58,6 +59,8 @@ class ThreadedNmapScan(luigi.Task):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
if not which("nmap"):
|
||||||
|
raise RuntimeError(style("[!] nmap is not installed", fg="bright_red"))
|
||||||
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
||||||
self.results_subfolder = (Path(self.results_dir) / "nmap-results").expanduser().resolve()
|
self.results_subfolder = (Path(self.results_dir) / "nmap-results").expanduser().resolve()
|
||||||
|
|
||||||
@@ -238,19 +241,13 @@ class SearchsploitScan(luigi.Task):
|
|||||||
results_dir: specifies the directory on disk to which all Task results are written *Required by upstream Task*
|
results_dir: specifies the directory on disk to which all Task results are written *Required by upstream Task*
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
requirements = ["searchsploit"]
|
||||||
|
exception = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def meets_requirements():
|
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["searchsploit"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" Searchsploit depends on ThreadedNmap to run.
|
""" Searchsploit depends on ThreadedNmap to run.
|
||||||
|
|
||||||
@@ -261,6 +258,7 @@ class SearchsploitScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
luigi.Task - ThreadedNmap
|
luigi.Task - ThreadedNmap
|
||||||
"""
|
"""
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {
|
args = {
|
||||||
"rate": self.rate,
|
"rate": self.rate,
|
||||||
"ports": self.ports,
|
"ports": self.ports,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from ..config import defaults
|
|||||||
from ...tools import tools
|
from ...tools import tools
|
||||||
|
|
||||||
import pipeline.models.db_manager
|
import pipeline.models.db_manager
|
||||||
from ..helpers import get_tool_state
|
from ..helpers import meets_requirements
|
||||||
from ...models.port_model import Port
|
from ...models.port_model import Port
|
||||||
from ...models.header_model import Header
|
from ...models.header_model import Header
|
||||||
from ...models.endpoint_model import Endpoint
|
from ...models.endpoint_model import Endpoint
|
||||||
@@ -58,21 +58,14 @@ class AquatoneScan(luigi.Task):
|
|||||||
|
|
||||||
threads = luigi.Parameter(default=defaults.get("threads", ""))
|
threads = luigi.Parameter(default=defaults.get("threads", ""))
|
||||||
scan_timeout = luigi.Parameter(default=defaults.get("aquatone-scan-timeout", ""))
|
scan_timeout = luigi.Parameter(default=defaults.get("aquatone-scan-timeout", ""))
|
||||||
|
requirements = ["aquatone", "masscan"]
|
||||||
|
exception = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
||||||
self.results_subfolder = Path(self.results_dir) / "aquatone-results"
|
self.results_subfolder = Path(self.results_dir) / "aquatone-results"
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def meets_requirements():
|
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["aquatone"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" AquatoneScan depends on GatherWebTargets to run.
|
""" AquatoneScan depends on GatherWebTargets to run.
|
||||||
|
|
||||||
@@ -82,6 +75,7 @@ class AquatoneScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
luigi.Task - GatherWebTargets
|
luigi.Task - GatherWebTargets
|
||||||
"""
|
"""
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {
|
args = {
|
||||||
"results_dir": self.results_dir,
|
"results_dir": self.results_dir,
|
||||||
"rate": self.rate,
|
"rate": self.rate,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from luigi.contrib.sqla import SQLAlchemyTarget
|
|||||||
import pipeline.models.db_manager
|
import pipeline.models.db_manager
|
||||||
from ...tools import tools
|
from ...tools import tools
|
||||||
from ..config import defaults
|
from ..config import defaults
|
||||||
from ..helpers import get_tool_state
|
from ..helpers import meets_requirements
|
||||||
from .targets import GatherWebTargets
|
from .targets import GatherWebTargets
|
||||||
from ...models.endpoint_model import Endpoint
|
from ...models.endpoint_model import Endpoint
|
||||||
from ..helpers import get_ip_address_version, is_ip_address
|
from ..helpers import get_ip_address_version, is_ip_address
|
||||||
@@ -59,21 +59,14 @@ class GobusterScan(luigi.Task):
|
|||||||
threads = luigi.Parameter(default=defaults.get("threads"))
|
threads = luigi.Parameter(default=defaults.get("threads"))
|
||||||
wordlist = luigi.Parameter(default=defaults.get("gobuster-wordlist"))
|
wordlist = luigi.Parameter(default=defaults.get("gobuster-wordlist"))
|
||||||
extensions = luigi.Parameter(default=defaults.get("gobuster-extensions"))
|
extensions = luigi.Parameter(default=defaults.get("gobuster-extensions"))
|
||||||
|
requirements = ["recursive-gobuster", "go", "gobuster", "masscan"]
|
||||||
|
exception = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
||||||
self.results_subfolder = Path(self.results_dir) / "gobuster-results"
|
self.results_subfolder = Path(self.results_dir) / "gobuster-results"
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def meets_requirements():
|
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["recursive-gobuster", "gobuster"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" GobusterScan depends on GatherWebTargets to run.
|
""" GobusterScan depends on GatherWebTargets to run.
|
||||||
|
|
||||||
@@ -83,6 +76,7 @@ class GobusterScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
luigi.Task - GatherWebTargets
|
luigi.Task - GatherWebTargets
|
||||||
"""
|
"""
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {
|
args = {
|
||||||
"results_dir": self.results_dir,
|
"results_dir": self.results_dir,
|
||||||
"rate": self.rate,
|
"rate": self.rate,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from luigi.contrib.sqla import SQLAlchemyTarget
|
|||||||
import pipeline.models.db_manager
|
import pipeline.models.db_manager
|
||||||
from ...tools import tools
|
from ...tools import tools
|
||||||
from ..config import defaults
|
from ..config import defaults
|
||||||
from ..helpers import get_tool_state
|
from ..helpers import meets_requirements
|
||||||
from .targets import GatherWebTargets
|
from .targets import GatherWebTargets
|
||||||
|
|
||||||
|
|
||||||
@@ -47,21 +47,15 @@ class TKOSubsScan(luigi.Task):
|
|||||||
results_dir: specifes the directory on disk to which all Task results are written *Required by upstream Task*
|
results_dir: specifes the directory on disk to which all Task results are written *Required by upstream Task*
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
requirements = ["go", "tko-subs", "masscan"]
|
||||||
|
exception = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
||||||
self.results_subfolder = (Path(self.results_dir) / "tkosubs-results").expanduser().resolve()
|
self.results_subfolder = (Path(self.results_dir) / "tkosubs-results").expanduser().resolve()
|
||||||
self.output_file = self.results_subfolder / "tkosubs.csv"
|
self.output_file = self.results_subfolder / "tkosubs.csv"
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def meets_requirements():
|
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["tko-subs"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" TKOSubsScan depends on GatherWebTargets to run.
|
""" TKOSubsScan depends on GatherWebTargets to run.
|
||||||
|
|
||||||
@@ -71,6 +65,7 @@ class TKOSubsScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
luigi.Task - GatherWebTargets
|
luigi.Task - GatherWebTargets
|
||||||
"""
|
"""
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {
|
args = {
|
||||||
"results_dir": self.results_dir,
|
"results_dir": self.results_dir,
|
||||||
"rate": self.rate,
|
"rate": self.rate,
|
||||||
@@ -177,6 +172,8 @@ class SubjackScan(luigi.Task):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
threads = luigi.Parameter(default=defaults.get("threads"))
|
threads = luigi.Parameter(default=defaults.get("threads"))
|
||||||
|
requirements = ["go", "subjack", "masscan"]
|
||||||
|
exception = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@@ -184,15 +181,6 @@ class SubjackScan(luigi.Task):
|
|||||||
self.results_subfolder = (Path(self.results_dir) / "subjack-results").expanduser().resolve()
|
self.results_subfolder = (Path(self.results_dir) / "subjack-results").expanduser().resolve()
|
||||||
self.output_file = self.results_subfolder / "subjack.txt"
|
self.output_file = self.results_subfolder / "subjack.txt"
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def meets_requirements():
|
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["subjack"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" SubjackScan depends on GatherWebTargets to run.
|
""" SubjackScan depends on GatherWebTargets to run.
|
||||||
|
|
||||||
@@ -202,6 +190,7 @@ class SubjackScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
luigi.Task - GatherWebTargets
|
luigi.Task - GatherWebTargets
|
||||||
"""
|
"""
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {
|
args = {
|
||||||
"results_dir": self.results_dir,
|
"results_dir": self.results_dir,
|
||||||
"rate": self.rate,
|
"rate": self.rate,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from luigi.contrib.sqla import SQLAlchemyTarget
|
|||||||
|
|
||||||
from .targets import GatherWebTargets
|
from .targets import GatherWebTargets
|
||||||
from ...tools import tools
|
from ...tools import tools
|
||||||
from ..helpers import get_tool_state
|
from ..helpers import meets_requirements
|
||||||
from ...models.endpoint_model import Endpoint
|
from ...models.endpoint_model import Endpoint
|
||||||
|
|
||||||
import pipeline.models.db_manager
|
import pipeline.models.db_manager
|
||||||
@@ -44,20 +44,14 @@ class WaybackurlsScan(luigi.Task):
|
|||||||
results_dir: specifes the directory on disk to which all Task results are written *Required by upstream Task*
|
results_dir: specifes the directory on disk to which all Task results are written *Required by upstream Task*
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
requirements = ["go", "waybackurls", "masscan"]
|
||||||
|
exception = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
||||||
self.results_subfolder = Path(self.results_dir) / "waybackurls-results"
|
self.results_subfolder = Path(self.results_dir) / "waybackurls-results"
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def meets_requirements():
|
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["waybackurls"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" WaybackurlsScan depends on GatherWebTargets to run.
|
""" WaybackurlsScan depends on GatherWebTargets to run.
|
||||||
|
|
||||||
@@ -67,6 +61,7 @@ class WaybackurlsScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
luigi.Task - GatherWebTargets
|
luigi.Task - GatherWebTargets
|
||||||
"""
|
"""
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {
|
args = {
|
||||||
"results_dir": self.results_dir,
|
"results_dir": self.results_dir,
|
||||||
"rate": self.rate,
|
"rate": self.rate,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from luigi.contrib.sqla import SQLAlchemyTarget
|
|||||||
import pipeline.models.db_manager
|
import pipeline.models.db_manager
|
||||||
from ...tools import tools
|
from ...tools import tools
|
||||||
from ..config import defaults
|
from ..config import defaults
|
||||||
from ..helpers import get_tool_state
|
from ..helpers import meets_requirements
|
||||||
from .targets import GatherWebTargets
|
from .targets import GatherWebTargets
|
||||||
from ...models.technology_model import Technology
|
from ...models.technology_model import Technology
|
||||||
from ..helpers import get_ip_address_version, is_ip_address
|
from ..helpers import get_ip_address_version, is_ip_address
|
||||||
@@ -54,21 +54,14 @@ class WebanalyzeScan(luigi.Task):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
threads = luigi.Parameter(default=defaults.get("threads"))
|
threads = luigi.Parameter(default=defaults.get("threads"))
|
||||||
|
requirements = ["go", "webanalyze", "masscan"]
|
||||||
|
exception = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
self.db_mgr = pipeline.models.db_manager.DBManager(db_location=self.db_location)
|
||||||
self.results_subfolder = Path(self.results_dir) / "webanalyze-results"
|
self.results_subfolder = Path(self.results_dir) / "webanalyze-results"
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def meets_requirements():
|
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["webanalyze"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" WebanalyzeScan depends on GatherWebTargets to run.
|
""" WebanalyzeScan depends on GatherWebTargets to run.
|
||||||
|
|
||||||
@@ -78,6 +71,7 @@ class WebanalyzeScan(luigi.Task):
|
|||||||
Returns:
|
Returns:
|
||||||
luigi.Task - GatherWebTargets
|
luigi.Task - GatherWebTargets
|
||||||
"""
|
"""
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {
|
args = {
|
||||||
"results_dir": self.results_dir,
|
"results_dir": self.results_dir,
|
||||||
"rate": self.rate,
|
"rate": self.rate,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import luigi
|
|||||||
from luigi.util import inherits
|
from luigi.util import inherits
|
||||||
|
|
||||||
from .nmap import SearchsploitScan
|
from .nmap import SearchsploitScan
|
||||||
from .helpers import get_tool_state
|
from .helpers import meets_requirements
|
||||||
from .web import AquatoneScan, GobusterScan, SubjackScan, TKOSubsScan, WaybackurlsScan, WebanalyzeScan
|
from .web import AquatoneScan, GobusterScan, SubjackScan, TKOSubsScan, WaybackurlsScan, WebanalyzeScan
|
||||||
|
|
||||||
|
|
||||||
@@ -28,28 +28,24 @@ class FullScan(luigi.WrapperTask):
|
|||||||
results_dir: specifes the directory on disk to which all Task results are written
|
results_dir: specifes the directory on disk to which all Task results are written
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@staticmethod
|
requirements = [
|
||||||
def meets_requirements():
|
"amass",
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
"aquatone",
|
||||||
needs = [
|
"masscan",
|
||||||
"amass",
|
"tko-subs",
|
||||||
"aquatone",
|
"recursive-gobuster",
|
||||||
"masscan",
|
"searchsploit",
|
||||||
"tko-subs",
|
"subjack",
|
||||||
"recursive-gobuster",
|
"gobuster",
|
||||||
"searchsploit",
|
"webanalyze",
|
||||||
"subjack",
|
"waybackurls",
|
||||||
"gobuster",
|
"go",
|
||||||
"webanalyze",
|
]
|
||||||
"waybackurls",
|
exception = True
|
||||||
]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" FullScan is a wrapper, as such it requires any Tasks that it wraps. """
|
""" FullScan is a wrapper, as such it requires any Tasks that it wraps. """
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {
|
args = {
|
||||||
"results_dir": self.results_dir,
|
"results_dir": self.results_dir,
|
||||||
"rate": self.rate,
|
"rate": self.rate,
|
||||||
@@ -111,17 +107,12 @@ class HTBScan(luigi.WrapperTask):
|
|||||||
results_dir: specifes the directory on disk to which all Task results are written
|
results_dir: specifes the directory on disk to which all Task results are written
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@staticmethod
|
requirements = ["aquatone", "go", "masscan", "recursive-gobuster", "searchsploit", "gobuster", "webanalyze"]
|
||||||
def meets_requirements():
|
exception = True
|
||||||
""" Reports whether or not this scan's needed tool(s) are installed or not """
|
|
||||||
needs = ["aquatone", "masscan", "recursive-gobuster", "searchsploit", "gobuster", "webanalyze"]
|
|
||||||
tools = get_tool_state()
|
|
||||||
|
|
||||||
if tools:
|
|
||||||
return all([tools.get(x).get("installed") is True for x in needs])
|
|
||||||
|
|
||||||
def requires(self):
|
def requires(self):
|
||||||
""" HTBScan is a wrapper, as such it requires any Tasks that it wraps. """
|
""" HTBScan is a wrapper, as such it requires any Tasks that it wraps. """
|
||||||
|
meets_requirements(self.requirements, self.exception)
|
||||||
args = {
|
args = {
|
||||||
"results_dir": self.results_dir,
|
"results_dir": self.results_dir,
|
||||||
"rate": self.rate,
|
"rate": self.rate,
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ class TestAmassScan:
|
|||||||
|
|
||||||
def test_scan_requires(self):
|
def test_scan_requires(self):
|
||||||
with patch("pipeline.recon.TargetList"):
|
with patch("pipeline.recon.TargetList"):
|
||||||
retval = self.scan.requires()
|
with patch("pipeline.recon.amass.meets_requirements"):
|
||||||
assert isinstance(retval, TargetList)
|
retval = self.scan.requires()
|
||||||
|
assert isinstance(retval, TargetList)
|
||||||
|
|
||||||
def test_scan_run(self):
|
def test_scan_run(self):
|
||||||
with patch("subprocess.run") as mocked_run:
|
with patch("subprocess.run") as mocked_run:
|
||||||
|
|||||||
@@ -1,34 +1,61 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
from pipeline.recon.helpers import get_ip_address_version, get_scans, is_ip_address
|
from pipeline.recon.helpers import get_ip_address_version, get_scans, is_ip_address, meets_requirements
|
||||||
from pipeline.recon import AmassScan, MasscanScan, FullScan, HTBScan, SearchsploitScan, ThreadedNmapScan
|
from pipeline.recon import AmassScan, MasscanScan, FullScan, HTBScan, SearchsploitScan, ThreadedNmapScan
|
||||||
from pipeline.recon.web import GobusterScan, SubjackScan, TKOSubsScan, AquatoneScan, WaybackurlsScan, WebanalyzeScan
|
from pipeline.recon.web import GobusterScan, SubjackScan, TKOSubsScan, AquatoneScan, WaybackurlsScan, WebanalyzeScan
|
||||||
|
|
||||||
|
|
||||||
def test_get_scans():
|
def test_get_scans():
|
||||||
|
with patch("pipeline.recon.helpers.meets_requirements"):
|
||||||
|
scan_names = [
|
||||||
|
AmassScan,
|
||||||
|
GobusterScan,
|
||||||
|
MasscanScan,
|
||||||
|
SubjackScan,
|
||||||
|
TKOSubsScan,
|
||||||
|
AquatoneScan,
|
||||||
|
FullScan,
|
||||||
|
HTBScan,
|
||||||
|
SearchsploitScan,
|
||||||
|
ThreadedNmapScan,
|
||||||
|
WebanalyzeScan,
|
||||||
|
WaybackurlsScan,
|
||||||
|
]
|
||||||
|
|
||||||
scan_names = [
|
scans = get_scans()
|
||||||
AmassScan,
|
for scan in scan_names:
|
||||||
GobusterScan,
|
if hasattr(scan, "requirements"):
|
||||||
MasscanScan,
|
assert scan.__name__ in scans.keys()
|
||||||
SubjackScan,
|
else:
|
||||||
TKOSubsScan,
|
assert scan not in scans.keys()
|
||||||
AquatoneScan,
|
|
||||||
FullScan,
|
|
||||||
HTBScan,
|
|
||||||
SearchsploitScan,
|
|
||||||
ThreadedNmapScan,
|
|
||||||
WebanalyzeScan,
|
|
||||||
WaybackurlsScan,
|
|
||||||
]
|
|
||||||
|
|
||||||
scans = get_scans()
|
|
||||||
|
|
||||||
for scan in scan_names:
|
@pytest.mark.parametrize(
|
||||||
if hasattr(scan, "meets_requirements") and scan.meets_requirements():
|
"requirements, exception",
|
||||||
assert scan.__name__ in scans.keys()
|
[
|
||||||
else:
|
(["amass"], True),
|
||||||
assert scan not in scans.keys()
|
(["masscan"], True),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
"amass",
|
||||||
|
"aquatone",
|
||||||
|
"masscan",
|
||||||
|
"tko-subs",
|
||||||
|
"recursive-gobuster",
|
||||||
|
"searchsploit",
|
||||||
|
"subjack",
|
||||||
|
"gobuster",
|
||||||
|
"webanalyze",
|
||||||
|
"waybackurls",
|
||||||
|
],
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_meets_requirements(requirements, exception):
|
||||||
|
with patch("pipeline.recon.helpers.get_tool_state"):
|
||||||
|
assert meets_requirements(requirements, exception)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class TestMasscanScan:
|
|||||||
self.scan = MasscanScan(
|
self.scan = MasscanScan(
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
)
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|||||||
@@ -15,18 +15,23 @@ nmap_results = Path(__file__).parent.parent / "data" / "recon-results" / "nmap-r
|
|||||||
|
|
||||||
class TestThreadedNmapScan:
|
class TestThreadedNmapScan:
|
||||||
def setup_method(self):
|
def setup_method(self):
|
||||||
self.tmp_path = Path(tempfile.mkdtemp())
|
with patch("pipeline.recon.nmap.which"):
|
||||||
self.scan = ThreadedNmapScan(
|
self.tmp_path = Path(tempfile.mkdtemp())
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
shutil.which = MagicMock()
|
||||||
)
|
shutil.which.return_value = True
|
||||||
|
self.scan = ThreadedNmapScan(
|
||||||
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|
||||||
def test_scan_requires(self):
|
def test_scan_requires(self):
|
||||||
with patch("pipeline.recon.ParseMasscanOutput"):
|
with patch("pipeline.recon.ParseMasscanOutput"):
|
||||||
retval = self.scan.requires()
|
with patch("pipeline.recon.nmap.which"):
|
||||||
assert isinstance(retval, ParseMasscanOutput)
|
retval = self.scan.requires()
|
||||||
|
assert isinstance(retval, ParseMasscanOutput)
|
||||||
|
|
||||||
def test_scan_run(self):
|
def test_scan_run(self):
|
||||||
with patch("concurrent.futures.ThreadPoolExecutor.map") as mocked_run:
|
with patch("concurrent.futures.ThreadPoolExecutor.map") as mocked_run:
|
||||||
@@ -75,14 +80,17 @@ class TestSearchsploitScan:
|
|||||||
self.scan = SearchsploitScan(
|
self.scan = SearchsploitScan(
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
)
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|
||||||
def test_scan_requires(self):
|
def test_scan_requires(self):
|
||||||
with patch("pipeline.recon.ThreadedNmapScan"):
|
with patch("pipeline.recon.ThreadedNmapScan"):
|
||||||
retval = self.scan.requires()
|
with patch("pipeline.recon.nmap.meets_requirements"):
|
||||||
assert isinstance(retval, ThreadedNmapScan)
|
with patch("pipeline.recon.nmap.which"):
|
||||||
|
retval = self.scan.requires()
|
||||||
|
assert isinstance(retval, ThreadedNmapScan)
|
||||||
|
|
||||||
def test_scan_output(self):
|
def test_scan_output(self):
|
||||||
retval = self.scan.output()
|
retval = self.scan.output()
|
||||||
|
|||||||
@@ -15,14 +15,16 @@ class TestAquatoneScan:
|
|||||||
self.scan = AquatoneScan(
|
self.scan = AquatoneScan(
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
)
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|
||||||
def test_scan_requires(self):
|
def test_scan_requires(self):
|
||||||
with patch("pipeline.recon.web.GatherWebTargets"):
|
with patch("pipeline.recon.web.GatherWebTargets"):
|
||||||
retval = self.scan.requires()
|
with patch("pipeline.recon.web.aquatone.meets_requirements"):
|
||||||
assert isinstance(retval, GatherWebTargets)
|
retval = self.scan.requires()
|
||||||
|
assert isinstance(retval, GatherWebTargets)
|
||||||
|
|
||||||
def test_scan_creates_results_dir(self):
|
def test_scan_creates_results_dir(self):
|
||||||
assert self.scan.results_subfolder == self.tmp_path / "aquatone-results"
|
assert self.scan.results_subfolder == self.tmp_path / "aquatone-results"
|
||||||
|
|||||||
@@ -14,14 +14,16 @@ class TestGobusterScan:
|
|||||||
self.scan = GobusterScan(
|
self.scan = GobusterScan(
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
)
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|
||||||
def test_scan_requires(self):
|
def test_scan_requires(self):
|
||||||
with patch("pipeline.recon.web.GatherWebTargets"):
|
with patch("pipeline.recon.web.GatherWebTargets"):
|
||||||
retval = self.scan.requires()
|
with patch("pipeline.recon.web.gobuster.meets_requirements"):
|
||||||
assert isinstance(retval, GatherWebTargets)
|
retval = self.scan.requires()
|
||||||
|
assert isinstance(retval, GatherWebTargets)
|
||||||
|
|
||||||
def test_scan_run(self):
|
def test_scan_run(self):
|
||||||
with patch("concurrent.futures.ThreadPoolExecutor.map") as mocked_run:
|
with patch("concurrent.futures.ThreadPoolExecutor.map") as mocked_run:
|
||||||
|
|||||||
@@ -17,14 +17,16 @@ class TestTKOSubsScanScan:
|
|||||||
self.scan = TKOSubsScan(
|
self.scan = TKOSubsScan(
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
)
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|
||||||
def test_scan_requires(self):
|
def test_scan_requires(self):
|
||||||
with patch("pipeline.recon.web.GatherWebTargets"):
|
with patch("pipeline.recon.web.GatherWebTargets"):
|
||||||
retval = self.scan.requires()
|
with patch("pipeline.recon.web.subdomain_takeover.meets_requirements"):
|
||||||
assert isinstance(retval, GatherWebTargets)
|
retval = self.scan.requires()
|
||||||
|
assert isinstance(retval, GatherWebTargets)
|
||||||
|
|
||||||
def test_scan_creates_results_dir(self):
|
def test_scan_creates_results_dir(self):
|
||||||
assert self.scan.results_subfolder == self.tmp_path / "tkosubs-results"
|
assert self.scan.results_subfolder == self.tmp_path / "tkosubs-results"
|
||||||
@@ -84,14 +86,16 @@ class TestSubjackScan:
|
|||||||
self.scan = SubjackScan(
|
self.scan = SubjackScan(
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
)
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|
||||||
def test_scan_requires(self):
|
def test_scan_requires(self):
|
||||||
with patch("pipeline.recon.web.GatherWebTargets"):
|
with patch("pipeline.recon.web.GatherWebTargets"):
|
||||||
retval = self.scan.requires()
|
with patch("pipeline.recon.web.subdomain_takeover.meets_requirements"):
|
||||||
assert isinstance(retval, GatherWebTargets)
|
retval = self.scan.requires()
|
||||||
|
assert isinstance(retval, GatherWebTargets)
|
||||||
|
|
||||||
def test_scan_creates_results_dir(self):
|
def test_scan_creates_results_dir(self):
|
||||||
assert self.scan.results_subfolder == self.tmp_path / "subjack-results"
|
assert self.scan.results_subfolder == self.tmp_path / "subjack-results"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class TestGatherWebTargets:
|
|||||||
self.scan = GatherWebTargets(
|
self.scan = GatherWebTargets(
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
)
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|||||||
@@ -12,14 +12,16 @@ class TestGatherWebTargets:
|
|||||||
self.scan = WaybackurlsScan(
|
self.scan = WaybackurlsScan(
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
)
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|
||||||
def test_scan_requires(self):
|
def test_scan_requires(self):
|
||||||
with patch("pipeline.recon.web.GatherWebTargets"):
|
with patch("pipeline.recon.web.GatherWebTargets"):
|
||||||
retval = self.scan.requires()
|
with patch("pipeline.recon.web.waybackurls.meets_requirements"):
|
||||||
assert isinstance(retval, GatherWebTargets)
|
retval = self.scan.requires()
|
||||||
|
assert isinstance(retval, GatherWebTargets)
|
||||||
|
|
||||||
def test_scan_creates_database(self):
|
def test_scan_creates_database(self):
|
||||||
assert self.scan.db_mgr.location.exists()
|
assert self.scan.db_mgr.location.exists()
|
||||||
|
|||||||
@@ -16,14 +16,16 @@ class TestWebanalyzeScan:
|
|||||||
self.scan = WebanalyzeScan(
|
self.scan = WebanalyzeScan(
|
||||||
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
target_file=__file__, results_dir=str(self.tmp_path), db_location=str(self.tmp_path / "testing.sqlite")
|
||||||
)
|
)
|
||||||
|
self.scan.exception = False
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
shutil.rmtree(self.tmp_path)
|
shutil.rmtree(self.tmp_path)
|
||||||
|
|
||||||
def test_scan_requires(self):
|
def test_scan_requires(self):
|
||||||
with patch("pipeline.recon.web.GatherWebTargets"):
|
with patch("pipeline.recon.web.GatherWebTargets"):
|
||||||
retval = self.scan.requires()
|
with patch("pipeline.recon.web.webanalyze.meets_requirements"):
|
||||||
assert isinstance(retval, GatherWebTargets)
|
retval = self.scan.requires()
|
||||||
|
assert isinstance(retval, GatherWebTargets)
|
||||||
|
|
||||||
def test_scan_creates_results_dir(self):
|
def test_scan_creates_results_dir(self):
|
||||||
assert self.scan.results_subfolder == self.tmp_path / "webanalyze-results"
|
assert self.scan.results_subfolder == self.tmp_path / "webanalyze-results"
|
||||||
|
|||||||
Reference in New Issue
Block a user