dirb multiple hosts wrapper

I've had the need in the past to run dirb (dirbuster like web directory brute force tool) against a range targets. However, dirb only takes a single host as an argument. It would be pretty easy to wrap it in an loop, but you're probably going to waste time on targets that may not be up or have a particular port open. It gets a bit more complicated when you're looking at multiple ports, and even moreso when some are IP's and some are hostnames.

In the end I wrote a quick python script to parse though an nmap greppable output, get a list of open ports/hosts. It grabs the hostname, if one is availible, otherwise it uses the IP. It associates this with the ports that it finds open, builds a list of servers, and then runs dirb against that list.

1) Run an nmap scan against the target environment.

nmap -Pn -p 80,443,8080,8443 --open -oG scan.gnmap 192.168.1.0/24
You can see here I'm running nmap against my home network, treating all hosts as online, looking at 4 specific web ports, only listing open ports, and outputting it in greppable format. You're output should look something like...

# Nmap 7.70 scan initiated Sat Jun 30 17:41:58 2018 as: nmap -Pn -p 80,443,8080,8443 --open -oG scan.gnmap 192.168.1.0/24
Host: 192.168.1.58 (na.nullsec.us)	Status: Up
Host: 192.168.1.58 (na.nullsec.us)	Ports: 443/open/tcp//https///	Ignored State: filtered (3)
Host: 192.168.1.59 (fake.nullsec.us)	Status: Up
Host: 192.168.1.59 (fake.nullsec.us)	Ports: 80/open/tcp//http///	Ignored State: closed (3)
Host: 192.168.1.69 ()	Status: Up
Host: 192.168.1.69 ()	Ports: 80/open/tcp//http///, 443/open/tcp//https///	Ignored State: closed (2)
Host: 192.168.1.70 ()	Status: Up
Host: 192.168.1.70 ()	Ports: 80/open/tcp//http///	Ignored State: closed (3)
# Nmap done at Sat Jun 30 17:42:06 2018 -- 256 IP addresses (4 hosts up) scanned in 8.16 seconds

2) Set some variables in the script

At the top of the script (following in step 3), you'll see a few variables that you should set. List the ports you scanned in either the plaintext or encrypted python lists. I split them like this should I could easily append the appropriate http:// or https:// later. Also set fname, the name of our scan, if you named it something different or placed it in a different location. Lastly, set your wordlist, this is what dirb will use to brute force directories. In this case I'm using a cleaned up version of PHPMyAdmin directories. Make sure you remove the leading slash. Some of you may have also just figured out why I'm interested in running this against a large number of hosts.

3) Run the script

It's a pretty short script. Most of it is just building the list of servers out. After that, it just does an os.system call to dirb with the proper flags. It does grep for the output of found directories, otherwise it gets really noisy.

#!/usr/bin/python3

import socket, os, re

plaintext = [80,8080] # Add your ports here and below, depending on whether you expect them to have TLS (HTTP/HTTPS)
encrypted = [443,8443]
fname = "/root/scan.gnmap" # line delimited file that does not include http:// or :80. e.g. just "some.server.com"
wordlist = "/root/pma-basher.txt" # Directories to test without leading / e.g. just "wp-admin/""

ports = plaintext + encrypted
servers = set()
server = ""

# ---- Uncomment one of the below -----
#user_agent = "\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36\"" # Chrome 67
#user_agent = "\"MMozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0\"" # Firefox 60
user_agent = "\"Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko\"" # IE 11
#user_agent = "\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134\"" # Edge

with open(fname) as f:
	lines = f.readlines()
	for line in lines:
		line = line.strip()
		if "Ports: " in line:
			server_ip = re.split(r'\s|\t',line)[1] 
			server_name = re.split(r'\s|\t',line)[2]
			server_name = server_name.strip("()")
			if len(server_name) == 0:
				server = server_ip
			else:
				server = server_name
			for port in ports:
				if str(str(port) + "/open/") in line:
					if port in plaintext:
						servers.add("http://" + server + ":" + str(port))
					elif port in encrypted:
						servers.add("https://" + server + ":" + str(port))

for server in servers:
	print("----- TESTING " + server + " -----")
	os.system("dirb " + server + " " + wordlist + " -r -a " + user_agent + " | grep DIRECTORY")