diff --git a/recon/config.py b/recon/config.py index a278a65..4d3cec6 100644 --- a/recon/config.py +++ b/recon/config.py @@ -13,5 +13,6 @@ tool_paths = { 'tko-subs': '/root/go/bin/tko-subs', 'tko-subs-dir': '/root/go/src/github.com/anshumanbh/tko-subs', 'subjack': '/root/go/bin/subjack', - 'subjack-fingerprints': '/root/go/src/github.com/haccer/subjack/fingerprints.json' + 'subjack-fingerprints': '/root/go/src/github.com/haccer/subjack/fingerprints.json', + 'CORScanner': '/opt/CORScanner/cors_scan.py', } diff --git a/recon/nmap.py b/recon/nmap.py index 3cc1cfd..abfabe3 100644 --- a/recon/nmap.py +++ b/recon/nmap.py @@ -102,16 +102,12 @@ class ThreadedNmap(luigi.Task): """ for target, protocol_dict in ip_dict.items(): for protocol, ports in protocol_dict.items(): - non_web_ports = ",".join(ports.difference(web_ports)) - - if not non_web_ports: - continue tmp_cmd = nmap_command[:] tmp_cmd[2] = "-sT" if protocol == "tcp" else "-sU" # arg to -oA, will drop into subdir off curdir - tmp_cmd[9] = non_web_ports + tmp_cmd[9] = ",".join(ports) tmp_cmd.append(f"{self.output().path}/nmap.{target}-{protocol}") tmp_cmd.append(target) # target as final arg to nmap @@ -177,7 +173,7 @@ class Searchsploit(luigi.Task): Returns: luigi.local_target.LocalTarget """ - return luigi.LocalTarget(f"{self.target_file}-searchsploit-results") + return luigi.LocalTarget(f"searchsploit-{self.target_file}-results") def run(self): """ Grabs the xml files created by ThreadedNmap and runs searchsploit --nmap on each one, saving the output. """ diff --git a/recon/web/corscanner.py b/recon/web/corscanner.py new file mode 100644 index 0000000..4e35c95 --- /dev/null +++ b/recon/web/corscanner.py @@ -0,0 +1,86 @@ +import luigi +from luigi.util import inherits +from luigi.contrib.external_program import ExternalProgramTask + +from recon.config import tool_paths +from recon.web.targets import GatherWebTargets + + +@inherits(GatherWebTargets) +class CORScannerScan(ExternalProgramTask): + """ Use CORScanner to scan for potential CORS misconfigurations. + + CORScanner commands are structured like the example below. + + python cors_scan.py -i webtargets.tesla.txt -t 100 + + An example of the corresponding luigi command is shown below. + + PYTHONPATH=$(pwd) luigi --local-scheduler --module recon.web.corscanner CORScannerScan --target-file tesla --top-ports 1000 --interface eth0 + + Install: + git clone https://github.com/chenjj/CORScanner.git + cd CORScanner + pip install -r requirements.txt + pip install future + + Args: + threads: number of threads for parallel subjack command execution + exempt_list: Path to a file providing blacklisted subdomains, one per line. *--* Optional for upstream Task + top_ports: Scan top N most popular ports *--* Required by upstream Task + ports: specifies the port(s) to be scanned *--* Required by upstream Task + interface: use the named raw network interface, such as "eth0" *--* Required by upstream Task + rate: desired rate for transmitting packets (packets per second) *--* Required by upstream Task + target_file: specifies the file on disk containing a list of ips or domains *--* Required by upstream Task + """ + + threads = luigi.Parameter(default="10") + + def requires(self): + """ CORScannerScan depends on GatherWebTargets to run. + + GatherWebTargets accepts exempt_list and expects rate, target_file, interface, + and either ports or top_ports as parameters + + Returns: + luigi.Task - GatherWebTargets + """ + args = { + "rate": self.rate, + "target_file": self.target_file, + "top_ports": self.top_ports, + "interface": self.interface, + "ports": self.ports, + "exempt_list": self.exempt_list, + } + return GatherWebTargets(**args) + + def output(self): + """ Returns the target output for this task. + + Naming convention for the output file is corscanner.TARGET_FILE.json. + + Returns: + luigi.local_target.LocalTarget + """ + return luigi.LocalTarget(f"corscanner.{self.target_file}.json") + + def program_args(self): + """ Defines the options/arguments sent to tko-subs after processing. + + Returns: + list: list of options/arguments, beginning with the name of the executable to run + """ + + command = [ + "python3", + tool_paths.get("CORScanner"), + "-i", + self.input().path, + "-t", + self.threads, + "-o", + self.output().path, + ] + + return command diff --git a/recon/wrappers.py b/recon/wrappers.py index 719d1e0..7e4c2f6 100644 --- a/recon/wrappers.py +++ b/recon/wrappers.py @@ -3,9 +3,11 @@ from luigi.util import inherits from recon.nmap import Searchsploit from recon.web.aquatone import AquatoneScan +from recon.web.corscanner import CORScannerScan +from recon.web.subdomain_takeover import TKOSubsScan, SubjackScan -@inherits(Searchsploit, AquatoneScan) +@inherits(Searchsploit, AquatoneScan, TKOSubsScan, SubjackScan, CORScannerScan) class FullScan(luigi.WrapperTask): """ Wraps multiple scan types in order to run tasks on the same hierarchical level at the same time. """ @@ -25,4 +27,10 @@ class FullScan(luigi.WrapperTask): del args["scan_timeout"] + yield SubjackScan(**args) yield Searchsploit(**args) + yield CORScannerScan(**args) + + del args["threads"] + + yield TKOSubsScan(**args)