Skip to content

Commit db6494f

Browse files
committedSep 4, 2019
implements nmap scanning into autosploit, also fix issues #1163
1 parent 5d9446a commit db6494f

File tree

7 files changed

+182
-27
lines changed

7 files changed

+182
-27
lines changed
 

‎README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ If you would like to contribute to the development of this project please be sur
185185

186186
Please, also, be sure to read our [contribution standards](https://github.com/NullArray/AutoSploit/wiki/Development-information#contribution-standards) before sending pull requests
187187

188-
If you need some help understanding the code, or want to chat with some other AutoSploit community members, feel free to join our [Discord server](https://discord.gg/9BeeZQk).
188+
If you need some help understanding the code, or want to chat with some other AutoSploit community members, feel free to join our [Discord server](https://discord.gg/DZe4zr2).
189189

190190
### Note
191191

‎autosploit/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,5 @@ def main():
132132
error_traceback = ''.join(traceback.format_tb(sys.exc_info()[2]))
133133
error_class = str(e.__class__).split(" ")[1].split(".")[1].strip(">").strip("'")
134134
error_file = save_error_to_file(str(error_traceback), str(e), error_class)
135-
request_issue_creation(error_file, hide_sensitive(), str(e))
135+
print error_traceback
136+
# request_issue_creation(error_file, hide_sensitive(), str(e))

‎etc/text_files/nmap_options.lst renamed to ‎etc/text_files/nmap_opts.lst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,4 @@
104104
--datadir
105105
--send-eth/--send-ip
106106
--privileged
107-
--unprivileged
108-
-V
107+
--unprivileged

‎lib/banner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
import random
33

4-
VERSION = "3.1.5"
4+
VERSION = "4.0"
55

66

77
def banner_1(line_sep="#--", space=" " * 30):

‎lib/scanner/nmap.py

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"""
5050

5151
import os
52-
import shlex
52+
import json
5353
import subprocess
5454

5555
from xml.etree import ElementTree
@@ -60,18 +60,51 @@
6060
import lib.settings
6161

6262

63-
def write_xml_data(host, output):
64-
if not os.path.exists(lib.settings.NMAP_XML_OUTPUT_BACKUP):
65-
os.makedirs(lib.settings.NMAP_XML_OUTPUT_BACKUP)
66-
file_path = "{}/{}_{}.xml".format(
67-
lib.settings.NMAP_XML_OUTPUT_BACKUP, str(host), lib.jsonize.random_file_name(length=10)
63+
def parse_nmap_args(args):
64+
"""
65+
parse the provided arguments and ask if they aren't in the `known` arguments list
66+
"""
67+
runnable_args = []
68+
known_args = [a.strip() for a in open(lib.settings.NMAP_OPTIONS_PATH).readlines()]
69+
for arg in args:
70+
if " " in arg:
71+
tmparg = arg.split(" ")[0]
72+
else:
73+
tmparg = arg
74+
if tmparg in known_args:
75+
runnable_args.append(arg)
76+
else:
77+
choice = lib.output.prompt(
78+
"argument: '{}' is not in the list of 'known' nmap arguments, "
79+
"do you want to use it anyways[y/N]".format(arg)
80+
)
81+
if choice.lower() == "y":
82+
runnable_args.append(tmparg)
83+
return runnable_args
84+
85+
86+
def write_data(host, output, is_xml=True):
87+
"""
88+
dump XML data to a file
89+
"""
90+
if not os.path.exists(lib.settings.NMAP_XML_OUTPUT_BACKUP if is_xml else lib.settings.NMAP_JSON_OUTPUT_BACKUP):
91+
os.makedirs(lib.settings.NMAP_XML_OUTPUT_BACKUP if is_xml else lib.settings.NMAP_JSON_OUTPUT_BACKUP)
92+
file_path = "{}/{}_{}.{}".format(
93+
lib.settings.NMAP_XML_OUTPUT_BACKUP if is_xml else lib.settings.NMAP_JSON_OUTPUT_BACKUP,
94+
str(host), lib.jsonize.random_file_name(length=10), "xml" if is_xml else "json"
6895
)
6996
with open(file_path, 'a+') as results:
70-
results.write(output)
97+
if is_xml:
98+
results.write(output)
99+
else:
100+
json.dump(output, results, indent=4)
71101
return file_path
72102

73103

74104
def find_nmap(search_paths):
105+
"""
106+
check if nmap is on the system
107+
"""
75108
for path in search_paths:
76109
try:
77110
_ = subprocess.Popen([path, '-V'], bufsize=10000, stdout=subprocess.PIPE, close_fds=True)
@@ -83,13 +116,15 @@ def find_nmap(search_paths):
83116

84117

85118
def do_scan(host, nmap_path, ports=None, arguments=None):
119+
"""
120+
perform the nmap scan
121+
"""
86122
if arguments is None:
87123
arguments = "-sV"
88-
arguments_list = shlex.split(arguments)
89124
launch_arguments = [
90125
nmap_path, '-oX', '-', host,
91126
'-p ' + ports if ports is not None else "",
92-
] + arguments_list
127+
] + arguments
93128
to_launch = []
94129
for item in launch_arguments:
95130
if not item == "":
@@ -111,12 +146,14 @@ def do_scan(host, nmap_path, ports=None, arguments=None):
111146
nmap_warn_tracestack.append(line + os.linesep)
112147
else:
113148
nmap_error_tracestack.append(line + os.linesep)
114-
path = write_xml_data(host, output_data)
115-
lib.output.misc_info("a copy of the output has been saved to: {}".format(path))
149+
write_data(host, output_data, is_xml=True)
116150
return output_data, "".join(nmap_warn_tracestack), "".join(nmap_error_tracestack)
117151

118152

119153
def parse_xml_output(output, warnings, error):
154+
"""
155+
parse the XML data out of the file into a dict
156+
"""
120157
results = {}
121158
try:
122159
root = ElementTree.fromstring(output)

‎lib/settings.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,17 @@ def complete_text(self, text, state):
7272
# autosploit command history file path
7373
HISTORY_FILE_PATH = "{}/.history".format(HOME)
7474

75-
# we'll save the scans output for future use
76-
NMAP_XML_OUTPUT_BACKUP = "{}/nmap_scans".format(HOME)
75+
# we'll save the scans xml output for future use
76+
NMAP_XML_OUTPUT_BACKUP = "{}/nmap_scans/xml".format(HOME)
77+
78+
# we'll dump the generated dict data into JSON and save it into a file
79+
NMAP_JSON_OUTPUT_BACKUP = "{}/nmap_scans/json".format(HOME)
7780

7881
# regex to discover errors or warnings
7982
NMAP_ERROR_REGEX_WARNING = re.compile("^warning: .*", re.IGNORECASE)
8083

8184
# possible options in nmap
82-
NMAP_OPTIONS_PATH = "{}/etc_text_files/nmap_opts.lst".format(CUR_DIR)
85+
NMAP_OPTIONS_PATH = "{}/etc/text_files/nmap_opts.lst".format(CUR_DIR)
8386

8487
# possible paths for nmap
8588
NMAP_POSSIBLE_PATHS = (
@@ -321,7 +324,7 @@ def cmdline(command, is_msf=True):
321324
else:
322325
print("{}".format(stdout_line).rstrip())
323326
except OSError as e:
324-
stdout_buff += "ERROR: " + e
327+
stdout_buff += "ERROR: " + str(e)
325328

326329
return stdout_buff
327330

‎lib/term/terminal.py

Lines changed: 122 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import json
23
import datetime
34

45
import lib.banner
@@ -48,7 +49,9 @@ class object for the main terminal of the program
4849
# clean the hosts file of duplicate IP's
4950
"clean", "clear",
5051
# easter eggs!
51-
"idkwhatimdoing", "ethics", "skid"
52+
"idkwhatimdoing", "ethics", "skid",
53+
# nmap arguments
54+
"nmap", "mapper", "mappy"
5255
]
5356
external_terminal_commands = lib.settings.load_external_commands()
5457
api_call_pointers = {
@@ -216,9 +219,14 @@ def do_api_search(self, requested_api_data, query, tokens):
216219
:param query: the query to be searched
217220
:param tokens: an argument dict that will contain the token information
218221
222+
Command Format:
223+
--------------
224+
search[/api/gather] API_NAME[API_NAME,...](shodan,censys,zoomeye) QUERY
225+
219226
Examples:
220227
---------
221-
search/api/gather shodan[,censys[,zoomeye]] windows 10
228+
search shodan,censys,zoomeye windows 10
229+
search shodan windows 7
222230
"""
223231
acceptable_api_names = ("shodan", "censys", "zoomeye")
224232
api_checker = lambda l: all(i.lower() in acceptable_api_names for i in l)
@@ -320,9 +328,13 @@ def do_add_single_host(self, ip):
320328
-----------
321329
:param ip: IP address to be added
322330
331+
Command Format:
332+
--------------
333+
single IP[,IP,IP,IP,IP,...]
334+
323335
Examples:
324336
---------
325-
single 89.76.12.124[,89.76.12.43,89.90.65.78,...]
337+
single 89.76.12.124,89.76.12.43
326338
"""
327339
for item in ip.split(","):
328340
validated_ip = lib.settings.validate_ip_addr(item)
@@ -357,9 +369,13 @@ def do_exploit_targets(self, workspace_info, shodan_token=None):
357369
-----------
358370
:param workspace_info: a tuple of workspace information
359371
372+
Command Format:
373+
--------------
374+
exploit[/run/attack] IP PORT WORKSPACE_NAME [whitewash list]
375+
360376
Examples:
361377
---------
362-
exploit/run/attack 127.0.0.1 9065 default [whitewash list]
378+
exploit 127.0.0.1 9065 default whitelist.txt
363379
"""
364380
if workspace_info[3] is not None and workspace_info[3] != "honeycheck":
365381
lib.output.misc_info("doing whitewash on hosts file")
@@ -420,9 +436,13 @@ def do_load_custom_hosts(self, file_path):
420436
-----------
421437
:param file_path: the full path to the loadable hosts file
422438
439+
Command Format:
440+
--------------
441+
custom[/personal] FILE_PATH
442+
423443
Examples:
424444
---------
425-
custom/personal /some/path/to/myfile.txt
445+
custom /some/path/to/myfile.txt
426446
"""
427447
import shutil
428448

@@ -437,7 +457,57 @@ def do_load_custom_hosts(self, file_path):
437457
lib.output.info("host file replaced, backup stored under '{}'".format(backup_path))
438458
self.loaded_hosts = open(lib.settings.HOST_FILE).readlines()
439459

460+
def do_nmap_scan(self, target, arguments):
461+
"""
462+
Explanation:
463+
-----------
464+
Perform a nmap scan on a provided target, given that nmap is on your system.
465+
If nmap is not on your system, this will not work, you may also provide
466+
arguments known to nmap.
467+
468+
Parameters:
469+
----------
470+
:param target: the target to attack
471+
:param arguments: a string of arguments separated by a comma
472+
473+
Command Format:
474+
--------------
475+
nmap[/mapper/mappy] TARGET [ARGUMENTS]
476+
477+
Examples:
478+
--------
479+
nmap/mapper/mappy 10.0.1.1 -sV,--dns-servers 1.1.1.1,--reason,-A
480+
nmap 10.0.1.1/24
481+
"""
482+
import lib.scanner.nmap
483+
484+
sep = "-" * 30
485+
if arguments is not None:
486+
arguments = arguments.split(",")
487+
passable_arguments = lib.scanner.nmap.parse_nmap_args(arguments)
488+
else:
489+
passable_arguments = None
490+
try:
491+
nmap_path = lib.scanner.nmap.find_nmap(lib.settings.NMAP_POSSIBLE_PATHS)
492+
except lib.errors.NmapNotFoundException:
493+
nmap_path = None
494+
lib.output.error("nmap was not found on your system please install nmap first")
495+
return
496+
lib.output.info("performing nmap scan on {}".format(target))
497+
try:
498+
output, warnings, errors = lib.scanner.nmap.do_scan(target, nmap_path, arguments=passable_arguments)
499+
formatted_results_output = lib.scanner.nmap.parse_xml_output(output, warnings, errors)
500+
save_file = lib.scanner.nmap.write_data(target, formatted_results_output, is_xml=False)
501+
lib.output.misc_info("JSON data dumped to file: '{}'".format(save_file))
502+
print("{sep}\n{data}\n{sep}".format(
503+
data=json.dumps(formatted_results_output["nmap_scan"][target], indent=4), sep=sep
504+
))
505+
except lib.errors.NmapScannerError as e:
506+
lib.output.error(str(e).strip())
507+
440508
def terminal_main_display(self, tokens, extra_commands=None, save_history=True):
509+
# idk what the fuck the problem is but this seems to fix it so...
510+
import lib.output
441511
"""
442512
terminal main display
443513
"""
@@ -502,7 +572,7 @@ def terminal_main_display(self, tokens, extra_commands=None, save_history=True):
502572
self.do_quit_terminal(save_history=save_history)
503573
elif any(c in choice for c in ("view", "show")):
504574
self.do_view_gathered()
505-
elif any(c in choice for c in ("ver", "version")):
575+
elif any(c in choice for c in ("version",)):
506576
self.do_show_version_number()
507577
elif any(c in choice for c in ("clean", "clear")):
508578
self.do_clean_hosts()
@@ -625,9 +695,54 @@ def terminal_main_display(self, tokens, extra_commands=None, save_history=True):
625695
self.do_token_reset(api, token, username)
626696
else:
627697
lib.output.error("cannot reset {} API credentials".format(choice))
698+
elif any(c in choice for c in ["nmap", "mapper", "mappy"]):
699+
try:
700+
if "help" in choice_data_list:
701+
print(self.do_nmap_scan.__doc__)
702+
except TypeError:
703+
pass
704+
target = choice_data_list[1]
705+
try:
706+
arguments = choice_data_list[2]
707+
lib.output.warning(
708+
"arguments that have a space in them most likely will not be processed correctly, "
709+
"(IE --dns-servers 1.1.1.1 will most likely cause issues)"
710+
)
711+
except IndexError:
712+
arguments = None
713+
# don't know how im going to implement ports yet
714+
# try:
715+
# ports = choice_data_list[3]
716+
# except IndexError:
717+
# ports = None
718+
719+
self.do_nmap_scan(target, arguments)
628720
self.history.append(choice)
629721
self.__reload()
630722
except KeyboardInterrupt:
631723
lib.output.warning("use the `exit/quit` command to end terminal session")
632724
except IndexError:
633-
pass
725+
pass
726+
except Exception as e:
727+
global stop_animation
728+
729+
stop_animation = True
730+
731+
import sys
732+
import traceback
733+
import lib.creation.issue_creator
734+
735+
print(
736+
"\033[31m[!] AutoSploit has hit an unhandled exception: '{}', "
737+
"in order for the developers to troubleshoot and repair the "
738+
"issue AutoSploit will need to gather your OS information, "
739+
"current arguments, the error message, and a traceback. "
740+
"None of this information can be used to identify you in any way\033[0m".format(str(e))
741+
)
742+
error_traceback = ''.join(traceback.format_tb(sys.exc_info()[2]))
743+
error_class = str(e.__class__).split(" ")[1].split(".")[1].strip(">").strip("'")
744+
error_file = lib.settings.save_error_to_file(str(error_traceback), str(e), error_class)
745+
lib.creation.issue_creator.request_issue_creation(error_file, lib.creation.issue_creator.hide_sensitive(), str(e))
746+
lib.output.info("continuing terminal session")
747+
# this way if you're in the terminal already we won't quit out of it
748+
continue

0 commit comments

Comments
 (0)
Please sign in to comment.