From ca6d7d2ce0c3622cab8c4ecb35393dfd930ad7ac Mon Sep 17 00:00:00 2001 From: its-a-feature Date: Fri, 10 Apr 2026 09:35:59 -0500 Subject: [PATCH] fixed an issue with database connection exhaustion on errors --- CHANGELOG.MD | 7 +++++++ VERSION | 2 +- mythic-docker/src/rabbitmq/recv_c2_sync.go | 1 + .../src/rabbitmq/recv_mythic_rpc_artifact_search.go | 1 + .../rabbitmq/recv_mythic_rpc_callback_edge_search.go | 1 + .../src/rabbitmq/recv_mythic_rpc_callback_search.go | 1 + .../rabbitmq/recv_mythic_rpc_custombrowser_search.go | 1 + .../recv_mythic_rpc_payload_create_from_uuid.go | 2 ++ .../src/rabbitmq/recv_mythic_rpc_process_search.go | 1 + .../src/rabbitmq/recv_pt_payload_build_response.go | 1 + mythic-docker/src/rabbitmq/recv_pt_sync.go | 11 +++++++++++ mythic-docker/src/utils/config.go | 2 +- 12 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 73dc456c..4da31cda 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.4.33] - 2026-04-10 + +### Changed + +- Fixed an issue where payload/command syncing would error out and leave dangling database connections +- Updated the postgres docker image to use customized database info for health checks + ## [3.4.32] - 2026-04-06 ### Changed diff --git a/VERSION b/VERSION index 391fae89..9279b5d4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.4.32 \ No newline at end of file +3.4.33 \ No newline at end of file diff --git a/mythic-docker/src/rabbitmq/recv_c2_sync.go b/mythic-docker/src/rabbitmq/recv_c2_sync.go index dbfe93fe..13f23ff2 100644 --- a/mythic-docker/src/rabbitmq/recv_c2_sync.go +++ b/mythic-docker/src/rabbitmq/recv_c2_sync.go @@ -251,6 +251,7 @@ func updateC2Parameters(in C2SyncMessage, c2Profile databaseStructs.C2profile) e logging.LogError(err, "Failed to fetch c2 parameters for c2 profile when syncing") return err } else { + defer rows.Close() for rows.Next() { found := false if err = rows.StructScan(&databaseParameter); err != nil { diff --git a/mythic-docker/src/rabbitmq/recv_mythic_rpc_artifact_search.go b/mythic-docker/src/rabbitmq/recv_mythic_rpc_artifact_search.go index 13337a84..0d4cce6e 100644 --- a/mythic-docker/src/rabbitmq/recv_mythic_rpc_artifact_search.go +++ b/mythic-docker/src/rabbitmq/recv_mythic_rpc_artifact_search.go @@ -78,6 +78,7 @@ func MythicRPCArtifactSearch(input MythicRPCArtifactSearchMessage) MythicRPCArti response.Error = err.Error() return response } else { + defer rows.Close() for rows.Next() { result := MythicRPCArtifactSearchArtifactData{} searchResult := databaseStructs.Taskartifact{} diff --git a/mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_edge_search.go b/mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_edge_search.go index bef955a7..835ba257 100644 --- a/mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_edge_search.go +++ b/mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_edge_search.go @@ -66,6 +66,7 @@ func MythicRPCCallbackEdgeSearch(input MythicRPCCallbackEdgeSearchMessage) Mythi return response } searchResults := databaseStructs.Callbackgraphedge{} + defer rows.Close() for rows.Next() { result := MythicRPCCallbackEdgeSearchMessageResult{} err = rows.StructScan(&searchResults) diff --git a/mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_search.go b/mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_search.go index a43f9791..6915684a 100644 --- a/mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_search.go +++ b/mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_search.go @@ -181,6 +181,7 @@ func MythicRPCCallbackSearch(input MythicRPCCallbackSearchMessage) MythicRPCCall response.Error = err.Error() return response } + defer rows.Close() for rows.Next() { result := MythicRPCCallbackSearchMessageResult{} err = rows.StructScan(&searchResults) diff --git a/mythic-docker/src/rabbitmq/recv_mythic_rpc_custombrowser_search.go b/mythic-docker/src/rabbitmq/recv_mythic_rpc_custombrowser_search.go index 0566de67..3f880d68 100644 --- a/mythic-docker/src/rabbitmq/recv_mythic_rpc_custombrowser_search.go +++ b/mythic-docker/src/rabbitmq/recv_mythic_rpc_custombrowser_search.go @@ -137,6 +137,7 @@ func MythicRPCCustomBrowserSearch(input MythicRPCCustomBrowserSearchMessage) Myt response.Error = err.Error() return response } + defer rows.Close() for rows.Next() { searchResult := databaseStructs.MythicTree{} err = rows.StructScan(&searchResult) diff --git a/mythic-docker/src/rabbitmq/recv_mythic_rpc_payload_create_from_uuid.go b/mythic-docker/src/rabbitmq/recv_mythic_rpc_payload_create_from_uuid.go index bd71091b..6a4c6759 100644 --- a/mythic-docker/src/rabbitmq/recv_mythic_rpc_payload_create_from_uuid.go +++ b/mythic-docker/src/rabbitmq/recv_mythic_rpc_payload_create_from_uuid.go @@ -151,6 +151,7 @@ func associateBuildParametersWithPayload(databasePayload databaseStructs.Payload logging.LogError(err, "Failed to get build parameters from database when trying to build payload") return nil, err } + defer rows.Close() for rows.Next() { err = rows.StructScan(&databaseBuildParameter) if err != nil { @@ -298,6 +299,7 @@ func associateC2ProfilesWithPayload(databasePayload databaseStructs.Payload, c2P logging.LogError(err, "Failed to get c2 parameters from database when trying to build payload") return nil, err } + defer rows.Close() for rows.Next() { err = rows.StructScan(&databaseC2ProfileParameter) if err != nil { diff --git a/mythic-docker/src/rabbitmq/recv_mythic_rpc_process_search.go b/mythic-docker/src/rabbitmq/recv_mythic_rpc_process_search.go index dc7adf93..53f0a2c2 100644 --- a/mythic-docker/src/rabbitmq/recv_mythic_rpc_process_search.go +++ b/mythic-docker/src/rabbitmq/recv_mythic_rpc_process_search.go @@ -110,6 +110,7 @@ func MythicRPCProcessSearch(input MythicRPCProcessSearchMessage) MythicRPCProces response.Error = err.Error() return response } else { + defer rows.Close() for rows.Next() { searchResult := databaseStructs.MythicTree{} if err = rows.StructScan(&searchResult); err != nil { diff --git a/mythic-docker/src/rabbitmq/recv_pt_payload_build_response.go b/mythic-docker/src/rabbitmq/recv_pt_payload_build_response.go index ff5d6130..c62d0f30 100644 --- a/mythic-docker/src/rabbitmq/recv_pt_payload_build_response.go +++ b/mythic-docker/src/rabbitmq/recv_pt_payload_build_response.go @@ -157,6 +157,7 @@ func updateLoadedCommandsFromPayloadBuild(databasePayload databaseStructs.Payloa logging.LogError(err, "Failed to get payload commands when trying to update loaded commands for payload build response") return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&databasePayloadCommand); err != nil { logging.LogError(err, "Failed to get row from payloadcommand when trying to process payload build response") diff --git a/mythic-docker/src/rabbitmq/recv_pt_sync.go b/mythic-docker/src/rabbitmq/recv_pt_sync.go index a59e1351..6126c818 100644 --- a/mythic-docker/src/rabbitmq/recv_pt_sync.go +++ b/mythic-docker/src/rabbitmq/recv_pt_sync.go @@ -479,6 +479,7 @@ func updatePayloadTypeBuildParameters(in PayloadTypeSyncMessage, payloadtype dat logging.LogError(err, "Failed to fetch build parameters for payloadtype when syncing") return err } else { + defer rows.Close() for rows.Next() { found := false if err = rows.StructScan(&databaseParameter); err != nil { @@ -624,6 +625,7 @@ func updatePayloadTypeC2Profiles(in PayloadTypeSyncMessage, payloadtype database logging.LogError(err, "Failed to get payloadtypec2profile from database") return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&databaseC2Profile); err != nil { logging.LogError(err, "Failed to get row from payloadtypec2profile") @@ -684,6 +686,7 @@ func updatePayloadTypeWrappers(in PayloadTypeSyncMessage, payloadtype databaseSt logging.LogError(err, "Failed to get wrappedpayloadtypes from database") return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&databaseWrapper); err != nil { logging.LogError(err, "Failed to get row from wrappedpayloadtypes for importing new payloadtype") @@ -715,6 +718,7 @@ func updatePayloadTypeWrappers(in PayloadTypeSyncMessage, payloadtype databaseSt logging.LogError(err, "Failed to get wrappedpayloadtypes from database") return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&databaseWrapper); err != nil { logging.LogError(err, "Failed to get row from wrappedpayloadtypes for importing new payloadtype") @@ -815,6 +819,7 @@ func updatePayloadTypeCommands(in PayloadTypeSyncMessage, payloadtype databaseSt logging.LogError(err, "Failed to fetch commands for payloadtype when syncing") return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&databaseCommand); err != nil { logging.LogError(err, "Failed to parse command into structure when syncing payloadtype") @@ -981,6 +986,7 @@ func updatePayloadTypeCommandParameters(in PayloadTypeSyncMessage, payloadtype d logging.LogError(err, "Failed to fetch command parameters for command when syning") return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&databaseParameter); err != nil { logging.LogError(err, "Failed to parse commandparameter into structure when syncing command") @@ -1142,6 +1148,7 @@ func updatePayloadTypeCommandBrowserScripts(in PayloadTypeSyncMessage, syncComma return err } else { found := false + defer rows.Close() for rows.Next() { if err = rows.StructScan(&databaseBrowserScript); err != nil { logging.LogError(err, "Failed to parse browserscript into structure when syncing command") @@ -1212,6 +1219,7 @@ func addBrowserScriptToAllOperators(browserscript databaseStructs.Browserscript) logging.LogError(err, "Failed to get operators") return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&operator); err != nil { logging.LogError(err, "Failed to parse operator into structure") @@ -1241,6 +1249,7 @@ func updateBrowserScriptForAllOperators(browserscript databaseStructs.Browserscr logging.LogError(err, "Failed to get operators") return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&operatorScript); err != nil { logging.LogError(err, "Failed to parse browserscript into structure for updating scripts") @@ -1278,6 +1287,7 @@ func removeBrowserScriptFromAllOperators(browserscript databaseStructs.Browsersc logging.LogError(err, "Failed to get browserscripts for command", "command", browserscript.CommandID) return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&operatorScript); err != nil { logging.LogError(err, "Failed to parse operator into structure") @@ -1307,6 +1317,7 @@ func updatePayloadTypeCommandMitreAttack(in PayloadTypeSyncMessage, syncCommand logging.LogError(err, "Failed to get attackcommand from database") return err } else { + defer rows.Close() for rows.Next() { if err = rows.StructScan(&databaseMitreAttack); err != nil { logging.LogError(err, "Failed to parse mitre att&ck into structure") diff --git a/mythic-docker/src/utils/config.go b/mythic-docker/src/utils/config.go index 521e6e5e..6d00536e 100644 --- a/mythic-docker/src/utils/config.go +++ b/mythic-docker/src/utils/config.go @@ -11,7 +11,7 @@ import ( "github.com/spf13/viper" ) -const mythicServerVersion = "3.4.32" +const mythicServerVersion = "3.4.33" type Config struct { // server configuration