Skip to content

Commit fe6e345

Browse files
committed
created an automatic issue creator
1 parent b45e473 commit fe6e345

File tree

7 files changed

+284
-126
lines changed

7 files changed

+284
-126
lines changed

autosploit/main.py

Lines changed: 88 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
from lib.cmdline.cmd import AutoSploitParser
88
from lib.term.terminal import AutoSploitTerminal
9+
from lib.creation.issue_creator import (
10+
request_issue_creation,
11+
hide_sensitive
12+
)
913
from lib.output import (
1014
info,
1115
warning,
@@ -18,9 +22,9 @@
1822
check_services,
1923
cmdline,
2024
close,
21-
download_modules_list,
2225
EXPLOIT_FILES_PATH,
23-
START_SERVICES_PATH
26+
START_SERVICES_PATH,
27+
save_error_to_file,
2428
)
2529
from lib.jsonize import (
2630
load_exploits,
@@ -29,91 +33,99 @@
2933

3034

3135
def main():
32-
3336
try:
34-
is_admin = os.getuid() == 0
35-
except AttributeError:
36-
# we'll make it cross platform because it seems like a cool idea
37-
is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
3837

39-
if not is_admin:
40-
close("must have admin privileges to run")
38+
try:
39+
is_admin = os.getuid() == 0
40+
except AttributeError:
41+
# we'll make it cross platform because it seems like a cool idea
42+
is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
4143

42-
opts = AutoSploitParser().optparser()
44+
if not is_admin:
45+
close("must have admin privileges to run")
4346

44-
if opts.downloadModules is not None:
45-
info("downloading modules")
46-
for search in opts.downloadModules:
47-
downloaded = download_modules_list(search)
48-
info("downloaded {} file(s)".format(len(downloaded)))
49-
for f in downloaded:
50-
print("=> {}".format(f))
51-
info("new exploit paths have been added to JSON files, re-run autosploit to access them")
52-
exit(1)
47+
opts = AutoSploitParser().optparser()
5348

54-
logo()
55-
info("welcome to autosploit, give us a little bit while we configure")
56-
misc_info("checking your running platform")
57-
platform_running = platform.system()
58-
misc_info("checking for disabled services")
59-
# according to ps aux, postgre and apache2 are the names of the services on Linux systems
60-
service_names = ("postgres", "apache2")
61-
if "darwin" in platform_running.lower():
62-
service_names = ("postgres", "apachectl")
49+
logo()
50+
info("welcome to autosploit, give us a little bit while we configure")
51+
misc_info("checking your running platform")
52+
platform_running = platform.system()
53+
misc_info("checking for disabled services")
54+
# according to ps aux, postgre and apache2 are the names of the services on Linux systems
55+
service_names = ("postgres", "apache2")
56+
if "darwin" in platform_running.lower():
57+
service_names = ("postgres", "apachectl")
6358

64-
for service in list(service_names):
65-
while not check_services(service):
66-
choice = prompt(
67-
"it appears that service {} is not enabled, would you like us to enable it for you[y/N]".format(
68-
service.title()
59+
for service in list(service_names):
60+
while not check_services(service):
61+
choice = prompt(
62+
"it appears that service {} is not enabled, would you like us to enable it for you[y/N]".format(
63+
service.title()
64+
)
6965
)
70-
)
71-
if choice.lower().startswith("y"):
72-
try:
73-
if "darwin" in platform_running.lower():
74-
cmdline("{} darwin".format(START_SERVICES_PATH))
75-
elif "linux" in platform_running.lower():
76-
cmdline("{} linux".format(START_SERVICES_PATH))
77-
else:
78-
close("your platform is not supported by AutoSploit at this time", status=2)
66+
if choice.lower().startswith("y"):
67+
try:
68+
if "darwin" in platform_running.lower():
69+
cmdline("{} darwin".format(START_SERVICES_PATH))
70+
elif "linux" in platform_running.lower():
71+
cmdline("{} linux".format(START_SERVICES_PATH))
72+
else:
73+
close("your platform is not supported by AutoSploit at this time", status=2)
7974

80-
# moving this back because it was funky to see it each run
81-
info("services started successfully")
82-
# this tends to show up when trying to start the services
83-
# I'm not entirely sure why, but this fixes it
84-
except psutil.NoSuchProcess:
85-
pass
86-
else:
87-
process_start_command = "`sudo service {} start`"
88-
if "darwin" in platform_running.lower():
89-
process_start_command = "`brew services start {}`"
90-
close(
91-
"service {} is required to be started for autosploit to run successfully (you can do it manually "
92-
"by using the command {}), exiting".format(
93-
service.title(), process_start_command.format(service)
75+
# moving this back because it was funky to see it each run
76+
info("services started successfully")
77+
# this tends to show up when trying to start the services
78+
# I'm not entirely sure why, but this fixes it
79+
except psutil.NoSuchProcess:
80+
pass
81+
else:
82+
process_start_command = "`sudo service {} start`"
83+
if "darwin" in platform_running.lower():
84+
process_start_command = "`brew services start {}`"
85+
close(
86+
"service {} is required to be started for autosploit to run successfully (you can do it manually "
87+
"by using the command {}), exiting".format(
88+
service.title(), process_start_command.format(service)
89+
)
9490
)
95-
)
9691

97-
if len(sys.argv) > 1:
98-
info("attempting to load API keys")
99-
loaded_tokens = load_api_keys()
100-
AutoSploitParser().parse_provided(opts)
92+
if len(sys.argv) > 1:
93+
info("attempting to load API keys")
94+
loaded_tokens = load_api_keys()
95+
AutoSploitParser().parse_provided(opts)
96+
97+
if not opts.exploitFile:
98+
misc_info("checking if there are multiple exploit files")
99+
loaded_exploits = load_exploits(EXPLOIT_FILES_PATH)
100+
else:
101+
loaded_exploits = load_exploit_file(opts.exploitFile)
102+
misc_info("Loaded {} exploits from {}.".format(
103+
len(loaded_exploits),
104+
opts.exploitFile))
101105

102-
if not opts.exploitFile:
106+
AutoSploitParser().single_run_args(opts, loaded_tokens, loaded_exploits)
107+
else:
108+
warning(
109+
"no arguments have been parsed, defaulting to terminal session. "
110+
"press 99 to quit and help to get help"
111+
)
103112
misc_info("checking if there are multiple exploit files")
104113
loaded_exploits = load_exploits(EXPLOIT_FILES_PATH)
105-
else:
106-
loaded_exploits = load_exploit_file(opts.exploitFile)
107-
misc_info("Loaded {} exploits from {}.".format(
108-
len(loaded_exploits),
109-
opts.exploitFile))
114+
info("attempting to load API keys")
115+
loaded_tokens = load_api_keys()
116+
terminal = AutoSploitTerminal(loaded_tokens)
117+
terminal.terminal_main_display(loaded_exploits)
118+
except Exception as e:
119+
import traceback
120+
121+
print(
122+
"\033[31m[!] AutoSploit has hit an unhandled exception: '{}', "
123+
"in order for the developers to troubleshoot and repair the "
124+
"issue AutoSploit will need to gather your OS information, metasploit version, "
125+
"current arguments, the error message, and a traceback. "
126+
"None of this information can be used to identify you in any way\033[0m".format(str(e))
127+
)
128+
error_traceback = ''.join(traceback.format_tb(sys.exc_info()[2]))
129+
error_file = save_error_to_file(str(error_traceback))
130+
request_issue_creation(error_file, hide_sensitive(), str(e))
110131

111-
AutoSploitParser().single_run_args(opts, loaded_tokens, loaded_exploits)
112-
else:
113-
warning("no arguments have been parsed, defaulting to terminal session. press 99 to quit and help to get help")
114-
misc_info("checking if there are multiple exploit files")
115-
loaded_exploits = load_exploits(EXPLOIT_FILES_PATH)
116-
info("attempting to load API keys")
117-
loaded_tokens = load_api_keys()
118-
terminal = AutoSploitTerminal(loaded_tokens)
119-
terminal.terminal_main_display(loaded_exploits)

etc/text_files/auth.key

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Vm0wd2VFMUdiRmhTV0d4V1YwZG9XVll3WkRSV1ZteHlWMjVrVlUxV2NIbFdNalZyWVZVeFYxZHVhRmRTZWtFeFZtMTRTMk15VGtsaFJscHBWa1ZhU1ZkV1VrZFRNazE0Vkc1V2FsSnRhRzlVVmxwWFRrWmFjbHBFVWxwV2JIQllWVEkxVDFkSFNraFZiR2hhWVRGYU0xWXhXbUZqTVZwMFVteG9hVlpyV1hwV1IzaGhZekZhU0ZOclpGaGlSMmhvVm1wT1UyRkdiRlpYYlhScVlrWmFlVlV5Y3pGV01rcEpVV3hzVjFaNlJUQlpla3BIWXpGT2MxWnNaR2xTYTNCWFZtMHhOR1F3TUhoalJXaHNVakJhVlZWc1VsZFhiR1J5VjIxR2FGWnNjSHBaTUZadlZqRktjMk5HYUZwaGExcG9WbXBHYTJOc1pISlBWbVJPWWxkb1dsWXhXbE5TTVZwMFZtdGthbEpXY0ZsWmExVXhZMVpTVjFkdFJrNVdiRlkxV1ROd1YxWnJNVmRqUldSWFRXNUNTRlpxUm1GV01rNUhWRzFHVTFKV2NFVldiR1EwVVRGYVZrMVZWazVTUkVFNQ==:9

lib/creation/__init__.py

Whitespace-only changes.

lib/creation/issue_creator.py

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import re
2+
import sys
3+
import json
4+
import platform
5+
import hashlib
6+
import base64
7+
try:
8+
from urllib2 import Request, urlopen
9+
except ImportError:
10+
from urllib.request import Request, urlopen
11+
12+
import requests
13+
from bs4 import BeautifulSoup
14+
15+
import lib.settings
16+
import lib.output
17+
import lib.banner
18+
19+
try:
20+
raw_input
21+
except NameError:
22+
raw_input = input
23+
24+
25+
def create_identifier(data):
26+
obj = hashlib.sha1()
27+
try:
28+
obj.update(data)
29+
except:
30+
obj.update(data.encode("utf-8"))
31+
return obj.hexdigest()[1:10]
32+
33+
34+
def get_token(path):
35+
"""
36+
we know what this is for
37+
"""
38+
with open(path) as _token:
39+
data = _token.read()
40+
token, n = data.split(":")
41+
for _ in range(int(n)):
42+
token = base64.b64decode(token)
43+
return token
44+
45+
46+
def ensure_no_issue(param):
47+
"""
48+
ensure that there is not already an issue that has been created for yours
49+
"""
50+
urls = (
51+
"https://github.com/NullArray/AutoSploit/issues",
52+
"https://github.com/NullArray/AutoSploit/issues?q=is%3Aissue+is%3Aclosed"
53+
)
54+
for url in urls:
55+
req = requests.get(url)
56+
param = re.compile(param)
57+
try:
58+
if param.search(req.content) is not None:
59+
return True
60+
except:
61+
content = str(req.content)
62+
if param.search(content) is not None:
63+
return True
64+
return False
65+
66+
67+
def find_url(params):
68+
"""
69+
get the URL that your issue is created at
70+
"""
71+
searches = (
72+
"https://github.com/NullArray/AutoSploit/issues",
73+
"https://github.com/NullArray/AutoSploit/issues?q=is%3Aissue+is%3Aclosed"
74+
)
75+
for search in searches:
76+
retval = "https://github.com{}"
77+
href = None
78+
searcher = re.compile(params, re.I)
79+
req = requests.get(search)
80+
status, html = req.status_code, req.content
81+
if status == 200:
82+
split_information = str(html).split("\n")
83+
for i, line in enumerate(split_information):
84+
if searcher.search(line) is not None:
85+
href = split_information[i - 1]
86+
if href is not None:
87+
soup = BeautifulSoup(href, "html.parser")
88+
for item in soup.findAll("a"):
89+
link = item.get("href")
90+
return retval.format(link)
91+
return None
92+
93+
94+
def hide_sensitive():
95+
sensitive = (
96+
"--proxy", "-P", "--personal-agent", "-q", "--query", "-C", "--config",
97+
"--whitelist", "--msf-path"
98+
)
99+
args = sys.argv
100+
for item in sys.argv:
101+
if item in sensitive:
102+
try:
103+
item_index = args.index(item) + 1
104+
hidden = ''.join([x.replace(x, "*") for x in str(args[item_index])])
105+
args.pop(item_index)
106+
args.insert(item_index, hidden)
107+
return ' '.join(args)
108+
except:
109+
return ' '.join([item for item in sys.argv])
110+
111+
112+
def request_issue_creation(path, arguments, error_message):
113+
"""
114+
request the creation and create the issue
115+
"""
116+
117+
question = raw_input(
118+
"do you want to create an anonymized issue?[y/N]: "
119+
)
120+
if question.lower().startswith("y"):
121+
# gonna read a chunk of it instead of one line
122+
chunk = 4096
123+
with open(path) as data:
124+
identifier = create_identifier(data.read(chunk))
125+
# gotta seek to the beginning of the file since it's already been read `4096` into it
126+
data.seek(0)
127+
issue_title = "Unhandled Exception ({})".format(identifier)
128+
129+
issue_data = {
130+
"title": issue_title,
131+
"body": (
132+
"Autosploit version: `{}`\n"
133+
"OS information: `{}`\n"
134+
"Running context: `{}`\n"
135+
"Error meesage: `{}`\n"
136+
"Error traceback:\n```\n{}\n```\n"
137+
"Metasploit launched: `{}`\n".format(
138+
lib.banner.VERSION,
139+
platform.platform(),
140+
' '.join(sys.argv),
141+
error_message,
142+
open(path).read(),
143+
lib.settings.MSF_LAUNCHED,
144+
)
145+
)
146+
}
147+
148+
_json_data = json.dumps(issue_data)
149+
if sys.version_info > (3,): # python 3
150+
_json_data = _json_data.encode("utf-8")
151+
152+
if not ensure_no_issue(identifier):
153+
req = Request(
154+
url="https://api.github.com/repos/nullarray/autosploit/issues", data=_json_data,
155+
headers={"Authorization": "token {}".format(get_token(lib.settings.TOKEN_PATH))}
156+
)
157+
urlopen(req, timeout=10).read()
158+
lib.output.info(
159+
"issue has been generated with the title '{}', at the following "
160+
"URL '{}'".format(
161+
issue_title, find_url(identifier)
162+
)
163+
)
164+
else:
165+
lib.output.error(
166+
"someone has already created this issue here: {}".format(find_url(identifier))
167+
)

lib/exploitation/exploiter.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def whitelist_wash(hosts, whitelist_file):
1919
whitelist_hosts = [x.strip() for x in open(whitelist_file).readlines() if x.strip()]
2020
lib.output.info('Found {} entries in whitelist.txt, scrubbing'.format(str(len(whitelist_hosts))))
2121
washed_hosts = []
22-
#return supplied hosts if whitelist file is empty
22+
# return supplied hosts if whitelist file is empty
2323
if len(whitelist_hosts) == 0:
2424
return hosts
2525
else:
@@ -70,6 +70,8 @@ def start_exploit(self, sep="*" * 10):
7070
if self.dry_run:
7171
lib.settings.close("dry run was initiated, exploitation will not be done")
7272

73+
lib.settings.MSF_LAUNCHED = True
74+
7375
today_printable = datetime.datetime.today().strftime("%Y-%m-%d_%Hh%Mm%Ss")
7476
current_run_path = path.join(lib.settings.RC_SCRIPTS_PATH, today_printable)
7577
makedirs(current_run_path)

0 commit comments

Comments
 (0)