Modifies reference structure for tool paths (#61)

This commit is contained in:
Ryan Good
2020-05-11 21:07:15 -04:00
committed by GitHub
parent 1448cd037f
commit c8bb606ecc
31 changed files with 115 additions and 242 deletions

View File

@@ -53,19 +53,18 @@ Dynamically creating strings and filesystem paths are handled by the following t
In order to get values out of ``pipeline.recon.config.py``, you'll need to use one of the yaml helpers listed below. In order to get values out of ``pipeline.recon.config.py``, you'll need to use one of the yaml helpers listed below.
- ``!get_parent`` - (niche) get parent directory of a given tool that is defined in the ``pipeline.recon.config.tool_paths`` dictionary
- ``!get_default`` - get a value from the ``pipeline.recon.config.defaults`` dictionary - ``!get_default`` - get a value from the ``pipeline.recon.config.defaults`` dictionary
- ``!get_tool_path`` - get a value from the ``pipeline.recon.config.tool_paths`` dictionary - ``!get_tool_path`` - get a path value from the ``pipeline.tools.tools`` dictionary
Simple Example Tool Definition Simple Example Tool Definition
****************************** ******************************
The example below needs go to be installed prior to being installed itself. It then grabs the path to the ``go`` binary from ``pipeline.recon.config.tool_paths`` by using ``!get_tool_path``. After that, it creates a command using ``!join`` that will look like ``/usr/local/go/bin/go get github.com/tomnomnom/waybackurls``. This command will be run by the ``install waybackurls`` command (or ``install all``). The example below needs go to be installed prior to being installed itself. It then grabs the path to the ``go`` binary from ``pipeline.tools.tools`` by using ``!get_tool_path``. After that, it creates a command using ``!join`` that will look like ``/usr/local/go/bin/go get github.com/tomnomnom/waybackurls``. This command will be run by the ``install waybackurls`` command (or ``install all``).
.. code-block:: yaml .. code-block:: yaml
dependencies: [go] dependencies: [go]
go: &gobin !get_tool_path "{go}" go: &gobin !get_tool_path "{go[path]}"
commands: commands:
- !join [*gobin, get github.com/tomnomnom/waybackurls] - !join [*gobin, get github.com/tomnomnom/waybackurls]

View File

@@ -341,13 +341,11 @@ class ReconShell(cmd2.Cmd):
self.do_install(tool) self.do_install(tool)
return return
if persistent_tool_dict.exists(): if persistent_tool_dict.exists():
tools = pickle.loads(persistent_tool_dict.read_bytes()) tools = pickle.loads(persistent_tool_dict.read_bytes())
if tools.get(args.tool).get("dependencies"): if tools.get(args.tool).get("dependencies"):
# get all of the requested tools dependencies # get all of the requested tools dependencies
for dependency in tools.get(args.tool).get("dependencies"): for dependency in tools.get(args.tool).get("dependencies"):
if tools.get(dependency).get("installed"): if tools.get(dependency).get("installed"):
# already installed, skip it # already installed, skip it

View File

@@ -4,7 +4,7 @@ from .wrappers import FullScan, HTBScan
from .amass import AmassScan, ParseAmassOutput from .amass import AmassScan, ParseAmassOutput
from .masscan import MasscanScan, ParseMasscanOutput from .masscan import MasscanScan, ParseMasscanOutput
from .nmap import ThreadedNmapScan, SearchsploitScan from .nmap import ThreadedNmapScan, SearchsploitScan
from .config import tool_paths, top_udp_ports, top_tcp_ports, defaults, web_ports from .config import top_udp_ports, top_tcp_ports, defaults, web_ports
from .parsers import ( from .parsers import (
install_parser, install_parser,
scan_parser, scan_parser,

View File

@@ -7,8 +7,8 @@ from luigi.util import inherits
from luigi.contrib.sqla import SQLAlchemyTarget from luigi.contrib.sqla import SQLAlchemyTarget
import pipeline.models.db_manager import pipeline.models.db_manager
from .config import tool_paths
from .targets import TargetList from .targets import TargetList
from ..tools import tools
from ..models.target_model import Target from ..models.target_model import Target
@@ -94,7 +94,7 @@ class AmassScan(luigi.Task):
return subprocess.run(f"touch {self.output().path}".split()) return subprocess.run(f"touch {self.output().path}".split())
command = [ command = [
f"{tool_paths.get('amass')}", tools.get("amass").get("path"),
"enum", "enum",
"-active", "-active",
"-ip", "-ip",

View File

@@ -16,25 +16,7 @@ defaults = {
defaults["tools-dir"] = f"{defaults.get('home')}/.local/recon-pipeline/tools" defaults["tools-dir"] = f"{defaults.get('home')}/.local/recon-pipeline/tools"
defaults["database-dir"] = f"{defaults.get('home')}/.local/recon-pipeline/databases" defaults["database-dir"] = f"{defaults.get('home')}/.local/recon-pipeline/databases"
defaults["gobuster-wordlist"] = f"{defaults.get('tools-dir')}/seclists/Discovery/Web-Content/common.txt" defaults["gobuster-wordlist"] = f"{defaults.get('tools-dir')}/seclists/Discovery/Web-Content/common.txt"
defaults["project-dir"] = str(Path(__file__).parents[2])
tool_paths = {
"aquatone": f"{defaults.get('tools-dir')}/aquatone",
"tko-subs": f"{Path.home()}/go/bin/tko-subs",
"tko-subs-dir": f"{Path.home()}/go/src/github.com/anshumanbh/tko-subs",
"subjack": f"{Path.home()}/go/bin/subjack",
"subjack-fingerprints": f"{Path.home()}/go/src/github.com/haccer/subjack/fingerprints.json",
"gobuster": f"{Path.home()}/go/bin/gobuster",
"recursive-gobuster": f"{defaults.get('tools-dir')}/recursive-gobuster/recursive-gobuster.pyz",
"webanalyze": f"{Path.home()}/go/bin/webanalyze",
"masscan": f"{defaults.get('tools-dir')}/masscan",
"amass": f"{defaults.get('tools-dir')}/amass",
"go": "/usr/local/go/bin/go",
"searchsploit": f"{defaults.get('tools-dir')}/exploitdb/searchsploit",
"luigid": str(Path(__file__).parents[2] / "luigid.service"),
"seclists": f"{defaults.get('tools-dir')}/seclists",
"exploitdb": f"{defaults.get('tools-dir')}/exploitdb",
"waybackurls": f"{Path.home()}/go/bin/waybackurls",
}
web_ports = { web_ports = {
"80", "80",

View File

@@ -9,11 +9,12 @@ from luigi.contrib.sqla import SQLAlchemyTarget
import pipeline.models.db_manager import pipeline.models.db_manager
from .targets import TargetList from .targets import TargetList
from ..tools import tools
from .amass import ParseAmassOutput 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 .config import top_tcp_ports, top_udp_ports, defaults, tool_paths, web_ports from .config import top_tcp_ports, top_udp_ports, defaults, web_ports
@inherits(TargetList, ParseAmassOutput) @inherits(TargetList, ParseAmassOutput)
@@ -108,7 +109,7 @@ class MasscanScan(luigi.Task):
) )
command = [ command = [
tool_paths.get("masscan"), tools.get("masscan").get("path"),
"-v", "-v",
"--open", "--open",
"--banners", "--banners",

View File

@@ -12,9 +12,10 @@ 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, tool_paths from .config import defaults
from .helpers import get_ip_address_version, is_ip_address from .helpers import get_ip_address_version, is_ip_address
from ..tools import tools
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
@@ -281,7 +282,7 @@ class SearchsploitScan(luigi.Task):
""" Grabs the xml files created by ThreadedNmap and runs searchsploit --nmap on each one, saving the output. """ """ Grabs the xml files created by ThreadedNmap and runs searchsploit --nmap on each one, saving the output. """
for entry in Path(self.input().get("localtarget").path).glob("nmap*.xml"): for entry in Path(self.input().get("localtarget").path).glob("nmap*.xml"):
proc = subprocess.run( proc = subprocess.run(
[tool_paths.get("searchsploit"), "-j", "-v", "--nmap", str(entry)], stdout=subprocess.PIPE [tools.get("searchsploit").get("path"), "-j", "-v", "--nmap", str(entry)], stdout=subprocess.PIPE
) )
if proc.stdout: if proc.stdout:
# change wall-searchsploit-results/nmap.10.10.10.157-tcp to 10.10.10.157 # change wall-searchsploit-results/nmap.10.10.10.157-tcp to 10.10.10.157

View File

@@ -9,7 +9,8 @@ from luigi.util import inherits
from luigi.contrib.sqla import SQLAlchemyTarget from luigi.contrib.sqla import SQLAlchemyTarget
from .targets import GatherWebTargets from .targets import GatherWebTargets
from ..config import tool_paths, defaults from ..config import defaults
from ...tools import tools
import pipeline.models.db_manager import pipeline.models.db_manager
from ...models.port_model import Port from ...models.port_model import Port
@@ -250,7 +251,7 @@ class AquatoneScan(luigi.Task):
self.results_subfolder.mkdir(parents=True, exist_ok=True) self.results_subfolder.mkdir(parents=True, exist_ok=True)
command = [ command = [
tool_paths.get("aquatone"), tools.get("aquatone").get("path"),
"-scan-timeout", "-scan-timeout",
self.scan_timeout, self.scan_timeout,
"-threads", "-threads",

View File

@@ -11,7 +11,8 @@ from luigi.contrib.sqla import SQLAlchemyTarget
import pipeline.models.db_manager import pipeline.models.db_manager
from .targets import GatherWebTargets from .targets import GatherWebTargets
from ..config import tool_paths, defaults from ..config import defaults
from ...tools import tools
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
@@ -139,10 +140,16 @@ class GobusterScan(luigi.Task):
for url_scheme in ("https://", "http://"): for url_scheme in ("https://", "http://"):
if self.recursive: if self.recursive:
command = [tool_paths.get("recursive-gobuster"), "-s", "-w", self.wordlist, f"{url_scheme}{target}"] command = [
tools.get("recursive-gobuster").get("path"),
"-s",
"-w",
self.wordlist,
f"{url_scheme}{target}",
]
else: else:
command = [ command = [
tool_paths.get("gobuster"), tools.get("gobuster").get("path"),
"dir", "dir",
"-q", "-q",
"-e", "-e",

View File

@@ -8,8 +8,9 @@ from luigi.util import inherits
from luigi.contrib.sqla import SQLAlchemyTarget from luigi.contrib.sqla import SQLAlchemyTarget
import pipeline.models.db_manager import pipeline.models.db_manager
from ...tools import tools
from .targets import GatherWebTargets from .targets import GatherWebTargets
from ..config import tool_paths, defaults from ..config import defaults
@inherits(GatherWebTargets) @inherits(GatherWebTargets)
@@ -120,9 +121,9 @@ class TKOSubsScan(luigi.Task):
return return
command = [ command = [
tool_paths.get("tko-subs"), tools.get("tko-subs").get("path"),
f"-domain={','.join(domains)}", f"-domain={','.join(domains)}",
f"-data={tool_paths.get('tko-subs-dir')}/providers-data.csv", f"-data={tools.get('tko-subs').get('git_dir')}/providers-data.csv",
f"-output={self.output_file}", f"-output={self.output_file}",
] ]
@@ -261,7 +262,7 @@ class SubjackScan(luigi.Task):
f.write(f"{hostname}\n") f.write(f"{hostname}\n")
command = [ command = [
tool_paths.get("subjack"), tools.get("subjack").get("path"),
"-w", "-w",
str(subjack_input_file), str(subjack_input_file),
"-t", "-t",
@@ -274,7 +275,7 @@ class SubjackScan(luigi.Task):
"-v", "-v",
"-ssl", "-ssl",
"-c", "-c",
tool_paths.get("subjack-fingerprints"), tools.get("subjack").get("fingerprints"),
] ]
subprocess.run(command) subprocess.run(command)

View File

@@ -11,8 +11,9 @@ from luigi.util import inherits
from luigi.contrib.sqla import SQLAlchemyTarget from luigi.contrib.sqla import SQLAlchemyTarget
import pipeline.models.db_manager import pipeline.models.db_manager
from ...tools import tools
from .targets import GatherWebTargets from .targets import GatherWebTargets
from ..config import tool_paths, defaults from ..config import defaults
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
@@ -153,7 +154,7 @@ class WebanalyzeScan(luigi.Task):
target = f"[{target}]" target = f"[{target}]"
for url_scheme in ("https://", "http://"): for url_scheme in ("https://", "http://"):
command = [tool_paths.get("webanalyze"), "-host", f"{url_scheme}{target}", "-output", "csv"] command = [tools.get("webanalyze").get("path"), "-host", f"{url_scheme}{target}", "-output", "csv"]
commands.append(command) commands.append(command)
self.results_subfolder.mkdir(parents=True, exist_ok=True) self.results_subfolder.mkdir(parents=True, exist_ok=True)
@@ -162,7 +163,7 @@ class WebanalyzeScan(luigi.Task):
os.chdir(self.results_subfolder) os.chdir(self.results_subfolder)
if not Path("apps.json").exists(): if not Path("apps.json").exists():
subprocess.run(f"{tool_paths.get('webanalyze')} -update".split()) subprocess.run(f"{tools.get('webanalyze').get('path')} -update".split())
with ThreadPoolExecutor(max_workers=self.threads) as executor: with ThreadPoolExecutor(max_workers=self.threads) as executor:
executor.map(self._wrapped_subprocess, commands) executor.map(self._wrapped_subprocess, commands)

View File

@@ -1,10 +1,11 @@
installed: false installed: false
dependencies: [go] dependencies: [go]
go: &gotool !get_tool_path "{go}" tools: &tools !get_default "{tools-dir}"
amass: &amass !get_tool_path "{amass}" go: &gotool !get_tool_path "{go[path]}"
path: &amass !join_path [*tools, "amass"]
commands: commands:
- !join [*gotool, get -u github.com/OWASP/Amass/v3/...] - !join [*gotool, get github.com/OWASP/Amass/v3/...]
- !join [cp ~/go/bin/amass, *amass] - !join [cp ~/go/bin/amass, *amass]
shell: true shell: true

View File

@@ -1,6 +1,6 @@
installed: false installed: false
dependencies: tools: &tools !get_default "{tools-dir}"
aquatone: &aqua !get_tool_path "{aquatone}" path: &aqua !join_path [*tools, aquatone]
commands: commands:
- mkdir /tmp/aquatone - mkdir /tmp/aquatone
@@ -10,5 +10,3 @@ commands:
- !join [mv /tmp/aquatone/aquatone, *aqua] - !join [mv /tmp/aquatone/aquatone, *aqua]
- rm -rf /tmp/aquatone - rm -rf /tmp/aquatone
- bash -c 'found=false; for loc in {/usr/bin/google-chrome,/usr/bin/google-chrome-beta,/usr/bin/google-chrome-unstable,/usr/bin/chromium-browser,/usr/bin/chromium}; do if [[ $(which $loc) ]]; then found=true; break; fi ; done; if [[ $found = false ]]; then sudo apt install -y chromium-browser ; fi' - bash -c 'found=false; for loc in {/usr/bin/google-chrome,/usr/bin/google-chrome-beta,/usr/bin/google-chrome-unstable,/usr/bin/chromium-browser,/usr/bin/chromium}; do if [[ $(which $loc) ]]; then found=true; break; fi ; done; if [[ $found = false ]]; then sudo apt install -y chromium-browser ; fi'
shell: true

View File

@@ -0,0 +1,3 @@
installed: true
tools: &tools !get_default "{tools-dir}"
path: !join_path [*tools, exploitdb]

View File

@@ -1,12 +1,9 @@
installed: false installed: false
dependencies:
home: &home !get_default "{home}" home: &home !get_default "{home}"
go: &gotool !get_tool_path "{go}" path: &gotool /usr/local/go/bin/go
bashrc: &bashrc !join_path [*home, "/.bashrc;"] bashrc: &bashrc !join_path [*home, "/.bashrc;"]
commands: commands:
- wget -q https://dl.google.com/go/go1.13.7.linux-amd64.tar.gz -O /tmp/go.tar.gz - wget -q https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz -O /tmp/go.tar.gz
- sudo tar -C /usr/local -xvf /tmp/go.tar.gz - sudo tar -C /usr/local -xvf /tmp/go.tar.gz
- !join ["bash -c 'if [ ! $(echo ${PATH} | grep $(dirname", *gotool, ")) ]; then echo PATH=${PATH}:/usr/local/go/bin >>", *bashrc, "fi'"] - !join ["bash -c 'if [ ! $(echo ${PATH} | grep $(dirname", *gotool, ")) ]; then echo PATH=${PATH}:/usr/local/go/bin >>", *bashrc, "fi'"]
shell: true

View File

@@ -1,7 +1,8 @@
installed: false installed: false
dependencies: [go, seclists] dependencies: [go, seclists]
home: &home !get_default "{home}" home: &home !get_default "{home}"
go: &gotool !get_tool_path "{go}" path: !join_path [*home, go/bin/gobuster]
go: &gotool !get_tool_path "{go[path]}"
go_home: &gohome !join_path [*home, "/go/src/github.com/OJ/gobuster &&"] go_home: &gohome !join_path [*home, "/go/src/github.com/OJ/gobuster &&"]
commands: commands:

View File

@@ -1,9 +1,10 @@
import yaml import yaml
from pathlib import Path from pathlib import Path
from ..recon.config import tool_paths, defaults from ..recon.config import defaults
definitions = Path(__file__).parent definitions = Path(__file__).parent
tools = {}
def join(loader, node): def join(loader, node):
@@ -30,16 +31,10 @@ def get_default(loader, node):
return py_str.format(**defaults) return py_str.format(**defaults)
def get_parent(loader, node):
""" yaml tag handler to access tool parents """
py_str = loader.construct_python_str(node)
return Path(py_str.format(**tool_paths)).parent
def get_tool_path(loader, node): def get_tool_path(loader, node):
""" yaml tag handler to access tool_paths dict at load time """ """ yaml tag handler to access tools dict at load time """
py_str = loader.construct_python_str(node) py_str = loader.construct_python_str(node)
return py_str.format(**tool_paths) return py_str.format(**tools)
yaml.add_constructor("!join", join) yaml.add_constructor("!join", join)
@@ -47,12 +42,20 @@ yaml.add_constructor("!join_empty", join_empty)
yaml.add_constructor("!join_path", join_path) yaml.add_constructor("!join_path", join_path)
yaml.add_constructor("!get_default", get_default) yaml.add_constructor("!get_default", get_default)
yaml.add_constructor("!get_tool_path", get_tool_path) yaml.add_constructor("!get_tool_path", get_tool_path)
yaml.add_constructor("!get_parent", get_parent)
tools = {} def load_yaml(file):
for file in definitions.iterdir(): try:
if file.name.endswith(".yaml"):
config = yaml.full_load(file.read_text()) config = yaml.full_load(file.read_text())
tool_name = str(file.name.replace(".yaml", "")) tool_name = str(file.name.replace(".yaml", ""))
tools[tool_name] = config tools[tool_name] = config
except KeyError as error: # load dependencies first
dependency = error.args[0]
dependency_file = definitions / (dependency + ".yaml")
load_yaml(dependency_file)
load_yaml(file)
for file in definitions.iterdir():
if file.name.endswith(".yaml") and file.name.replace(".yaml", "") not in tools:
load_yaml(file)

View File

@@ -1,6 +1,6 @@
installed: false installed: false
dependencies: project-dir: &proj !get_default "{project-dir}"
service-file: &svcfile !get_tool_path "{luigid}" service-file: &svcfile !join_path [*proj, luigid.service]
commands: commands:
- !join [sudo cp, *svcfile, /lib/systemd/system/luigid.service] - !join [sudo cp, *svcfile, /lib/systemd/system/luigid.service]

View File

@@ -1,6 +1,6 @@
installed: false installed: false
dependencies: tools: &tools !get_default "{tools-dir}"
masscan: &masscan !get_tool_path "{masscan}" path: &masscan !join_path [*tools, masscan]
commands: commands:
- git clone https://github.com/robertdavidgraham/masscan /tmp/masscan - git clone https://github.com/robertdavidgraham/masscan /tmp/masscan
@@ -8,5 +8,3 @@ commands:
- !join [mv /tmp/masscan/bin/masscan, *masscan] - !join [mv /tmp/masscan/bin/masscan, *masscan]
- rm -rf /tmp/masscan - rm -rf /tmp/masscan
- !join [sudo setcap CAP_NET_RAW+ep, *masscan] - !join [sudo setcap CAP_NET_RAW+ep, *masscan]
shell: true

View File

@@ -1,10 +1,10 @@
installed: false installed: false
dependencies: [go] dependencies: [go]
recursive-parent: &recpar !get_parent "{recursive-gobuster}" tools: &tools !get_default "{tools-dir}"
path: !join_path [*tools, recursive-gobuster/recursive-gobuster.pyz]
recursive-parent: &recpar !join_path [*tools, recursive-gobuster]
commands: commands:
- !join ["bash -c 'if [ -d", *recpar, "]; then cd", *recpar, - !join ["bash -c 'if [ -d", *recpar, "]; then cd", *recpar,
"&& git fetch --all && git pull; else git clone https://github.com/epi052/recursive-gobuster.git", "&& git fetch --all && git pull; else git clone https://github.com/epi052/recursive-gobuster.git",
*recpar, ; fi'] *recpar, ; fi']
shell: true

View File

@@ -1,9 +1,9 @@
installed: false installed: false
dependencies: dependencies: [exploitdb]
home: &home !get_default "{home}" home: &home !get_default "{home}"
tools-dir: &tools !get_default "{tools-dir}" tools: &tools !get_default "{tools-dir}"
exploitdb-file: &exploitdb !get_tool_path "{exploitdb}" exploitdb-file: &exploitdb !get_tool_path "{exploitdb[path]}"
searchsploit-file: &searchsploit !get_tool_path "{searchsploit}" path: &searchsploit !join_path [*tools, exploitdb/searchsploit]
searchsploit-rc: &ss_rc !join_path [*exploitdb, ".searchsploit_rc"] searchsploit-rc: &ss_rc !join_path [*exploitdb, ".searchsploit_rc"]
homesploit: &homesploit !join_path [*home, ".searchsploit_rc"] homesploit: &homesploit !join_path [*home, ".searchsploit_rc"]
sed-command: &sedcom !join_empty ["'s#/opt#", *tools, "#g'"] sed-command: &sedcom !join_empty ["'s#/opt#", *tools, "#g'"]
@@ -15,5 +15,3 @@ commands:
"&& git fetch --all && git pull; else git clone https://github.com/offensive-security/exploitdb.git", *exploitdb, ; fi'] "&& git fetch --all && git pull; else git clone https://github.com/offensive-security/exploitdb.git", *exploitdb, ; fi']
- !join ["bash -c 'if [ -f", *ss_rc, "]; then cp -n", *ss_rc, *home, ; fi'] - !join ["bash -c 'if [ -f", *ss_rc, "]; then cp -n", *ss_rc, *home, ; fi']
- !join ["bash -c 'if [ -f", *homesploit, "]; then sed -i", *sedcom, *homesploit, ; fi'] - !join ["bash -c 'if [ -f", *homesploit, "]; then sed -i", *sedcom, *homesploit, ; fi']
shell: true

View File

@@ -1,10 +1,8 @@
installed: false installed: false
depencencies: tools: &tools !get_default "{tools-dir}"
seclists-file: &secfile !get_tool_path "{seclists}" path: &secfile !join_path [*tools, seclists]
commands: commands:
- !join ["bash -c 'if [[ -d /usr/share/seclists ]]; then ln -s /usr/share/seclists", - !join ["bash -c 'if [[ -d /usr/share/seclists ]]; then ln -s /usr/share/seclists",
*secfile, "; elif [[ -d", *secfile, "]] ; then cd", *secfile, "&& git fetch --all && git pull;", *secfile, "; elif [[ -d", *secfile, "]] ; then cd", *secfile, "&& git fetch --all && git pull;",
else git clone https://github.com/danielmiessler/SecLists.git, *secfile, ; fi'] else git clone https://github.com/danielmiessler/SecLists.git, *secfile, ; fi']
shell: true

View File

@@ -1,8 +1,10 @@
installed: false installed: false
dependencies: [go] dependencies: [go]
go: &gotool !get_tool_path "{go}" go: &gotool !get_tool_path "{go[path]}"
home: &home !get_default "{home}" home: &home !get_default "{home}"
path: !join_path [*home, go/bin/subjack]
subjack_home: &subjhome !join_path [*home, "/go/src/github.com/haccer/subjack &&"] subjack_home: &subjhome !join_path [*home, "/go/src/github.com/haccer/subjack &&"]
fingerprints: !join_path [*home, go/src/github.com/haccer/subjack/fingerprints.json]
commands: commands:
- !join [*gotool, get github.com/haccer/subjack] - !join [*gotool, get github.com/haccer/subjack]

View File

@@ -1,8 +1,10 @@
installed: false installed: false
dependencies: [go] dependencies: [go]
go: &gotool !get_tool_path "{go}" go: &gotool !get_tool_path "{go[path]}"
home: &home !get_default "{home}" home: &home !get_default "{home}"
path: !join_path [*home, go/bin/tko-subs]
tko_home: &tkohome !join_path [*home, "go/src/github.com/anshumanbh/tko-subs &&"] tko_home: &tkohome !join_path [*home, "go/src/github.com/anshumanbh/tko-subs &&"]
git_dir: !join_path [*home, go/src/github.com/anshumanbh/tko-subs]
commands: commands:
- !join [*gotool, get, github.com/anshumanbh/tko-subs] - !join [*gotool, get, github.com/anshumanbh/tko-subs]

View File

@@ -1,9 +1,7 @@
installed: false installed: false
dependencies: ["go"] dependencies: [go]
go: &gotool !get_tool_path "{go}" go: &gotool !get_tool_path "{go[path]}"
path: !join_path [!get_default "{home}", go, bin, waybackurls] path: !join_path [!get_default "{home}", go, bin, waybackurls]
commands: commands:
- !join [*gotool, get, github.com/tomnomnom/waybackurls] - !join [*gotool, get, github.com/tomnomnom/waybackurls]
shell: false

View File

@@ -1,7 +1,8 @@
installed: false installed: false
dependencies: [go] dependencies: [go]
home: &home !get_default "{home}" home: &home !get_default "{home}"
go: &gotool !get_tool_path "{go}" go: &gotool !get_tool_path "{go[path]}"
path: !join_path [*home, go/bin/webanalyze]
webanalyze_home: &webhome !join_path [*home, "/go/src/github.com/rverton/webanalyze &&"] webanalyze_home: &webhome !join_path [*home, "/go/src/github.com/rverton/webanalyze &&"]
commands: commands:

View File

@@ -2,12 +2,14 @@ from pathlib import Path
import pytest import pytest
from pipeline.recon import tool_paths, defaults, web_ports, top_tcp_ports, top_udp_ports from pipeline.recon import defaults, web_ports, top_tcp_ports, top_udp_ports
from pipeline.tools import tools
def test_tool_paths_absolute(): def test_tool_paths_absolute():
for path in tool_paths.values(): for tool in tools.values():
assert Path(path).is_absolute() if tool.get("path"):
assert Path(tool["path"]).is_absolute()
@pytest.mark.parametrize("test_input", ["database-dir", "tools-dir", "gobuster-wordlist"]) @pytest.mark.parametrize("test_input", ["database-dir", "tools-dir", "gobuster-wordlist"])

View File

@@ -7,7 +7,8 @@ import luigi
import pytest import pytest
from luigi.contrib.sqla import SQLAlchemyTarget from luigi.contrib.sqla import SQLAlchemyTarget
from pipeline.recon import ThreadedNmapScan, SearchsploitScan, ParseMasscanOutput, config from pipeline.recon import ThreadedNmapScan, SearchsploitScan, ParseMasscanOutput
from pipeline.tools import tools
nmap_results = Path(__file__).parent.parent / "data" / "recon-results" / "nmap-results" nmap_results = Path(__file__).parent.parent / "data" / "recon-results" / "nmap-results"
@@ -101,7 +102,7 @@ class TestSearchsploitScan:
assert len(self.scan.db_mgr.get_all_searchsploit_results()) == 0 assert len(self.scan.db_mgr.get_all_searchsploit_results()) == 0
if not Path(config.tool_paths.get("searchsploit")).exists(): if not Path(tools.get("searchsploit").get("path")).exists():
pytest.skip("exploit-db's searchsploit tool not installed") pytest.skip("exploit-db's searchsploit tool not installed")
self.scan.run() self.scan.run()

View File

@@ -12,7 +12,8 @@ import pytest
from pipeline.models.port_model import Port from pipeline.models.port_model import Port
from pipeline.models.target_model import Target from pipeline.models.target_model import Target
from pipeline.models.db_manager import DBManager from pipeline.models.db_manager import DBManager
from pipeline.recon.config import defaults, tool_paths from pipeline.tools import tools
from pipeline.recon.config import defaults
from pipeline.models.ip_address_model import IPAddress from pipeline.models.ip_address_model import IPAddress
recon_shell = importlib.import_module("pipeline.recon-pipeline") recon_shell = importlib.import_module("pipeline.recon-pipeline")
@@ -294,143 +295,21 @@ class TestReconShell:
# ("all", "commands failed and may have not installed properly", 1) # ("all", "commands failed and may have not installed properly", 1)
# after tools moved to DB, update this test # after tools moved to DB, update this test
@pytest.mark.parametrize("test_input, expected, return_code", [("all", "is already installed", 0)]) @pytest.mark.parametrize(
"test_input, expected, return_code", [("all", "is already installed", 0), ("amass", "dependency", 1)]
)
def test_do_install(self, test_input, expected, return_code, capsys, tmp_path): def test_do_install(self, test_input, expected, return_code, capsys, tmp_path):
process_mock = MagicMock() process_mock = MagicMock()
attrs = {"communicate.return_value": (b"output", b"error"), "returncode": return_code} attrs = {"communicate.return_value": (b"output", b"error"), "returncode": return_code}
process_mock.configure_mock(**attrs) process_mock.configure_mock(**attrs)
tool_dict = {
"luigi-service": {
"installed": False,
"dependencies": None,
"commands": [
f"sudo cp {str(Path(__file__).parents[2] / 'luigid.service')} /lib/systemd/system/luigid.service",
f"sudo cp $(which luigid) /usr/local/bin",
"sudo systemctl daemon-reload",
"sudo systemctl start luigid.service",
"sudo systemctl enable luigid.service",
],
"shell": True,
},
"seclists": {
"installed": False,
"dependencies": None,
"shell": True,
"commands": [
f"bash -c 'if [[ -d /usr/share/seclists ]]; then ln -s /usr/share/seclists {defaults.get('tools-dir')}/seclists; elif [[ -d {defaults.get('tools-dir')}/seclists ]] ; then cd {defaults.get('tools-dir')}/seclists && git fetch --all && git pull; else git clone https://github.com/danielmiessler/SecLists.git {defaults.get('tools-dir')}/seclists; fi'"
],
},
"searchsploit": {
"installed": False,
"dependencies": None,
"shell": True,
"commands": [
f"bash -c 'if [[ -d /usr/share/exploitdb ]]; then ln -s /usr/share/exploitdb {defaults.get('tools-dir')}/exploitdb && sudo ln -s $(which searchsploit) {defaults.get('tools-dir')}/exploitdb/searchsploit; elif [[ -d {Path(tool_paths.get('searchsploit')).parent} ]]; then cd {Path(tool_paths.get('searchsploit')).parent} && git fetch --all && git pull; else git clone https://github.com/offensive-security/exploitdb.git {defaults.get('tools-dir')}/exploitdb; fi'",
f"bash -c 'if [[ -f {Path(tool_paths.get('searchsploit')).parent}/.searchsploit_rc ]]; then cp -n {Path(tool_paths.get('searchsploit')).parent}/.searchsploit_rc {Path.home().expanduser().resolve()}; fi'",
f"bash -c 'if [[ -f {Path.home().resolve()}/.searchsploit_rc ]]; then sed -i 's#/opt#{defaults.get('tools-dir')}#g' {Path.home().resolve()}/.searchsploit_rc; fi'",
],
},
"masscan": {
"installed": False,
"dependencies": None,
"commands": [
"git clone https://github.com/robertdavidgraham/masscan /tmp/masscan",
"make -s -j -C /tmp/masscan",
f"mv /tmp/masscan/bin/masscan {tool_paths.get('masscan')}",
"rm -rf /tmp/masscan",
f"sudo setcap CAP_NET_RAW+ep {tool_paths.get('masscan')}",
],
},
"amass": {
"installed": False,
"dependencies": ["go"],
"commands": [
f"{tool_paths.get('go')} get -u github.com/OWASP/Amass/v3/...",
f"cp ~/go/bin/amass {tool_paths.get('amass')}",
],
"shell": True,
"environ": {"GO111MODULE": "on"},
},
"aquatone": {
"installed": False,
"dependencies": None,
"shell": True,
"commands": [
"mkdir /tmp/aquatone",
"wget -q https://github.com/michenriksen/aquatone/releases/download/v1.7.0/aquatone_linux_amd64_1.7.0.zip -O /tmp/aquatone/aquatone.zip",
"bash -c 'if [[ ! $(which unzip) ]]; then sudo apt install -y zip; fi'",
"unzip /tmp/aquatone/aquatone.zip -d /tmp/aquatone",
f"mv /tmp/aquatone/aquatone {tool_paths.get('aquatone')}",
"rm -rf /tmp/aquatone",
"bash -c 'found=false; for loc in {/usr/bin/google-chrome,/usr/bin/google-chrome-beta,/usr/bin/google-chrome-unstable,/usr/bin/chromium-browser,/usr/bin/chromium}; do if [[ $(which $loc) ]]; then found=true; break; fi ; done; if [[ $found = false ]]; then sudo apt install -y chromium-browser ; fi'",
],
},
"gobuster": {
"installed": False,
"dependencies": ["go", "seclists"],
"commands": [
f"{tool_paths.get('go')} get github.com/OJ/gobuster",
f"(cd ~/go/src/github.com/OJ/gobuster && {tool_paths.get('go')} build && {tool_paths.get('go')} install)",
],
"shell": True,
},
"tko-subs": {
"installed": False,
"dependencies": ["go"],
"commands": [
f"{tool_paths.get('go')} get github.com/anshumanbh/tko-subs",
f"(cd ~/go/src/github.com/anshumanbh/tko-subs && {tool_paths.get('go')} build && {tool_paths.get('go')} install)",
],
"shell": True,
},
"subjack": {
"installed": False,
"dependencies": ["go"],
"commands": [
f"{tool_paths.get('go')} get github.com/haccer/subjack",
f"(cd ~/go/src/github.com/haccer/subjack && {tool_paths.get('go')} install)",
],
"shell": True,
},
"webanalyze": {
"installed": False,
"dependencies": ["go"],
"commands": [
f"{tool_paths.get('go')} get github.com/rverton/webanalyze/...",
f"(cd ~/go/src/github.com/rverton/webanalyze && {tool_paths.get('go')} build && {tool_paths.get('go')} install)",
],
"shell": True,
},
"recursive-gobuster": {
"installed": False,
"dependencies": ["gobuster", "seclists"],
"shell": True,
"commands": [
f"bash -c 'if [[ -d {Path(tool_paths.get('recursive-gobuster')).parent} ]] ; then cd {Path(tool_paths.get('recursive-gobuster')).parent} && git fetch --all && git pull; else git clone https://github.com/epi052/recursive-gobuster.git {Path(tool_paths.get('recursive-gobuster')).parent}; fi'"
],
},
"go": {
"installed": False,
"dependencies": None,
"commands": [
"wget -q https://dl.google.com/go/go1.13.7.linux-amd64.tar.gz -O /tmp/go.tar.gz",
"sudo tar -C /usr/local -xvf /tmp/go.tar.gz",
f'bash -c \'if [[ ! $(echo "${{PATH}}" | grep $(dirname {tool_paths.get("go")})) ]]; then echo "PATH=${{PATH}}:/usr/local/go/bin" >> ~/.bashrc; fi\'',
],
},
"waybackurls": {
"installed": True,
"depencencies": ["go"],
"commands": ["/usr/local/go/bin/go get github.com/tomnomnom/waybackurls"],
"shell": True,
},
}
tooldir = tmp_path / ".local" / "recon-pipeline" / "tools" tooldir = tmp_path / ".local" / "recon-pipeline" / "tools"
tooldir.mkdir(parents=True, exist_ok=True) tooldir.mkdir(parents=True, exist_ok=True)
pickle.dump(tool_dict, (tooldir / ".tool-dict.pkl").open("wb")) tools["waybackurls"]["installed"] = True
tools["amass"]["shell"] = False
pickle.dump(tools, (tooldir / ".tool-dict.pkl").open("wb"))
with patch("subprocess.Popen", autospec=True) as mocked_popen: with patch("subprocess.Popen", autospec=True) as mocked_popen:
mocked_popen.return_value = process_mock mocked_popen.return_value = process_mock

View File

@@ -4,7 +4,7 @@ import tempfile
from pathlib import Path from pathlib import Path
from unittest.mock import patch, MagicMock from unittest.mock import patch, MagicMock
from pipeline.recon.config import tool_paths from pipeline.tools import tools
from pipeline.recon.web import WebanalyzeScan, GatherWebTargets from pipeline.recon.web import WebanalyzeScan, GatherWebTargets
webanalyze_results = Path(__file__).parent.parent / "data" / "recon-results" / "webanalyze-results" webanalyze_results = Path(__file__).parent.parent / "data" / "recon-results" / "webanalyze-results"
@@ -65,7 +65,7 @@ class TestWebanalyzeScan:
self.scan.results_subfolder.mkdir() self.scan.results_subfolder.mkdir()
os.chdir(self.scan.results_subfolder) os.chdir(self.scan.results_subfolder)
assert len([x for x in self.scan.results_subfolder.iterdir()]) == 0 assert len([x for x in self.scan.results_subfolder.iterdir()]) == 0
cmd = [tool_paths.get("webanalyze"), "-host", "https://google.com", "-output", "csv"] cmd = [tools.get("webanalyze").get("path"), "-host", "https://google.com", "-output", "csv"]
self.scan._wrapped_subprocess(cmd) self.scan._wrapped_subprocess(cmd)
assert len([x for x in self.scan.results_subfolder.iterdir()]) == 1 assert len([x for x in self.scan.results_subfolder.iterdir()]) == 1
assert next(self.scan.results_subfolder.iterdir()).name == "webanalyze-https_google.com.csv" assert next(self.scan.results_subfolder.iterdir()).name == "webanalyze-https_google.com.csv"