Skip to content

Commit

Permalink
Merge pull request #1169 from NullArray/dev-beta
Browse files Browse the repository at this point in the history
nmap scanning
  • Loading branch information
NullArray authored Sep 4, 2019
2 parents 71e05c5 + a3ff69d commit 8ee8ea1
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 27 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ If you would like to contribute to the development of this project please be sur

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

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).
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).

### Note

Expand Down
3 changes: 2 additions & 1 deletion autosploit/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,5 @@ def main():
error_traceback = ''.join(traceback.format_tb(sys.exc_info()[2]))
error_class = str(e.__class__).split(" ")[1].split(".")[1].strip(">").strip("'")
error_file = save_error_to_file(str(error_traceback), str(e), error_class)
request_issue_creation(error_file, hide_sensitive(), str(e))
print error_traceback
# request_issue_creation(error_file, hide_sensitive(), str(e))
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,4 @@
--datadir
--send-eth/--send-ip
--privileged
--unprivileged
-V
--unprivileged
2 changes: 1 addition & 1 deletion lib/banner.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import random

VERSION = "3.1.5"
VERSION = "4.0"


def banner_1(line_sep="#--", space=" " * 30):
Expand Down
59 changes: 48 additions & 11 deletions lib/scanner/nmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"""

import os
import shlex
import json
import subprocess

from xml.etree import ElementTree
Expand All @@ -60,18 +60,51 @@
import lib.settings


def write_xml_data(host, output):
if not os.path.exists(lib.settings.NMAP_XML_OUTPUT_BACKUP):
os.makedirs(lib.settings.NMAP_XML_OUTPUT_BACKUP)
file_path = "{}/{}_{}.xml".format(
lib.settings.NMAP_XML_OUTPUT_BACKUP, str(host), lib.jsonize.random_file_name(length=10)
def parse_nmap_args(args):
"""
parse the provided arguments and ask if they aren't in the `known` arguments list
"""
runnable_args = []
known_args = [a.strip() for a in open(lib.settings.NMAP_OPTIONS_PATH).readlines()]
for arg in args:
if " " in arg:
tmparg = arg.split(" ")[0]
else:
tmparg = arg
if tmparg in known_args:
runnable_args.append(arg)
else:
choice = lib.output.prompt(
"argument: '{}' is not in the list of 'known' nmap arguments, "
"do you want to use it anyways[y/N]".format(arg)
)
if choice.lower() == "y":
runnable_args.append(tmparg)
return runnable_args


def write_data(host, output, is_xml=True):
"""
dump XML data to a file
"""
if not os.path.exists(lib.settings.NMAP_XML_OUTPUT_BACKUP if is_xml else lib.settings.NMAP_JSON_OUTPUT_BACKUP):
os.makedirs(lib.settings.NMAP_XML_OUTPUT_BACKUP if is_xml else lib.settings.NMAP_JSON_OUTPUT_BACKUP)
file_path = "{}/{}_{}.{}".format(
lib.settings.NMAP_XML_OUTPUT_BACKUP if is_xml else lib.settings.NMAP_JSON_OUTPUT_BACKUP,
str(host), lib.jsonize.random_file_name(length=10), "xml" if is_xml else "json"
)
with open(file_path, 'a+') as results:
results.write(output)
if is_xml:
results.write(output)
else:
json.dump(output, results, indent=4)
return file_path


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


def do_scan(host, nmap_path, ports=None, arguments=None):
"""
perform the nmap scan
"""
if arguments is None:
arguments = "-sV"
arguments_list = shlex.split(arguments)
launch_arguments = [
nmap_path, '-oX', '-', host,
'-p ' + ports if ports is not None else "",
] + arguments_list
] + arguments
to_launch = []
for item in launch_arguments:
if not item == "":
Expand All @@ -111,12 +146,14 @@ def do_scan(host, nmap_path, ports=None, arguments=None):
nmap_warn_tracestack.append(line + os.linesep)
else:
nmap_error_tracestack.append(line + os.linesep)
path = write_xml_data(host, output_data)
lib.output.misc_info("a copy of the output has been saved to: {}".format(path))
write_data(host, output_data, is_xml=True)
return output_data, "".join(nmap_warn_tracestack), "".join(nmap_error_tracestack)


def parse_xml_output(output, warnings, error):
"""
parse the XML data out of the file into a dict
"""
results = {}
try:
root = ElementTree.fromstring(output)
Expand Down
11 changes: 7 additions & 4 deletions lib/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,17 @@ def complete_text(self, text, state):
# autosploit command history file path
HISTORY_FILE_PATH = "{}/.history".format(HOME)

# we'll save the scans output for future use
NMAP_XML_OUTPUT_BACKUP = "{}/nmap_scans".format(HOME)
# we'll save the scans xml output for future use
NMAP_XML_OUTPUT_BACKUP = "{}/nmap_scans/xml".format(HOME)

# we'll dump the generated dict data into JSON and save it into a file
NMAP_JSON_OUTPUT_BACKUP = "{}/nmap_scans/json".format(HOME)

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

# possible options in nmap
NMAP_OPTIONS_PATH = "{}/etc_text_files/nmap_opts.lst".format(CUR_DIR)
NMAP_OPTIONS_PATH = "{}/etc/text_files/nmap_opts.lst".format(CUR_DIR)

# possible paths for nmap
NMAP_POSSIBLE_PATHS = (
Expand Down Expand Up @@ -321,7 +324,7 @@ def cmdline(command, is_msf=True):
else:
print("{}".format(stdout_line).rstrip())
except OSError as e:
stdout_buff += "ERROR: " + e
stdout_buff += "ERROR: " + str(e)

return stdout_buff

Expand Down
129 changes: 122 additions & 7 deletions lib/term/terminal.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import json
import datetime

import lib.banner
Expand Down Expand Up @@ -48,7 +49,9 @@ class object for the main terminal of the program
# clean the hosts file of duplicate IP's
"clean", "clear",
# easter eggs!
"idkwhatimdoing", "ethics", "skid"
"idkwhatimdoing", "ethics", "skid",
# nmap arguments
"nmap", "mapper", "mappy"
]
external_terminal_commands = lib.settings.load_external_commands()
api_call_pointers = {
Expand Down Expand Up @@ -216,9 +219,14 @@ def do_api_search(self, requested_api_data, query, tokens):
:param query: the query to be searched
:param tokens: an argument dict that will contain the token information
Command Format:
--------------
search[/api/gather] API_NAME[API_NAME,...](shodan,censys,zoomeye) QUERY
Examples:
---------
search/api/gather shodan[,censys[,zoomeye]] windows 10
search shodan,censys,zoomeye windows 10
search shodan windows 7
"""
acceptable_api_names = ("shodan", "censys", "zoomeye")
api_checker = lambda l: all(i.lower() in acceptable_api_names for i in l)
Expand Down Expand Up @@ -320,9 +328,13 @@ def do_add_single_host(self, ip):
-----------
:param ip: IP address to be added
Command Format:
--------------
single IP[,IP,IP,IP,IP,...]
Examples:
---------
single 89.76.12.124[,89.76.12.43,89.90.65.78,...]
single 89.76.12.124,89.76.12.43
"""
for item in ip.split(","):
validated_ip = lib.settings.validate_ip_addr(item)
Expand Down Expand Up @@ -357,9 +369,13 @@ def do_exploit_targets(self, workspace_info, shodan_token=None):
-----------
:param workspace_info: a tuple of workspace information
Command Format:
--------------
exploit[/run/attack] IP PORT WORKSPACE_NAME [whitewash list]
Examples:
---------
exploit/run/attack 127.0.0.1 9065 default [whitewash list]
exploit 127.0.0.1 9065 default whitelist.txt
"""
if workspace_info[3] is not None and workspace_info[3] != "honeycheck":
lib.output.misc_info("doing whitewash on hosts file")
Expand Down Expand Up @@ -420,9 +436,13 @@ def do_load_custom_hosts(self, file_path):
-----------
:param file_path: the full path to the loadable hosts file
Command Format:
--------------
custom[/personal] FILE_PATH
Examples:
---------
custom/personal /some/path/to/myfile.txt
custom /some/path/to/myfile.txt
"""
import shutil

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

def do_nmap_scan(self, target, arguments):
"""
Explanation:
-----------
Perform a nmap scan on a provided target, given that nmap is on your system.
If nmap is not on your system, this will not work, you may also provide
arguments known to nmap.
Parameters:
----------
:param target: the target to attack
:param arguments: a string of arguments separated by a comma
Command Format:
--------------
nmap[/mapper/mappy] TARGET [ARGUMENTS]
Examples:
--------
nmap/mapper/mappy 10.0.1.1 -sV,--dns-servers 1.1.1.1,--reason,-A
nmap 10.0.1.1/24
"""
import lib.scanner.nmap

sep = "-" * 30
if arguments is not None:
arguments = arguments.split(",")
passable_arguments = lib.scanner.nmap.parse_nmap_args(arguments)
else:
passable_arguments = None
try:
nmap_path = lib.scanner.nmap.find_nmap(lib.settings.NMAP_POSSIBLE_PATHS)
except lib.errors.NmapNotFoundException:
nmap_path = None
lib.output.error("nmap was not found on your system please install nmap first")
return
lib.output.info("performing nmap scan on {}".format(target))
try:
output, warnings, errors = lib.scanner.nmap.do_scan(target, nmap_path, arguments=passable_arguments)
formatted_results_output = lib.scanner.nmap.parse_xml_output(output, warnings, errors)
save_file = lib.scanner.nmap.write_data(target, formatted_results_output, is_xml=False)
lib.output.misc_info("JSON data dumped to file: '{}'".format(save_file))
print("{sep}\n{data}\n{sep}".format(
data=json.dumps(formatted_results_output["nmap_scan"][target], indent=4), sep=sep
))
except lib.errors.NmapScannerError as e:
lib.output.error(str(e).strip())

def terminal_main_display(self, tokens, extra_commands=None, save_history=True):
# idk what the fuck the problem is but this seems to fix it so...
import lib.output
"""
terminal main display
"""
Expand Down Expand Up @@ -502,7 +572,7 @@ def terminal_main_display(self, tokens, extra_commands=None, save_history=True):
self.do_quit_terminal(save_history=save_history)
elif any(c in choice for c in ("view", "show")):
self.do_view_gathered()
elif any(c in choice for c in ("ver", "version")):
elif any(c in choice for c in ("version",)):
self.do_show_version_number()
elif any(c in choice for c in ("clean", "clear")):
self.do_clean_hosts()
Expand Down Expand Up @@ -625,9 +695,54 @@ def terminal_main_display(self, tokens, extra_commands=None, save_history=True):
self.do_token_reset(api, token, username)
else:
lib.output.error("cannot reset {} API credentials".format(choice))
elif any(c in choice for c in ["nmap", "mapper", "mappy"]):
try:
if "help" in choice_data_list:
print(self.do_nmap_scan.__doc__)
except TypeError:
pass
target = choice_data_list[1]
try:
arguments = choice_data_list[2]
lib.output.warning(
"arguments that have a space in them most likely will not be processed correctly, "
"(IE --dns-servers 1.1.1.1 will most likely cause issues)"
)
except IndexError:
arguments = None
# don't know how im going to implement ports yet
# try:
# ports = choice_data_list[3]
# except IndexError:
# ports = None
if "help" not in choice_data_list:
self.do_nmap_scan(target, arguments)
self.history.append(choice)
self.__reload()
except KeyboardInterrupt:
lib.output.warning("use the `exit/quit` command to end terminal session")
except IndexError:
pass
pass
except Exception as e:
global stop_animation

stop_animation = True

import sys
import traceback
import lib.creation.issue_creator

print(
"\033[31m[!] AutoSploit has hit an unhandled exception: '{}', "
"in order for the developers to troubleshoot and repair the "
"issue AutoSploit will need to gather your OS information, "
"current arguments, the error message, and a traceback. "
"None of this information can be used to identify you in any way\033[0m".format(str(e))
)
error_traceback = ''.join(traceback.format_tb(sys.exc_info()[2]))
error_class = str(e.__class__).split(" ")[1].split(".")[1].strip(">").strip("'")
error_file = lib.settings.save_error_to_file(str(error_traceback), str(e), error_class)
lib.creation.issue_creator.request_issue_creation(error_file, lib.creation.issue_creator.hide_sensitive(), str(e))
lib.output.info("continuing terminal session")
# this way if you're in the terminal already we won't quit out of it
continue

0 comments on commit 8ee8ea1

Please sign in to comment.