From 2114c2f09bc500bf8d6db446952f93df3204a06b Mon Sep 17 00:00:00 2001 From: Cody Thomas Date: Thu, 7 Oct 2021 17:35:30 -0700 Subject: [PATCH] Fixed an issue with hijackable websockets in Firefox if a user is already logged into Mythic and navigates to a compromised website. Issue discovered by @BillDemirkapi on 10/7/2021 and fixed on 10/7/2021 --- README.md | 2 +- mythic-docker/app/routes/routes.py | 29 ++++++++++++++++++--------- mythic-docker/app/templates/base.html | 6 +++++- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index fc455bed3..0e98e6926 100755 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A cross-platform, post-exploit, red teaming framework built with python3, docker * Objective By the Sea 2019 talk on JXA: https://objectivebythesea.com/v2/talks/OBTS_v2_Thomas.pdf * Objective By the sea 2019 Video: https://www.youtube.com/watch?v=E-QEsGsq3uI&list=PLliknDIoYszvTDaWyTh6SYiTccmwOsws8&index=17 -* Current Version: 2.2.13 +* Current Version: 2.2.14 ## Installing Agents and C2 Profiles diff --git a/mythic-docker/app/routes/routes.py b/mythic-docker/app/routes/routes.py index 6d96ff374..9091ee961 100755 --- a/mythic-docker/app/routes/routes.py +++ b/mythic-docker/app/routes/routes.py @@ -183,12 +183,18 @@ async def post(self, request): resp.cookies[self.config.cookie_access_token_name()][ "httponly" ] = True + resp.cookies[self.config.cookie_access_token_name()][ + "samesite" + ] = "strict" resp.cookies[ self.config.cookie_refresh_token_name() ] = refresh_token resp.cookies[self.config.cookie_refresh_token_name()][ "httponly" ] = True + resp.cookies[self.config.cookie_refresh_token_name()][ + "samesite" + ] = "strict" return resp except Exception as e: print(str(sys.exc_info()[-1].tb_lineno) + " " + str(e)) @@ -296,6 +302,14 @@ async def logout(request, user): return resp +@mythic.exception(asyncio.CancelledError) +async def handle_cancellation(request, exception): + logger.info( + "Request {} was cancelled".format(str(request)) + ) + return json({"status": "error", "error": "Request was cancelled"}, status=500) + + @mythic.exception(NotFound) async def handler_404(request, exception): return json({"status": "error", "error": "Not Found"}, status=404) @@ -329,7 +343,6 @@ async def handler_auth_failed(request, exception): @mythic.exception(SanicException) def catch_all(request, exception): - logger.exception( "Caught random exception within Mythic: {}, {}".format(exception, str(request)) ) @@ -351,36 +364,34 @@ async def check_ips(request): @mythic.middleware("response") async def add_cors(request, response): - response.headers["Access-Control-Allow-Origin"] = "*" - response.headers["Access-Control-Allow-Methods"] = "*" - response.headers["Access-Control-Allow-Credentials"] = "true" response.headers["Access-Control-Allow-Headers"] = "authorization,content-type" @mythic.listener("before_server_start") async def setup_initial_info(sanic, loop): + logger.info("setup_initial_info") app.db_objects = Manager(mythic_db, loop=loop) await mythic_db.connect_async(loop=loop) app.db_objects.database.allow_sync = True # logging.WARNING await initial_setup() - await app.api.rabbitmq_api.start_listening() + asyncio.create_task(app.api.rabbitmq_api.start_listening()) async def initial_setup(): # create mythic_admin import multiprocessing try: - max_worker_connection = int(400 / (multiprocessing.cpu_count() + 1)) + max_worker_connection = int(200 / (multiprocessing.cpu_count() + 1)) app.websocket_pool = await asyncpg.create_pool(mythic.config["DB_POOL_ASYNCPG_CONNECT_STRING"], max_size=max_worker_connection) # redis automatically creates a pool behind the scenes - app.redis_pool = redis.Redis(host=app.redis_host, port=app.redis_port, db=0) + app.redis_pool = redis.Redis(host=app.redis_host, port=app.redis_port, db=3) # clear the database on start keys = app.redis_pool.keys("*") for k in keys: app.redis_pool.delete(k) - operators = await app.db_objects.execute(Operator.select()) - if len(operators) != 0: + operators = await app.db_objects.count(Operator.select()) + if operators > 0: logger.info("Users already exist, aborting initial install") return salt = str(uuid4()) diff --git a/mythic-docker/app/templates/base.html b/mythic-docker/app/templates/base.html index 6970892a7..79047734f 100755 --- a/mythic-docker/app/templates/base.html +++ b/mythic-docker/app/templates/base.html @@ -712,6 +712,9 @@ [[ messages.length ]] - v2.2.13 + v2.2.14 {% endif %}