From 3341a6bb063b19c70238f3fe8a0786b55d25a1bf Mon Sep 17 00:00:00 2001 From: DarkC0ntributor <102583472+DarkC0ntributor@users.noreply.github.com> Date: Fri, 24 Jun 2022 12:56:15 +0200 Subject: [PATCH 1/4] add filer to config --- C2_Profiles/http/c2_code/config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/C2_Profiles/http/c2_code/config.json b/C2_Profiles/http/c2_code/config.json index 20b98c7..e8a193d 100755 --- a/C2_Profiles/http/c2_code/config.json +++ b/C2_Profiles/http/c2_code/config.json @@ -13,6 +13,9 @@ "cert_path": "fullchain.pem", "debug": false, "use_ssl": false, + "allowed_ips": [], + "get_uri":"/", + "post_uri":"/", "payloads": {} } ] From f12d02df8a584a7968c4346619e46be21b3cdbb6 Mon Sep 17 00:00:00 2001 From: DarkC0ntributor <102583472+DarkC0ntributor@users.noreply.github.com> Date: Fri, 24 Jun 2022 12:58:07 +0200 Subject: [PATCH 2/4] add optional filter on URI and IP --- C2_Profiles/http/c2_code/server | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/C2_Profiles/http/c2_code/server b/C2_Profiles/http/c2_code/server index 35c0ed5..faa8fee 100755 --- a/C2_Profiles/http/c2_code/server +++ b/C2_Profiles/http/c2_code/server @@ -33,7 +33,7 @@ def server_error_handler(request, exception): async def download_file(request, **kwargs): try: if config[request.app.name]['debug']: - await print_flush("agent_message request from: {} with {} and {}".format(request.url, request.cookies, request.headers)) + await print_flush("download_file request from: {} with {} and {}".format(request.url, request.cookies, request.headers)) await print_flush(config[request.app.name]['payloads']) await print_flush(request.path) if config[request.app.name]['debug']: @@ -56,6 +56,10 @@ async def agent_message(request, **kwargs): if config[request.app.name]['debug']: await print_flush("agent_message request from: {} with {} and {}".format(request.url, request.cookies, request.headers)) await print_flush(" and URI: {}".format(request.query_string)) + ip_wl = config[request.app.name]['allowed_ips'] + if len(ip_wl)>0: + if request.ip not in ip_wl: + raise ValueError(f"IP {request.ip} not whitelisted") if config[request.app.name]['debug']: await print_flush("Forwarding along to: {}".format(config['mythic_address'])) if request.method == "POST": @@ -145,6 +149,7 @@ if __name__ == "__main__": # now look at the specific instances to start for inst in main_config['instances']: config[str(inst['port'])] = {'debug': inst['debug'], + 'allowed_ips': inst['allowed_ips'], 'headers': inst['ServerHeaders'], 'payloads': {}} if inst['debug']: @@ -161,8 +166,8 @@ if __name__ == "__main__": for k, v in inst["payloads"].items(): config[str(inst["port"])]["payloads"][f"{k}"] = v app.add_route(download_file, f"{k}", methods=["GET"]) - app.add_route(agent_message, "/", methods=['GET','POST']) - app.add_route(agent_message, "/", methods=['GET','POST']) + app.add_route(agent_message, inst.get("get_uri","/"), methods=['GET']) + app.add_route(agent_message, inst.get("post_uri","/"), methods=['POST']) app.error_handler.add(Exception, server_error_handler) keyfile = Path(inst['key_path']) certfile = Path(inst['cert_path']) From 8fc153a3294ac73ef3b29b0e7a218af8fdefcb8d Mon Sep 17 00:00:00 2001 From: DarkC0ntributor <102583472+DarkC0ntributor@users.noreply.github.com> Date: Mon, 27 Jun 2022 14:47:29 +0200 Subject: [PATCH 3/4] add verbose parameter --- C2_Profiles/http/c2_code/config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/C2_Profiles/http/c2_code/config.json b/C2_Profiles/http/c2_code/config.json index e8a193d..84911f3 100755 --- a/C2_Profiles/http/c2_code/config.json +++ b/C2_Profiles/http/c2_code/config.json @@ -12,6 +12,7 @@ "key_path": "privkey.pem", "cert_path": "fullchain.pem", "debug": false, + "verbose": true, "use_ssl": false, "allowed_ips": [], "get_uri":"/", From 0efe31e265c6515b8b1ac5df5969878814ae8340 Mon Sep 17 00:00:00 2001 From: DarkC0ntributor <102583472+DarkC0ntributor@users.noreply.github.com> Date: Mon, 27 Jun 2022 14:58:44 +0200 Subject: [PATCH 4/4] Request logging of verbose, IP filter with subnets --- C2_Profiles/http/c2_code/server | 46 +++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/C2_Profiles/http/c2_code/server b/C2_Profiles/http/c2_code/server index faa8fee..b1cff53 100755 --- a/C2_Profiles/http/c2_code/server +++ b/C2_Profiles/http/c2_code/server @@ -13,6 +13,26 @@ import os import aiohttp from OpenSSL import crypto, SSL import random +from ipaddress import ip_network,ip_address +from mythic_c2_container.MythicCallbackRPC import MythicCallbackRPC, MythicRPCResponse +from aio_pika.patterns import RPC + +async def rpc_call(function_name: str, **func_kwargs): + mrpc = MythicCallbackRPC() + await mrpc.connect() + rpc = await RPC.create(mrpc.channel) + func = getattr(rpc.proxy, function_name) + if func is not None and callable(func): + output = await func(**func_kwargs) + else: + output = await rpc.call(function_name, kwargs=dict(**func_kwargs)) + return output + +async def report_error(message, request): + await rpc_call("create_event_message", + message=f"HTTP C2: {message}\n{request.url}?{request.query_string}\nFrom: {request.ip}\n{request.headers}", + warning=True) + config = {} @@ -22,11 +42,17 @@ async def print_flush(message): session = aiohttp.ClientSession() -def server_error_handler(request, exception): +async def server_error_handler(request, exception): + global config if request is None: print("Invalid HTTP Method - Likely HTTPS trying to talk to HTTP") sys.stdout.flush() return html("Error: Failed to process request", status=500, headers={}) + else: + if isinstance(exception, NotFound): + if config[request.app.name]['verbose']: + await report_error(f"Path '{request.path}' is not whitelisted",request) + return html("Error: Requested URL {} not found".format(request.url), status=404, headers=config[request.app.name]['headers']) @@ -58,7 +84,13 @@ async def agent_message(request, **kwargs): await print_flush(" and URI: {}".format(request.query_string)) ip_wl = config[request.app.name]['allowed_ips'] if len(ip_wl)>0: - if request.ip not in ip_wl: + ip = ip_address(request.ip) + for net in ip_wl: + if ip in net: + break + else: + if config[request.app.name]['verbose']: + await report_error(f"IP {request.ip} not whitelisted", request) raise ValueError(f"IP {request.ip} not whitelisted") if config[request.app.name]['debug']: await print_flush("Forwarding along to: {}".format(config['mythic_address'])) @@ -76,9 +108,6 @@ async def agent_message(request, **kwargs): async with session.get(config['mythic_address'] + "?{}".format(request.query_string), data=request.body, ssl=False, headers={"Mythic": "http", **request.headers, **forwarded_headers}) as resp: return raw(await resp.read(), status=resp.status, headers=config[request.app.name]['headers']) except Exception as e: - if request is None: - await print_flush("Invalid HTTP Method - Likely HTTPS trying to talk to HTTP") - return server_error_handler(request, e) if config[request.app.name]['debug']: await print_flush("error in agent_message: {}".format(str(e))) return server_error_handler(request, e) @@ -149,7 +178,8 @@ if __name__ == "__main__": # now look at the specific instances to start for inst in main_config['instances']: config[str(inst['port'])] = {'debug': inst['debug'], - 'allowed_ips': inst['allowed_ips'], + 'allowed_ips': list(map(ip_network,inst['allowed_ips'])), + 'verbose': inst['verbose'], 'headers': inst['ServerHeaders'], 'payloads': {}} if inst['debug']: @@ -166,8 +196,8 @@ if __name__ == "__main__": for k, v in inst["payloads"].items(): config[str(inst["port"])]["payloads"][f"{k}"] = v app.add_route(download_file, f"{k}", methods=["GET"]) - app.add_route(agent_message, inst.get("get_uri","/"), methods=['GET']) - app.add_route(agent_message, inst.get("post_uri","/"), methods=['POST']) + app.add_route(agent_message, inst.get("get_uri","/"), methods=['GET']) + app.add_route(agent_message, inst.get("post_uri","/"), methods=['POST']) app.error_handler.add(Exception, server_error_handler) keyfile = Path(inst['key_path']) certfile = Path(inst['cert_path'])