-
Notifications
You must be signed in to change notification settings - Fork 5
/
mnikto.py
143 lines (126 loc) · 5.25 KB
/
mnikto.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"""
Run nikto save data and create images of the results
USAGE: python mnikto.py <output_dir> --url <url>|--csv <csv>|--txt <txt> [-s <screenshot directory>]
"""
import os
import logging
import argparse
from urllib.parse import urlparse
from utils import utils # noqa
from utils import logging_config # noqa pylint: disable=unused-import
from utils import run_commands
log = logging.getLogger("ptscripts.web_nikto")
NIKTO_COMMAND = "nikto -C all -maxtime 1h -nointeractive "\
"-useragent 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)"\
" Chrome/40.0.2214.85 Safari/537.36' -ask auto -o {output} -host {domain} -port {port}{root}{ssl}"
NIKTO_PROXY_COMMAND = "nikto -C all -maxtime 1h -nointeractive "\
"-useragent 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)"\
" Chrome/40.0.2214.85 Safari/537.36' -ask auto -o {output} -host {domain} -port {port}{root}"\
" -nossl -useproxy http://{proxy}/"
def run_nikto(url_dict, output_dir, proxy, screenshot=False):
html_path = os.path.join(output_dir, f"nikto_{url_dict['domain']}_{url_dict['port']}.html")
csv_path = os.path.join(output_dir, f"nikto_{url_dict['domain']}_{url_dict['port']}.csv")
if proxy:
log.info(f"Using proxy: {proxy}")
command_text = NIKTO_PROXY_COMMAND
else:
command_text = NIKTO_COMMAND
command = command_text.format(domain=url_dict['domain'], port=url_dict['port'],
root=url_dict['root'], ssl=url_dict['ssl'], output=csv_path,
proxy=proxy)
log.info('Running command: {}'.format(command))
text_output = run_commands.bash_command(command)
html_output = run_commands.create_html_file(text_output, command, html_path)
if html_output and screenshot:
log.info("Creating a screenshot of the output and saving it to {}".format(screenshot))
utils.dir_exists(screenshot, True)
utils.selenium_image(html_output, screenshot)
if not html_output:
log.error("Didn't receive a response from running the command.")
def parse_url_nikto(url):
parsed_url = urlparse(url)
netloc = parsed_url.netloc
# if non-standard port break it up.
if ":" in netloc:
domain = netloc.split(":")[0]
port = netloc.split(":")[1]
# otherwise port is based on scheme
else:
domain = netloc
if parsed_url.scheme == 'http':
port = '80'
else:
port = '443'
if parsed_url.scheme == 'https':
ssl = " -ssl"
else:
ssl = ""
if parsed_url.path:
root = " -root " + parsed_url.path
else:
root = ""
return {'domain': domain, 'port': port, 'root': root, 'ssl': ssl}
def main(args):
os.makedirs(args.output, exist_ok=True)
urls = []
# Prepare commands
if args.csv:
log.info('Running nikto against CSV file.')
webservers = utils.parse_csv_for_webservers(args.csv)
for webserver in webservers:
if webserver['service_tunnel'] == 'ssl' or webserver['service_name'] == 'https':
ssl = " -ssl"
else:
ssl = ""
port = webserver['port']
domain = webserver['ipv4']
root = ""
urls.append({'domain': domain, 'port': port, 'root': root, 'ssl': ssl})
elif args.url:
log.info('Running nikto against a single URL.')
parsed_url = parse_url_nikto(args.url)
urls.append(parsed_url)
else:
log.info('Running nikto against a text file of URLs.')
with open(args.txt, 'r') as f:
for line in f:
parsed_url = parse_url_nikto(line.strip())
urls.append(parsed_url)
if args.screenshot:
screenshot = args.screenshot
else:
screenshot = False
url_count = len(urls)
for i, url in enumerate(urls, start=1):
log.info('**** Number {} of {} ****'.format(i, url_count))
run_nikto(url, args.output, args.proxy, screenshot)
def parse_args(args):
parser = argparse.ArgumentParser(
parents=[utils.parent_argparser()],
description='Run nikto against one or many targets.',
)
# Mutually exclusive inputs: csv, url, list of sites.
input_arg = parser.add_mutually_exclusive_group()
input_arg.add_argument('--csv', help='CSV File of open ports.')
input_arg.add_argument('--url', help="Single url to be tested")
input_arg.add_argument('--txt', help='Text file with url per line.')
parser.add_argument('output', help="where to store results")
parser.add_argument("-s", "--screenshot",
help="full path to where the screenshot will be saved.")
parser.add_argument("-p", "--proxy", help="proxy")
args = parser.parse_args(args)
logger = logging.getLogger("ptscripts")
if args.quiet:
logger.setLevel('ERROR')
elif args.verbose:
logger.setLevel('DEBUG')
logger.debug("Logger set to debug.")
else:
logger.setLevel('INFO')
if not args.csv and not args.url and not args.txt:
print('You must provide either a single URL (--url), a CSV file (--csv) or a text file (--txt)')
sys.exit()
return args
if __name__ == "__main__":
import sys
main(parse_args(sys.argv[1:]))