Add documentation and some minor improvements

This commit is contained in:
Cag 2019-01-21 17:45:28 +11:00
Родитель 07ce02ddf0
Коммит 7902049b9f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 130B2DC4484808D2
7 изменённых файлов: 115 добавлений и 22 удалений

Просмотреть файл

@ -1,4 +1,4 @@
FROM ruby:latest
FROM ruby
MAINTAINER Cag
# This is to be able to talk to Tenable API

Просмотреть файл

@ -1 +1,85 @@
# vautomator-standalone
Iterative automation of common VA tasks using OOP.
If you'd like to contribute, please reach out to [me](https://mozillians.org/en-US/u/Cag/) and I'd be happy to add you as a contributor.
## Install & Running
1. First, download the repo: `git clone https://github.com/caggle/vautomator-standalone.git && cd vautomator-standalone`
2. Build the Docker image: `docker-compose build vautomator`
3. Run it!: `docker run -v ${PWD}/results:/app/results -it vautomator:latest ./run.py <target>`
Example run:
```
$ docker run -v ${PWD}/results:/app/results -it vautomator:latest ./run.py http://192.168.0.1
[f2769b83b62b] 2019-01-21 06:23:51 AM UTC INFO [+] Running all the scans now. This may take a while...
[f2769b83b62b] 2019-01-21 06:24:23 AM UTC WARNING [!] The target has recently been scanned by Tenable.io, retrieving results...
[f2769b83b62b] 2019-01-21 06:24:30 AM UTC INFO [+] Running nmap port scans...
[f2769b83b62b] 2019-01-21 06:26:54 AM UTC INFO [+] Nmap port scan(s) successfully ran.
[f2769b83b62b] 2019-01-21 06:26:54 AM UTC INFO [+] Running ssh_scan...
[f2769b83b62b] 2019-01-21 06:26:58 AM UTC INFO [+] SSH scan successfully ran.
[f2769b83b62b] 2019-01-21 06:26:58 AM UTC INFO [+] Running TLS Observatory scan...
[f2769b83b62b] 2019-01-21 06:27:19 AM UTC INFO [+] TLS Observatory scan successfully ran.
[f2769b83b62b] 2019-01-21 06:27:19 AM UTC INFO [+] Running dirb scan...
[f2769b83b62b] 2019-01-21 06:31:48 AM UTC INFO [+] Directory brute scan successfully ran.
[f2769b83b62b] 2019-01-21 06:31:49 AM UTC INFO [+] All done. Tool output from the scan can be found at /app/results/192.168.0.1/
====== SCAN SUMMARY ======
INFO [+] [\o/] nmap scan completed successfully!
INFO [+] [\o/] dirbrute scan completed successfully!
INFO [+] [\o/] sshscan scan completed successfully!
INFO [+] [\o/] tlsobs scan completed successfully!
INFO [+] [\o/] nessus scan completed successfully!
WARNING [!] [ :| ] httpobs scan skipped as not applicable to the target.
====== END OF SCAN =======
```
## What it does
Using **Python 3**, it runs a bunch of tools against a URL/FQDN/IPv4 address on a Docker image of its own, and saves tool outputs for later analysis, as a part of a vulnerability assessment.
### What it actually does
* Determines if the the target is a URL, an IPv4 address or a hostname/FQDN
* If URL *(note: it could be a URL with FQDN or IPv4 address)* it will run:
* An nmap UDP scan for about 25 selected UDP services
* An nmap TCP scan for top 1000 services
* ssh_scan (if an SSH service is identified)
* A Nessus (Tenable.io) "Basic Network Scan" (provided if you have valid Tenable.io API keys)
* HTTP Observatory scan
* TLS Observatory scan
* Directory bruteforcing against a wordlist
* If IP address, it will only run:
* An nmap UDP scan for about 25 selected UDP services
* An nmap TCP scan for top 1000 services
* ssh_scan (if an SSH service is identified)
* A Nessus (Tenable.io) "Basic Network Scan" (provided if you have valid Tenable.io API keys)
In the current implementation these tasks are performed sequentially with the intent being "run and forget" for a couple of hours, while you are doing other important work.
#### Port scans
For TCP and UDP port scans, [python-nmap](https://pypi.org/project/python-nmap/) is used.
##### SSH scan
For SSH scan, [ssh_scan](https://github.com/mozilla/ssh_scan) is used.
#### Nessus scan
Nessus scans will fail unless you have a pair of valid Tenable.io API keys *with administrative permissions*. If you do, populate the .env file with them in the below form building the Docker image:
```
TENABLEIO_ACCESS_KEY=<ACCESS_KEY>
TENABLEIO_SECRET_KEY=<SECRET_KEY>
```
#### Web App scans
If you are running the tool against a URL, a number of additional external tools will be utilised. These will be installed in the Docker container when you build it.
* [HTTP Observatory](https://github.com/mozilla/http-observatory) is used as a Python module.
* [TLS Observatory](https://github.com/mozilla/tls-observatory), by means of `tlsobs` client.
* For directory brute-forcing:
* By default, `dirb` will be used with the common wordlist.
* `gobuster` will also be installed in the Docker container, however a command line switch to use it instead is not available yet (you would have to modify the code).

Просмотреть файл

@ -1,6 +1,9 @@
version: '3'
services:
vautomator:
# This does not work for some reason
# sysctls:
# - net.ipv6.conf.all.disable_ipv6=0
build:
context: .
dockerfile: ./Dockerfile
@ -8,4 +11,3 @@ services:
- TENABLEIO_ACCESS_KEY=${TENABLEIO_ACCESS_KEY}
- TENABLEIO_SECRET_KEY=${TENABLEIO_SECRET_KEY}
image: vautomator

Просмотреть файл

@ -6,9 +6,11 @@ from netaddr import valid_ipv4
from urllib.parse import urlparse
from lib import task
# Logging in UTC
logger = logging.getLogger(__name__)
coloredlogs.install(level='INFO', logger=logger, reconfigure=True,
fmt='[%(hostname)s] %(asctime)s %(levelname)-8s %(message)s')
fmt='[%(hostname)s] %(asctime)s %(levelname)-8s %(message)s',
datefmt="%Y-%m-%d %I:%M:%S %p %Z")
class Target:
@ -89,7 +91,8 @@ class Target:
return False
def addTask(self, new_task):
# self.tasklist.append(new_task)
# This is a hacky way pf running ssh_scan
# right after nmap port scan
if isinstance(new_task, task.SSHScanTask):
self.tasklist.insert(2, new_task)
else:
@ -110,6 +113,7 @@ class Target:
elif isinstance(one_task, task.NessusTask):
nessus_results = one_task.runNessusScan()
if (nessus_results):
# TODO: Need to be more precise about this time check
epoch_cdate = nessus_results.histories()[0].creation_date
cdate = datetime.datetime.fromtimestamp(float(epoch_cdate))
if(cdate.date() < datetime.date.today()):

Просмотреть файл

@ -11,9 +11,11 @@ from tenable_io.api.scans import ScanExportRequest
from tenable_io.api.models import Scan
from distutils.spawn import find_executable
# Logging in UTC
logger = logging.getLogger(__name__)
coloredlogs.install(level='INFO', logger=logger, reconfigure=True,
fmt='[%(hostname)s] %(asctime)s %(levelname)-8s %(message)s')
fmt='[%(hostname)s] %(asctime)s %(levelname)-8s %(message)s',
datefmt="%Y-%m-%d %I:%M:%S %p %Z")
class Task:
@ -34,16 +36,16 @@ class NmapTask(Task):
# We need to check if SSH service is available within port scan results
if (port_scan_results["".join(port_scan_results.all_hosts())].has_tcp(22)):
# Port 22/tcp is open, perform ssh_scan scan
# SSHScanTask(self.tasktarget).runSSHScan(22)
self.tasktarget.addTask(SSHScanTask(self.tasktarget, 22))
else:
# Need to find the actual SSH port, in case it is not 22
# Magic happens here...
# Ref: https://bitbucket.org/xael/python-nmap/src/2b493f71a26f63a01c155c073fbf0211a3219ff2/nmap/nmap.py?at=default&fileviewer=file-view-default#nmap.py-436:465
for ssh_port in port_scan_results["".join(port_scan_results.all_hosts())].all_tcp():
if 'script' in port_scan_results["".join(port_scan_results.all_hosts())]['tcp'][ssh_port].keys():
if 'ssh' in "".join(port_scan_results["".join(port_scan_results.all_hosts())]['tcp'][ssh_port]['script'].values()).lower():
# We have SSH service on a non-standard port, perform scan
# SSHScanTask(self.tasktarget).runSSHScan(ssh_port)
self.tasktarget.addTask(SSHScanTask(self.tasktarget, ssh_port))
return
@ -230,7 +232,7 @@ class NessusTask(Task):
logger.error("[-] Tenable.io scan failed: ".format(TIOException))
return False
def downloadReport(self, nscan, reportformat="html", style="vulns"):
def downloadReport(self, nscan, reportformat="html", style="assets"):
report_path = "/app/results/" + self.tasktarget.targetdomain + "/Scan_for_" + self.tasktarget.targetdomain
if reportformat == "html":
@ -246,7 +248,7 @@ class NessusTask(Task):
else:
return False
if style == "vulns":
if style == "assets":
reportoutline = ScanExportRequest.CHAPTER_CUSTOM_VULN_BY_HOST
elif style == "exec":
reportoutline = ScanExportRequest.CHAPTER_EXECUTIVE_SUMMARY
@ -257,9 +259,9 @@ class NessusTask(Task):
nscan.download(report_path, format=fmt, chapter=reportoutline)
def checkScanStatus(self, nscan, scan_history=None):
def checkScanStatus(self, nscan):
# Query Tenable API to check if the scan is finished
status = nscan.status(nscan.id, scan_history)
status = nscan.status(nscan.id)
if status == nscan.STATUS_COMPLETED:
return "COMPLETE"
@ -336,12 +338,12 @@ class DirectoryBruteTask(Task):
logger.info("[+] Running dirb scan...")
if "URL" in self.tasktarget.getType():
cmd = "/app/vendor/dirb222/dirb " + self.tasktarget.targetname \
+ "/ /app/vendor/dirb222/wordlists/common.txt -o /app/results/" \
+ self.tasktarget.targetdomain + "/https_dirb_common.txt -f"
+ "/ /app/vendor/dirb222/wordlists/small.txt -o /app/results/" \
+ self.tasktarget.targetdomain + "/https_dirb_common.txt -f -w -S -r"
else:
cmd = "/app/vendor/dirb222/dirb https://" + self.tasktarget.targetdomain \
+ "/ /app/vendor/dirb222/wordlists/common.txt -o /app/results/" \
+ self.tasktarget.targetdomain + "/https_dirb_common.txt -f"
+ "/ /app/vendor/dirb222/wordlists/small.txt -o /app/results/" \
+ self.tasktarget.targetdomain + "/https_dirb_common.txt -f -w -S -r"
dirbscan_cmd = utils.sanitise_shell_command(cmd)
p = subprocess.Popen(dirbscan_cmd, stdout=subprocess.PIPE, shell=True)

Просмотреть файл

@ -12,8 +12,8 @@ def sanitise_shell_command(command):
def package_results(output_dir):
# Do reporting (take all the output from the prior runs,
# zip it up, and attach to BMO)
# Do reporting (take all the output from
# the prior runs, zip it up
tarfile = output_dir.split('/')
cmd = "tar --warning=no-all -zcf " + output_dir + tarfile[3] + ".tar.gz -C " \
+ output_dir + " . --exclude=" + output_dir + tarfile[3] + ".tar.gz"

11
run.py
Просмотреть файл

@ -8,10 +8,11 @@ import coloredlogs
from urllib.parse import urlparse
from lib import target, task, utils
# Logging in UTC
logger = logging.getLogger(__name__)
# Default logging level is INFO
coloredlogs.install(level='INFO', logger=logger, reconfigure=True,
fmt='[%(hostname)s] %(asctime)s %(levelname)-8s %(message)s')
fmt='[%(hostname)s] %(asctime)s %(levelname)-8s %(message)s',
datefmt="%Y-%m-%d %I:%M:%S %p %Z")
def setupVA(va_target):
@ -33,7 +34,7 @@ def setupVA(va_target):
va_target.addTask(task.DirectoryBruteTask(va_target, tool="dirb"))
else:
va_target.addTask(task.MozillaTLSObservatoryTask(va_target))
# va_target.addTask(task.DirectoryBruteTask(va_target, tool="dirb"))
va_target.addTask(task.DirectoryBruteTask(va_target, tool="dirb"))
# HTTP Observatory does not like IPs as a target, skipping
va_target.resultsdict.update({'httpobs': "PASS"})
elif va_target.getType() == "IPv4":
@ -73,9 +74,10 @@ def runVA(scan_with_tasks, outpath):
results = scan_with_tasks.runTasks()
# results here is a dict
time.sleep(1)
# Return code check is a bit hacky,
# basically we are ignoring warnings from tar
if utils.package_results(outpath).returncode is not 127:
logger.info("[+] All done. Tool output from the scan can be found at " + outpath)
# return results
else:
logger.warning("[!] There was a problem compressing tool output. Check " + outpath + " manually.")
time.sleep(1)
@ -85,7 +87,6 @@ def runVA(scan_with_tasks, outpath):
def main():
results = {'nmap': False, 'nessus': False, 'tlsobs': False, 'httpobs': False, 'sshscan': False, 'dirbrute': False}
# Get targeting info
destination = sys.argv[1]
output_path = "/app/results/" + destination + "/"
va_target = target.Target(destination, results)