From aea40a702d4d25678ccd161528319154bac6ca41 Mon Sep 17 00:00:00 2001 From: ekultek Date: Tue, 30 Apr 2019 11:41:55 -0500 Subject: [PATCH 01/19] creates a way to clean duplicate IP's out of the hosts file from the terminal --- api_calls/honeyscore_hook.py | 1 - lib/banner.py | 2 +- lib/settings.py | 1 + lib/term/terminal.py | 23 +++++++++++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/api_calls/honeyscore_hook.py b/api_calls/honeyscore_hook.py index 93f7917..cc773c8 100644 --- a/api_calls/honeyscore_hook.py +++ b/api_calls/honeyscore_hook.py @@ -1,5 +1,4 @@ import requests -from bs4 import BeautifulSoup class HoneyHook(object): diff --git a/lib/banner.py b/lib/banner.py index 808fea0..26f355a 100644 --- a/lib/banner.py +++ b/lib/banner.py @@ -1,7 +1,7 @@ import os import random -VERSION = "3.1.2" +VERSION = "3.1.3" def banner_1(line_sep="#--", space=" " * 30): diff --git a/lib/settings.py b/lib/settings.py index 527807f..4eec7c6 100644 --- a/lib/settings.py +++ b/lib/settings.py @@ -55,6 +55,7 @@ def complete_text(self, text, state): tokens/reset Reset API tokens if needed external View loaded external commands ver[sion] View the current version of the program +clean/clear Clean the hosts.txt file of duplicate IP addresses help/? Display this help """ diff --git a/lib/term/terminal.py b/lib/term/terminal.py index 2d7081c..534469b 100644 --- a/lib/term/terminal.py +++ b/lib/term/terminal.py @@ -45,6 +45,8 @@ class object for the main terminal of the program "reset", "tokens", # show the version number "ver", "version", + # clean the hosts file of duplicate IP's + "clean", "clear", # easter eggs! "idkwhatimdoing", "ethics", "skid" ] @@ -148,6 +150,25 @@ def do_terminal_command(self, command): """ lib.settings.cmdline(command, is_msf=False) + def do_clean_hosts(self): + """ + Clean the hosts.txt file of any duplicate IP addresses + """ + retval = set() + current_size = len(self.loaded_hosts) + for host in self.loaded_hosts: + retval.add(host) + cleaned_size = len(retval) + with open(lib.settings.HOST_FILE, 'w') as hosts: + for item in list(retval): + hosts.write(item) + if current_size != cleaned_size: + lib.output.info("cleaned {} duplicate IP address(es) (total of {})".format( + current_size - cleaned_size, cleaned_size + ) + ) + self.__reload() + def do_token_reset(self, api, token, username): """ Explanation: @@ -475,6 +496,8 @@ def terminal_main_display(self, tokens, extra_commands=None, save_history=True): self.do_view_gathered() elif any(c in choice for c in ("ver", "version")): self.do_show_version_number() + elif any(c in choice for c in ("clean", "clear")): + self.do_clean_hosts() elif "single" in choice: try: if "help" in choice_data_list: From 482d395c4aabf7aa2a396f7d73b89a9496db709f Mon Sep 17 00:00:00 2001 From: ekultek Date: Tue, 30 Apr 2019 12:19:59 -0500 Subject: [PATCH 02/19] creating a way to quickly search multiple queries using a bash script --- dryrun_autosploit.sh => drysploit.sh | 6 +++++- lib/cmdline/cmd.py | 2 +- quicksploit.sh | 30 ++++++++++++++++++++++++++++ run_autosploit.sh => runsploit.sh | 8 +++++++- 4 files changed, 43 insertions(+), 3 deletions(-) rename dryrun_autosploit.sh => drysploit.sh (89%) create mode 100755 quicksploit.sh rename run_autosploit.sh => runsploit.sh (72%) diff --git a/dryrun_autosploit.sh b/drysploit.sh similarity index 89% rename from dryrun_autosploit.sh rename to drysploit.sh index 1089632..9a8855a 100644 --- a/dryrun_autosploit.sh +++ b/drysploit.sh @@ -1,9 +1,13 @@ #!/usr/bin/env bash +# +# this script dryruns autosploit. That's it, nothing special just a dry run +# + if [[ $# -lt 1 ]]; then echo "Syntax:" - echo -e "\t./dryrun_autosploit.sh [whitelist]" + echo -e "\t./drysploit.sh [whitelist]" exit 1 fi diff --git a/lib/cmdline/cmd.py b/lib/cmdline/cmd.py index 493f3de..2dc3e56 100644 --- a/lib/cmdline/cmd.py +++ b/lib/cmdline/cmd.py @@ -79,7 +79,7 @@ def optparser(): misc.add_argument("--ethics", action="store_true", dest="displayEthics", help=argparse.SUPPRESS) # easter egg! misc.add_argument("--whitelist", metavar="PATH", dest="whitelist", - help="only exploit hosts listed in the whitelist file") + help="only exploit hosts listed in the whitelist file") misc.add_argument("-D", "--download", nargs="+", metavar="SEARCH1 SEARCH2 ...", dest="downloadModules", help="download new exploit modules with a provided search flag") opts = parser.parse_args() diff --git a/quicksploit.sh b/quicksploit.sh new file mode 100755 index 0000000..ecad084 --- /dev/null +++ b/quicksploit.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# +# this script quickly runs a query list of search keywords provided from a file on ALL of the +# available APIs. (Censys, Zoomeye, and Shodan) from there it will save all of them to the hosts.txt +# file and you can do as you will with that +# + +function doQuick() { + for item in $(cat $1); do python autosploit.py -A -a -f etc/json/default_modules.json -q $item; done +} + +function helpPage() { + echo "./quicksploit.sh FILENAME"; + exit 1; +} + +function main() { + if [[ $EUID -ne 0 ]]; then + echo "[!] must run script as root!"; + exit 1; + elif [[ ! -f $1 ]]; then + helpPage; + else + echo "[+] starting quicksploit searching!"; + doQuick $1; + fi +} + +main $@; \ No newline at end of file diff --git a/run_autosploit.sh b/runsploit.sh similarity index 72% rename from run_autosploit.sh rename to runsploit.sh index 9dfcdaf..df4c026 100755 --- a/run_autosploit.sh +++ b/runsploit.sh @@ -1,9 +1,15 @@ #!/bin/bash +# +# this script runs autosploit with default configs and default modules +# protip be on a VPS when you run this because it's gonna start an attack +# right away +# + if [[ $# -lt 1 ]]; then echo "Syntax:" - echo -e "\t./run_autosploit.sh PORT [WHITELIST]" + echo -e "\t./runsploit.sh PORT [WHITELIST]" exit 1 fi From 66a45236bfcd850a9ab92e121c9a3db7e35ba8c9 Mon Sep 17 00:00:00 2001 From: ekultek Date: Tue, 7 May 2019 08:37:37 -0500 Subject: [PATCH 03/19] adding a funny quote i found --- etc/text_files/ethics.lst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/etc/text_files/ethics.lst b/etc/text_files/ethics.lst index fcdf3ca..6fdd371 100644 --- a/etc/text_files/ethics.lst +++ b/etc/text_files/ethics.lst @@ -11,4 +11,5 @@ "My fear is that this has magnified the attack surface, and made it so that every exposed service on the internet will be scanned and probed on a near-constant basis by an entirely new set of attackers." "The release of tools like these exponentially expands the threat landscape by allowing a wider group of hackers to launch global attacks at will" "Good to know we’ve weaponized for the masses. Everyone can now be a script kiddie simply by plugging, playing and attacking." -"The fact that something is really easy, does not make unauthorized computer access any less a crime. And tools like this leave a forensic footprint that is miles wide. Yes, you can compromise poorly protected systems very easily with this tool, but you can also end up in a lot of trouble." \ No newline at end of file +"The fact that something is really easy, does not make unauthorized computer access any less a crime. And tools like this leave a forensic footprint that is miles wide. Yes, you can compromise poorly protected systems very easily with this tool, but you can also end up in a lot of trouble." +"I can't believe it's not skidware!" \ No newline at end of file From 4b4495fdcf0d9a7b246387b395341b000ffcad7b Mon Sep 17 00:00:00 2001 From: Ekultek Date: Wed, 8 May 2019 10:42:00 -0500 Subject: [PATCH 04/19] Update default_fuzzers.json --- etc/json/default_fuzzers.json | 1 - 1 file changed, 1 deletion(-) diff --git a/etc/json/default_fuzzers.json b/etc/json/default_fuzzers.json index b606973..5eb3b82 100644 --- a/etc/json/default_fuzzers.json +++ b/etc/json/default_fuzzers.json @@ -1,6 +1,5 @@ { "exploits": [ - "auxiliary/fuzzers/dns/dns_fuzzer", "auxiliary/fuzzers/ftp/client_ftp", "auxiliary/fuzzers/ftp/ftp_pre_post", "auxiliary/fuzzers/http/http_form_field", From 14136b421c1166ca3c784b70d94ff88c8c376173 Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 8 May 2019 10:50:47 -0500 Subject: [PATCH 05/19] some minor updates --- drysploit.sh | 3 --- install.sh | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drysploit.sh b/drysploit.sh index 9a8855a..288a931 100644 --- a/drysploit.sh +++ b/drysploit.sh @@ -11,9 +11,6 @@ if [[ $# -lt 1 ]]; then exit 1 fi -echo -e "[!] Make sure you are not on your localhost while running this script, press enter to continue"; -read - WHITELIST=$2 SEARCH_QUERY=$1 LPORT=4444 diff --git a/install.sh b/install.sh index a92582a..a4ef8a9 100755 --- a/install.sh +++ b/install.sh @@ -88,7 +88,7 @@ function install () { installOSX; ;; *) - echo "Unable to detect operating system that is compatible with AutoSploit..."; + echo "Unable to detect an operating system that is compatible with AutoSploit..."; ;; esac echo ""; From 2d316372c809729ac7629470d14957ff87b4c662 Mon Sep 17 00:00:00 2001 From: Ekultek Date: Thu, 27 Jun 2019 09:21:35 -0500 Subject: [PATCH 06/19] pushing for relation to the wrappers --- autosploit/main.py | 6 +- etc/text_files/nmap_options.lst | 108 ++++++++++++++++++++++ lib/errors.py | 8 +- lib/exploitation/exploiter.py | 3 +- lib/scanner/__init__.py | 0 lib/scanner/nmap.py | 156 ++++++++++++++++++++++++++++++++ lib/settings.py | 18 +++- 7 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 etc/text_files/nmap_options.lst create mode 100644 lib/scanner/__init__.py create mode 100644 lib/scanner/nmap.py diff --git a/autosploit/main.py b/autosploit/main.py index 6543054..b72d1a5 100644 --- a/autosploit/main.py +++ b/autosploit/main.py @@ -24,6 +24,7 @@ EXPLOIT_FILES_PATH, START_SERVICES_PATH, save_error_to_file, + stop_animation ) from lib.jsonize import ( load_exploits, @@ -115,6 +116,10 @@ def main(): terminal = AutoSploitTerminal(loaded_tokens, loaded_exploits) terminal.terminal_main_display(loaded_tokens) except Exception as e: + global stop_animation + + stop_animation = True + import traceback print( @@ -128,4 +133,3 @@ def main(): 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)) - diff --git a/etc/text_files/nmap_options.lst b/etc/text_files/nmap_options.lst new file mode 100644 index 0000000..4456386 --- /dev/null +++ b/etc/text_files/nmap_options.lst @@ -0,0 +1,108 @@ +-iL +-iR +--exclude +--excludefile +-sL +-sn +-Pn +-PS +-PA +-PU +-PY +-PE +-PP +-PM +-PO +-n +-R +--dns-servers +--system-dns +--traceroute +-sS +-sT +-sA +-sW +-sM +-sU +-sN +-sF +-sX +--scanflags +-sI +-sY +-sZ +-sO +-b +-p +--exclude-ports +-F +-r +--top-ports +--port-ratio +-sV +--version-intensity +--version-light +--version-all +--version-trace +-sC +--script +--script-args +--script-args-file +--script-trace +--script-updatedb +--script-help +-O +--osscan-limit +--osscan-guess +-T +--min-hostgroup +--max-hostgroup +--min-parallelism +--max-parallelism +--min-rtt-timeout +--max-rtt-timeout +--initial-rtt-timeout +--max-retries +--host-timeout +--scan-delay +--max-scan-delay +--min-rate +--max-rate +-f +--mtu +-D +-S +-e +-g +--source-port +--proxies +--data +--data-string +--data-length +--ip-options +--ttl +--spoof-mac +--badsum +-oN +-oX +-oS +-oG +-oA +-v +-d +--reason +--open +--packet-trace +--iflist +--append-output +--resume +--stylesheet +--webxml +--no-stylesheet +-6 +-A +--datadir +--send-eth/--send-ip +--privileged +--unprivileged +-V \ No newline at end of file diff --git a/lib/errors.py b/lib/errors.py index bab8acc..af2fc58 100644 --- a/lib/errors.py +++ b/lib/errors.py @@ -1 +1,7 @@ -class AutoSploitAPIConnectionError(Exception): pass \ No newline at end of file +class AutoSploitAPIConnectionError(Exception): pass + + +class NmapNotFoundException(Exception): pass + + +class NmapScannerError(Exception): pass \ No newline at end of file diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index b8a8786..ca69b40 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -110,13 +110,14 @@ def start_exploit(self, sep="*" * 10): if self.check_honey: lib.output.misc_info("checking if {} is a honeypot".format(host)) honey_score = api_calls.honeyscore_hook.HoneyHook(host, self.shodan_token).make_request() - if honey_score >= self.compare_honey: + if honey_score < self.compare_honey: lib.output.warning( "honeypot score ({}) is above (or equal to) requested, skipping target".format(honey_score) ) skip = True skip_amount += 1 else: + lib.output.misc_info("{} does not appear to be a honeypot, continuing attack") skip = False else: skip = False diff --git a/lib/scanner/__init__.py b/lib/scanner/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/scanner/nmap.py b/lib/scanner/nmap.py new file mode 100644 index 0000000..1797fec --- /dev/null +++ b/lib/scanner/nmap.py @@ -0,0 +1,156 @@ +import io +import os +import re +import csv +import sys +import shlex +import subprocess + +from xml.etree import ElementTree +from multiprocessing import Process + +import lib.jsonize +import lib.errors +import lib.output +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) + ) + with open(file_path, 'a+') as results: + results.write(output) + return file_path + + +def find_nmap(search_paths): + for path in search_paths: + try: + _ = subprocess.Popen([path, '-V'], bufsize=10000, stdout=subprocess.PIPE, close_fds=True) + except OSError: + pass + else: + return path + raise lib.errors.NmapNotFoundException + + +def do_scan(host, nmap_path, ports=None, arguments=None): + 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 + lib.output.info("launching nmap scan against {} ({})".format(host, " ".join(launch_arguments))) + process = subprocess.Popen( + launch_arguments, bufsize=10000, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + output, error = process.communicate() + output_data = bytes.decode(output) + nmap_error = bytes.decode(error) + nmap_error_tracestack = [] + nmap_warn_tracestack = [] + if len(nmap_error) > 0: + for line in nmap_error.split(os.linesep): + if len(line) != 0: + if lib.settings.NMAP_ERROR_REGEX_WARNING.search(line) is not 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)) + return output_data, "".join(nmap_warn_tracestack), "".join(nmap_error_tracestack) + + +def parse_xml_output(output, warnings, error): + results = {} + try: + root = ElementTree.fromstring(output) + except Exception: + if len(error) != 0: + raise lib.errors.NmapScannerError(error) + else: + raise lib.errors.NmapScannerError(output) + results['nmap_scan'] = { + 'full_command_line': root.get('args'), + 'scan_information': {}, + 'scan_stats': { + 'time_string': root.find('runstats/finished').get('timestr'), + 'elapsed': root.find('runstats/finished').get('elapsed'), + 'hosts_up': root.find('runstats/hosts').get('up'), + 'down_hosts': root.find('runstats/hosts').get('down'), + 'total_hosts_scanned': root.find('runstats/hosts').get('total') + } + } + if len(error) != 0: + results['nmap_scan']['scan_information']['errors'] = error + if len(warnings) != 0: + results['nmap_scan']['scan_information']['warnings'] = warnings + for info in root.findall('scaninfo'): + results['nmap_scan']['scan_information'][info.get('protocol')] = { + 'method': info.get('type'), + 'services': info.get('services') + } + for attempted_host in root.findall('host'): + host = None + addresses = {} + vendors = {} + for address in attempted_host.findall("address"): + address_type = address.get('addrtype') + addresses[address_type] = address.get('addr') + if address_type == "ipv4": + host = addresses[address_type] + elif address_type == "mac" and address.get('vendor') is not None: + vendors[addresses[address_type]] = address.get('vendor') + if host is None: + host = attempted_host.find('address').get('addr') + hostnames = [] + if len(attempted_host.findall('hostnames/hostname')) != 0: + for current_hostnames in attempted_host.findall('hostnames/hostname'): + hostnames.append({ + 'hostname': current_hostnames.get('name'), + 'host_type': current_hostnames.get('type') + }) + else: + hostnames.append({ + 'hostname': None, + 'host_type': None + }) + + results['nmap_scan'][host] = {} + results['nmap_scan'][host]['hostnames'] = hostnames + results['nmap_scan'][host]['addresses'] = addresses + results['nmap_scan'][host]['vendors'] = vendors + + print results;exit(1) + + for status in attempted_host.findall('status'): + results['nmap_scan'][attempted_host]['status'] = { + 'state': status.get('state'), + 'reason': status.get('reason') + } + for uptime in attempted_host.findall('uptime'): + results['nmap_scan'][attempted_host]['uptime'] = { + 'seconds': uptime.get('seconds'), + 'lastboot': uptime.get('lastboot') + } + for discovered_port in attempted_host.findall('ports/port'): + protocol = discovered_port.get('protocol') + port_number = discovered_port.get('portid') + port_state = discovered_port.find('state').get('reason') + + # damn I didn't even know you could do this! + for discovered_name in discovered_port.findall('service'): + name = discovered_name.get('name') + if discovered_name.get('product'): + discovered_product = discovered_name.get('product') + if discovered_name.get('version'): + discovered_version = discovered_name.get('version') + if discovered_name.get('extrainfo'): + extra_information = discovered_name.get('extrainfo') + print results \ No newline at end of file diff --git a/lib/settings.py b/lib/settings.py index 4eec7c6..4b94d00 100644 --- a/lib/settings.py +++ b/lib/settings.py @@ -1,4 +1,5 @@ import os +import re import sys import time import socket @@ -71,6 +72,20 @@ 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) + +# 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) + +# possible paths for nmap +NMAP_POSSIBLE_PATHS = ( + 'nmap', '/usr/bin/nmap', '/usr/local/bin/nmap', '/sw/bin/nmap', '/opt/local/bin/nmap' +) + # link to the checksums CHECKSUM_LINK = open("{}/etc/text_files/checksum_link.txt".format(CUR_DIR)).read() @@ -90,7 +105,8 @@ def complete_text(self, text, state): # one bash script to rule them all takes an argument via the operating system START_SERVICES_PATH = "{}/etc/scripts/start_services.sh".format(CUR_DIR) -RC_SCRIPTS_PATH = "{}/autosploit_out/".format(CUR_DIR) +# path where we will keep the rc scripts +RC_SCRIPTS_PATH = "{}/autosploit_out/".format(HOME) # path to the file that will contain our query QUERY_FILE_PATH = tempfile.NamedTemporaryFile(delete=False).name From fe1e425ed2675d4993c0fe390c5b55720af8dce2 Mon Sep 17 00:00:00 2001 From: Ekultek Date: Thu, 27 Jun 2019 13:06:31 -0500 Subject: [PATCH 07/19] the ip address generator is ready, just need to tie it together --- lib/creation/ip_generator.py | 66 ++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 lib/creation/ip_generator.py diff --git a/lib/creation/ip_generator.py b/lib/creation/ip_generator.py new file mode 100644 index 0000000..07207e6 --- /dev/null +++ b/lib/creation/ip_generator.py @@ -0,0 +1,66 @@ +import socket +import itertools + +from multiprocessing import Pool + + +def generate_ip_range(selected_range): + """ + generate an IP address range from each provided node. + for example `10.0.1-10.1-10` will return a generator + object that has IP `10.0.1.1 - 10.0.10.10` in it + """ + octets = selected_range.split(".") + chunks = [map(int, octet.split("-")) for octet in octets] + ranges = [range(c[0], c[1] + 1) if len(c) == 2 else c for c in chunks] + for address in itertools.product(*ranges): + yield ".".join(map(str, address)) + + +def check_ip_alive(ip): + """ + efficiently check if an IP address is alive or not + by using the socket.gethostbyaddr function + """ + def is_valid_ip(ip): + try: + socket.inet_aton(ip) + return True + except: + return False + + try: + if not is_valid_ip(ip): + return False + else: + return socket.gethostbyaddr(ip) + except socket.herror: + return False + + +def check_ip_wrapper(generated_ips, limit=350): + """ + multiprocess the check_ip_alive function in order + to proces a large amount of IP addresses quickly + """ + alive_ips = [] + ips_to_use = [] + i = 0 + proc_pool = Pool(processes=35) + + for ip in generated_ips: + ips_to_use.append(ip) + i += 1 + if i == limit: + break + for ip in ips_to_use: + try: + result = proc_pool.apply_async(check_ip_alive, args=(ip,)).get() + if not result: + pass + else: + alive_ips.append(ip) + except Exception: + pass + proc_pool.close() + return alive_ips From 15866139e4bc25d4a236411c1a34170c55b021fd Mon Sep 17 00:00:00 2001 From: Ekultek Date: Thu, 27 Jun 2019 13:07:49 -0500 Subject: [PATCH 08/19] minor update, oops --- lib/creation/ip_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/creation/ip_generator.py b/lib/creation/ip_generator.py index 07207e6..40218af 100644 --- a/lib/creation/ip_generator.py +++ b/lib/creation/ip_generator.py @@ -38,7 +38,7 @@ def is_valid_ip(ip): return False -def check_ip_wrapper(generated_ips, limit=350): +def check_ip_wrapper(generated_ips, limit=250): """ multiprocess the check_ip_alive function in order to proces a large amount of IP addresses quickly From 5b798b433271c5f9acd622928f477f94984bc963 Mon Sep 17 00:00:00 2001 From: Ekultek Date: Thu, 27 Jun 2019 14:12:03 -0500 Subject: [PATCH 09/19] just making some minor updates here and there --- lib/banner.py | 2 +- lib/cmdline/cmd.py | 16 ++++++++------ lib/creation/issue_creator.py | 28 ++++++++++++++++-------- lib/exploitation/exploiter.py | 41 +++++++++++++++-------------------- lib/settings.py | 2 +- lib/term/terminal.py | 24 ++++++++++---------- 6 files changed, 61 insertions(+), 52 deletions(-) diff --git a/lib/banner.py b/lib/banner.py index 26f355a..bb272a2 100644 --- a/lib/banner.py +++ b/lib/banner.py @@ -1,7 +1,7 @@ import os import random -VERSION = "3.1.3" +VERSION = "3.1.4" def banner_1(line_sep="#--", space=" " * 30): diff --git a/lib/cmdline/cmd.py b/lib/cmdline/cmd.py index 2dc3e56..647e8b3 100644 --- a/lib/cmdline/cmd.py +++ b/lib/cmdline/cmd.py @@ -25,10 +25,10 @@ def optparser(): """ parser = argparse.ArgumentParser( - usage="python autosploit.py -[c|z|s|a] -[q] QUERY\n" - "{spacer}[-C] WORKSPACE LHOST LPORT [-e] [--whitewash] PATH\n" - "{spacer}[--ruby-exec] [--msf-path] PATH [-E] EXPLOIT-FILE-PATH\n" - "{spacer}[--rand-agent] [--proxy] PROTO://IP:PORT [-P] AGENT".format( + usage="python autosploit.py -c[z|s|a] -q QUERY [-O|A]\n" + "{spacer}[-C WORKSPACE LHOST LPORT] [-e] [--whitewash PATH] [-H]\n" + "{spacer}[--ruby-exec] [--msf-path] PATH [-E EXPLOIT-FILE-PATH]\n" + "{spacer}[--rand-agent] [--proxy PROTO://IP:PORT] [-P AGENT] [-D QUERY,QUERY,..]".format( spacer=" " * 28 ) ) @@ -42,8 +42,10 @@ def optparser(): se.add_argument("-a", "--all", action="store_true", dest="searchAll", help="search all available search engines to gather hosts") save_results_args = se.add_mutually_exclusive_group(required=False) - save_results_args.add_argument("-O", "--overwrite", action="store_true", dest="overwriteHosts", - help="When specified, start from scratch by overwriting the host file with new search results.") + save_results_args.add_argument( + "-O", "--overwrite", action="store_true", dest="overwriteHosts", + help="When specified, start from scratch by overwriting the host file with new search results." + ) save_results_args.add_argument("-A", "--append", action="store_true", dest="appendHosts", help="When specified, append discovered hosts to the host file.") @@ -65,7 +67,7 @@ def optparser(): exploit.add_argument("-e", "--exploit", action="store_true", dest="startExploit", help="start exploiting the already gathered hosts") exploit.add_argument("-d", "--dry-run", action="store_true", dest="dryRun", - help="Do not launch metasploit's exploits. Do everything else. msfconsole is never called.") + help="msfconsole will never be called when this flag is passed") exploit.add_argument("-f", "--exploit-file-to-use", metavar="PATH", dest="exploitFile", help="Run AutoSploit with provided exploit JSON file.") exploit.add_argument("-H", "--is-honeypot", type=float, default=1000, dest="checkIfHoneypot", metavar="HONEY-SCORE", diff --git a/lib/creation/issue_creator.py b/lib/creation/issue_creator.py index 092b4a2..3b7f0c0 100644 --- a/lib/creation/issue_creator.py +++ b/lib/creation/issue_creator.py @@ -78,7 +78,7 @@ def check_version_number(current_version): try: req = requests.get("https://raw.githubusercontent.com/NullArray/AutoSploit/master/lib/banner.py") available_version = version_checker.search(req.content).group().split("=")[-1].split('"')[1] - if available_version != current_version: + if available_version > current_version: return False return True except Exception: @@ -168,15 +168,25 @@ def hide_sensitive(): args = sys.argv for item in sys.argv: if item in sensitive: - # TODO:/ we need to block the IP addresses in the -C argument - try: - item_index = args.index(item) + 1 - hidden = ''.join([x.replace(x, "*") for x in str(args[item_index])]) - args.pop(item_index) - args.insert(item_index, hidden) + if item in ["-C", "--config"]: + try: + item_index = args.index("-C") + 1 + except ValueError: + item_index = args.index("--config") + 1 + for _ in range(3): + hidden = ''.join([x.replace(x, '*') for x in str(args[item_index])]) + args.pop(item_index+_) + args.insert(item_index, hidden) return ' '.join(args) - except: - return ' '.join([item for item in sys.argv]) + else: + try: + item_index = args.index(item) + 1 + hidden = ''.join([x.replace(x, "*") for x in str(args[item_index])]) + args.pop(item_index) + args.insert(item_index, hidden) + return ' '.join(args) + except: + return ' '.join([item for item in sys.argv]) def request_issue_creation(path, arguments, error_message): diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index ca69b40..e53df58 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -40,6 +40,7 @@ class AutoSploitExploiter(object): sorted_modules = [] def __init__(self, configuration, all_modules, hosts=None, **kwargs): + self.hosts = hosts self.hosts = hosts self.configuration = configuration self.mods = all_modules @@ -89,14 +90,13 @@ def start_exploit(self, sep="*" * 10): report_path = path.join(current_run_path, "report.csv") with open(report_path, 'w') as f: csv_file = csv.writer(f, quoting=csv.QUOTE_ALL) - csv_file.writerow(['Target Host', - 'Date (UTC)', - 'MSF Module', - "LocalHost", - "Listening Port", - "Successful Logs", - "Failure Logs", - "All Logs"]) + csv_file.writerow( + [ + 'Target Host', 'Date (UTC)', 'MSF Module', + "LocalHost", "Listening Port", "Successful Logs", + "Failure Logs", "All Logs" + ] + ) lib.output.info("Launching exploits against {hosts_len} hosts:".format(hosts_len=len(self.hosts))) @@ -117,7 +117,7 @@ def start_exploit(self, sep="*" * 10): skip = True skip_amount += 1 else: - lib.output.misc_info("{} does not appear to be a honeypot, continuing attack") + lib.output.misc_info("{} does not appear to be a honeypot, continuing attack".format(host)) skip = False else: skip = False @@ -188,12 +188,11 @@ def start_exploit(self, sep="*" * 10): ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') msf_output_lines = [ansi_escape.sub('', x) for x in output if re.search('\[.\]', x)] - msf_wins = [x for x in msf_output_lines if re.search('\[\+\]', x) or - 'Meterpreter' in x or - 'Session' in x or - 'Sending stage' in x] - - msf_fails = [x for x in msf_output_lines if re.search('\[-\]', x)] + msf_wins = [ + x for x in msf_output_lines if re.search('\[\+\]', x) or + 'Meterpreter' in x or 'Session' in x or 'Sending stage' in x + ] + msf_fails = [x for x in msf_output_lines if re.search('\[-\]', x) and 'Background' not in x] if len(msf_wins): win_total += 1 @@ -201,14 +200,10 @@ def start_exploit(self, sep="*" * 10): fail_total += 1 csv_file = csv.writer(f, quoting=csv.QUOTE_ALL) - csv_file.writerow([rhost, - today_printable, - module_name, - lhost, - lport, - linesep.join(msf_wins), - linesep.join(msf_fails), - linesep.join(msf_output_lines)]) + csv_file.writerow([ + rhost, today_printable, module_name, lhost, lport, + linesep.join(msf_wins), linesep.join(msf_fails), linesep.join(msf_output_lines) + ]) print("") lib.output.info("{}RESULTS{}".format(sep, sep)) diff --git a/lib/settings.py b/lib/settings.py index 4b94d00..8a58a3e 100644 --- a/lib/settings.py +++ b/lib/settings.py @@ -51,7 +51,7 @@ def complete_text(self, text, state): exploit/run/attack Run the exploits on the already gathered hosts search/api/gather Search the API's for hosts exit/quit Exit the terminal session -single Load a single host into the file +single Load a single host into the file, or multiple hosts separated by a comma (1,2,3,..) personal/custom Load a custom host file tokens/reset Reset API tokens if needed external View loaded external commands diff --git a/lib/term/terminal.py b/lib/term/terminal.py index 534469b..36f0857 100644 --- a/lib/term/terminal.py +++ b/lib/term/terminal.py @@ -308,6 +308,7 @@ def do_add_single_host(self, ip): Explanation: ------------ Add a single host by IP address + Or a list of single hosts separatedd by a comma Parameters: ----------- @@ -315,15 +316,16 @@ def do_add_single_host(self, ip): Examples: --------- - single 89.76.12.124 + single 89.76.12.124[89.76.12.43,89.90.65.78,...] """ - validated_ip = lib.settings.validate_ip_addr(ip) - if not validated_ip: - lib.output.error("provided IP '{}' is invalid, try again".format(ip)) - else: - with open(lib.settings.HOST_FILE, "a+") as hosts: - hosts.write(ip + "\n") - lib.output.info("host '{}' saved to hosts file".format(ip)) + for item in ip.split(","): + validated_ip = lib.settings.validate_ip_addr(item) + if not validated_ip: + lib.output.error("provided IP '{}' is invalid, try again".format(ip)) + else: + with open(lib.settings.HOST_FILE, "a+") as hosts: + hosts.write(item + "\n") + lib.output.info("host '{}' saved to hosts file".format(item)) def do_quit_terminal(self, save_history=True): """ @@ -518,7 +520,7 @@ def terminal_main_display(self, tokens, extra_commands=None, save_history=True): lib.output.error( "must provide at least LHOST, LPORT, workspace name with `{}` keyword " "(IE {} 127.0.0.1 9076 default [whitelist-path] [honeycheck])".format( - choice.strip(), choice.strip() + choice.split(" ")[0].strip(), choice.split(" ")[0].strip() ) ) else: @@ -574,7 +576,7 @@ def terminal_main_display(self, tokens, extra_commands=None, save_history=True): lib.output.error( "must provide a list of API names after `{}` keyword and query " "(IE {} shodan,censys apache2)".format( - choice.strip(), choice.strip() + choice.split(" ")[0].strip(), choice.split(" ")[0].strip() ) ) else: @@ -605,7 +607,7 @@ def terminal_main_display(self, tokens, extra_commands=None, save_history=True): lib.output.error( "must supply API name with `{}` keyword along with " "new token (IE {} shodan mytoken123 [userID (censys)])".format( - choice.strip(), choice.strip() + choice.split(" ")[0].strip(), choice.split(" ")[0].strip() ) ) else: From e89abd07bbe8d77b051e8a4e96c40025ce8358eb Mon Sep 17 00:00:00 2001 From: Ekultek Date: Thu, 27 Jun 2019 14:13:35 -0500 Subject: [PATCH 10/19] just making some minor updates here and there --- lib/exploitation/exploiter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index e53df58..3e7eb8b 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -40,7 +40,6 @@ class AutoSploitExploiter(object): sorted_modules = [] def __init__(self, configuration, all_modules, hosts=None, **kwargs): - self.hosts = hosts self.hosts = hosts self.configuration = configuration self.mods = all_modules From 2f0fb770f1b14ed4e3244372d85d9a34d37198cc Mon Sep 17 00:00:00 2001 From: Ekultek Date: Thu, 27 Jun 2019 14:14:15 -0500 Subject: [PATCH 11/19] just making some minor updates here and there --- lib/term/terminal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/term/terminal.py b/lib/term/terminal.py index 36f0857..5b9106a 100644 --- a/lib/term/terminal.py +++ b/lib/term/terminal.py @@ -316,7 +316,7 @@ def do_add_single_host(self, ip): Examples: --------- - single 89.76.12.124[89.76.12.43,89.90.65.78,...] + single 89.76.12.124[,89.76.12.43,89.90.65.78,...] """ for item in ip.split(","): validated_ip = lib.settings.validate_ip_addr(item) From 988160c118a822c28fee6a4f19d634ca4157338b Mon Sep 17 00:00:00 2001 From: Ekultek Date: Thu, 27 Jun 2019 16:09:31 -0500 Subject: [PATCH 12/19] port scanner is ready --- lib/scanner/nmap.py | 88 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 13 deletions(-) diff --git a/lib/scanner/nmap.py b/lib/scanner/nmap.py index 1797fec..3daab79 100644 --- a/lib/scanner/nmap.py +++ b/lib/scanner/nmap.py @@ -1,13 +1,58 @@ -import io +""" + +********************************************************************************************* +* NOTICE FROM AUTOSPLOIT DEVELOPERS * +********************************************************************************************* +* this is basically an exact copy of * +* `https://github.com/komand/python-nmap/blob/master/nmap/nmap.py` that has been modified * +* to better fit into autosploits development. There has been very minimal changes to it * +* and it still basically functions the exact same way * +********************************************************************************************* + + +ORIGINAL INFO: +-------------- +nmap.py - version and date, see below +Source code : https://bitbucket.org/xael/python-nmap +Author : +* Alexandre Norman - norman at xael.org +Contributors: +* Steve 'Ashcrow' Milner - steve at gnulinux.net +* Brian Bustin - brian at bustin.us +* old.schepperhand +* Johan Lundberg +* Thomas D. maaaaz +* Robert Bost +* David Peltier +Licence: GPL v3 or any later version for python-nmap +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program. If not, see . +************** +IMPORTANT NOTE +************** +The Nmap Security Scanner used by python-nmap is distributed +under it's own licence that you can find at https://svn.nmap.org/nmap/COPYING +Any redistribution of python-nmap along with the Nmap Security Scanner +must conform to the Nmap Security Scanner licence + +__author__ = 'Alexandre Norman (norman@xael.org)' +__version__ = '0.6.2' +__last_modification__ = '2017.01.07' +""" + import os -import re -import csv -import sys import shlex import subprocess from xml.etree import ElementTree -from multiprocessing import Process import lib.jsonize import lib.errors @@ -45,7 +90,11 @@ def do_scan(host, nmap_path, ports=None, arguments=None): nmap_path, '-oX', '-', host, '-p ' + ports if ports is not None else "", ] + arguments_list - lib.output.info("launching nmap scan against {} ({})".format(host, " ".join(launch_arguments))) + to_launch = [] + for item in launch_arguments: + if not item == "": + to_launch.append(item) + lib.output.info("launching nmap scan against {} ({})".format(host, " ".join(to_launch))) process = subprocess.Popen( launch_arguments, bufsize=10000, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE @@ -127,24 +176,24 @@ def parse_xml_output(output, warnings, error): results['nmap_scan'][host]['addresses'] = addresses results['nmap_scan'][host]['vendors'] = vendors - print results;exit(1) - for status in attempted_host.findall('status'): - results['nmap_scan'][attempted_host]['status'] = { + results['nmap_scan'][host]['status'] = { 'state': status.get('state'), 'reason': status.get('reason') } for uptime in attempted_host.findall('uptime'): - results['nmap_scan'][attempted_host]['uptime'] = { + results['nmap_scan'][host]['uptime'] = { 'seconds': uptime.get('seconds'), 'lastboot': uptime.get('lastboot') } for discovered_port in attempted_host.findall('ports/port'): protocol = discovered_port.get('protocol') port_number = discovered_port.get('portid') - port_state = discovered_port.find('state').get('reason') + port_state = discovered_port.find('state').get('state') + port_reason = discovered_port.find('state').get('reason') - # damn I didn't even know you could do this! + # this is actually a thing!! + name = discovered_config = discovered_version = extra_information = discovered_product = stuff = "" for discovered_name in discovered_port.findall('service'): name = discovered_name.get('name') if discovered_name.get('product'): @@ -153,4 +202,17 @@ def parse_xml_output(output, warnings, error): discovered_version = discovered_name.get('version') if discovered_name.get('extrainfo'): extra_information = discovered_name.get('extrainfo') - print results \ No newline at end of file + if discovered_name.get('conf'): + discovered_config = discovered_name.get('conf') + + for other_stuff in discovered_name.findall('cpe'): + stuff = other_stuff.text + if protocol not in results['nmap_scan'][host].keys(): + results['nmap_scan'][host][protocol] = list() + results['nmap_scan'][host][protocol].append({ + 'port': port_number, 'state': port_state, 'reason': port_reason, + 'name': name, 'product': discovered_product, 'version': discovered_version, + 'extrainfo': extra_information, 'conf': discovered_config, 'cpe': stuff + }) + + return results From d5ff732bc1d1c4da57723bae256181fd2d1b8c0b Mon Sep 17 00:00:00 2001 From: Ekultek Date: Tue, 3 Sep 2019 16:20:52 -0500 Subject: [PATCH 13/19] fix for issue #1058 --- lib/term/terminal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/term/terminal.py b/lib/term/terminal.py index 5b9106a..3688794 100644 --- a/lib/term/terminal.py +++ b/lib/term/terminal.py @@ -282,7 +282,7 @@ def do_api_search(self, requested_api_data, query, tokens): proxy=proxy, agent=agent ).search() - except lib.errors.AutoSploitAPIConnectionError as e: + except (lib.errors.AutoSploitAPIConnectionError, Exception) as e: lib.settings.stop_animation = True lib.output.error("error searching API: '{}', error message: '{}'".format(api, str(e))) lib.settings.stop_animation = True From e37765eb27a9d4ab6cf199fc466a77837040cdbe Mon Sep 17 00:00:00 2001 From: Ekultek Date: Tue, 3 Sep 2019 16:25:33 -0500 Subject: [PATCH 14/19] fix for issue #1059 --- lib/settings.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/settings.py b/lib/settings.py index 8a58a3e..4b6666a 100644 --- a/lib/settings.py +++ b/lib/settings.py @@ -310,15 +310,18 @@ def cmdline(command, is_msf=True): split_cmd = [x.strip() for x in command.split(" ") if x] sys.stdout.flush() - - proc = Popen(split_cmd, stdout=PIPE, bufsize=1) stdout_buff = [] - for stdout_line in iter(proc.stdout.readline, b''): - stdout_buff += [stdout_line.rstrip()] - if is_msf: - print("(msf)>> {}".format(stdout_line).rstrip()) - else: - print("{}".format(stdout_line).rstrip()) + + try: + proc = Popen(split_cmd, stdout=PIPE, bufsize=1) + for stdout_line in iter(proc.stdout.readline, b''): + stdout_buff += [stdout_line.rstrip()] + if is_msf: + print("(msf)>> {}".format(stdout_line).rstrip()) + else: + print("{}".format(stdout_line).rstrip()) + except OSError as e: + stdout_buff += "ERROR: " + e return stdout_buff From d5df08e99b1ef655a676dc714a804efdb03f721d Mon Sep 17 00:00:00 2001 From: Ekultek Date: Tue, 3 Sep 2019 16:27:06 -0500 Subject: [PATCH 15/19] fix for issue #1060 --- lib/term/terminal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/term/terminal.py b/lib/term/terminal.py index 3688794..64d0cd8 100644 --- a/lib/term/terminal.py +++ b/lib/term/terminal.py @@ -562,7 +562,7 @@ def terminal_main_display(self, tokens, extra_commands=None, save_history=True): print(self.do_load_custom_hosts.__doc__) except TypeError: pass - if len(choice_data_list) == 1: + if choice_data_list is not None and len(choice_data_list) == 1: lib.output.error("must provide full path to file after `{}` keyword".format(choice)) else: self.do_load_custom_hosts(choice_data_list[-1]) From 0c2319de85bc1dda9be7b1674519eebd9e52fcef Mon Sep 17 00:00:00 2001 From: Ekultek Date: Tue, 3 Sep 2019 16:28:40 -0500 Subject: [PATCH 16/19] fix for issue #1061 --- lib/exploitation/exploiter.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index 3e7eb8b..f5863a8 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -123,7 +123,10 @@ def start_exploit(self, sep="*" * 10): if not skip: current_host_path = path.join(current_run_path, host.strip()) - makedirs(current_host_path) + try: + makedirs(current_host_path) + except OSError: + pass for mod in self.mods: if not self.dry_run: From c8979aa3898246ecc0da4c8e1d29c17dc9f3ff83 Mon Sep 17 00:00:00 2001 From: Ekultek Date: Tue, 3 Sep 2019 16:36:46 -0500 Subject: [PATCH 17/19] fix for issue #1150 --- lib/term/terminal.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/term/terminal.py b/lib/term/terminal.py index 64d0cd8..d95fd32 100644 --- a/lib/term/terminal.py +++ b/lib/term/terminal.py @@ -187,6 +187,12 @@ def do_token_reset(self, api, token, username): Censys -> reset/tokens censys Shodan -> reset.tokens shodan """ + import sys + + if sys.version_info > (3,): + token = token.encode("utf-8") + username = username.encode("utf-8") + if api.lower() == "censys": lib.output.info("resetting censys API credentials") with open(lib.settings.API_KEYS["censys"][0], 'w') as token_: From 40d1bbd63a6535c7d6ecedf47e3d94dd50c833f6 Mon Sep 17 00:00:00 2001 From: Ekultek Date: Tue, 3 Sep 2019 16:39:05 -0500 Subject: [PATCH 18/19] fix for issue #1159 --- lib/term/terminal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/term/terminal.py b/lib/term/terminal.py index d95fd32..ce7f232 100644 --- a/lib/term/terminal.py +++ b/lib/term/terminal.py @@ -66,7 +66,7 @@ def __init__(self, tokens, modules): self.modules = modules try: self.loaded_hosts = open(lib.settings.HOST_FILE).readlines() - except IOError: + except (IOError, Exception): lib.output.warning("no hosts file present") self.loaded_hosts = open(lib.settings.HOST_FILE, "a+").readlines() From 5d9446a00b50e5bcaf1a58f61cfbb8a65ea343bd Mon Sep 17 00:00:00 2001 From: Ekultek Date: Tue, 3 Sep 2019 16:40:42 -0500 Subject: [PATCH 19/19] bumps version number --- lib/banner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/banner.py b/lib/banner.py index bb272a2..2588164 100644 --- a/lib/banner.py +++ b/lib/banner.py @@ -1,7 +1,7 @@ import os import random -VERSION = "3.1.4" +VERSION = "3.1.5" def banner_1(line_sep="#--", space=" " * 30):