From 2752e5fece6f47d276eef9118a84b2047aea953f Mon Sep 17 00:00:00 2001 From: its-a-feature Date: Mon, 18 Nov 2024 14:51:53 -0600 Subject: [PATCH] updating file hosting processes --- CHANGELOG.MD | 8 ++++ VERSION | 2 +- mythic-docker/src/VERSION | 2 +- .../src/rabbitmq/check_container_status.go | 2 +- mythic-docker/src/rabbitmq/recv_c2_sync.go | 47 +++++++++++++++++++ .../c2profile_host_file_webhook.go | 22 --------- .../src/webserver/controllers/utils.go | 41 ++++++++++++++++ 7 files changed, 99 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index f87d07f85..6300ece7a 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -4,6 +4,14 @@ 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.3.1-rc25] - 2024-11-18 + +### Changed + +- Updated how file hosting works for C2 profiles + - When syncing to Mythic, C2 profiles get updated file hosting based on existing FileHosted tags in Mythic + - When stopping file hosting, Mythic ensures that the C2 profile successfully processed the request before updating the corresponding Tag + ## [3.3.1-rc24] - 2024-11-18 ### Changed diff --git a/VERSION b/VERSION index aea6fcd65..24231bb55 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3.1-rc24 \ No newline at end of file +3.3.1-rc25 \ No newline at end of file diff --git a/mythic-docker/src/VERSION b/mythic-docker/src/VERSION index aea6fcd65..24231bb55 100644 --- a/mythic-docker/src/VERSION +++ b/mythic-docker/src/VERSION @@ -1 +1 @@ -3.3.1-rc24 \ No newline at end of file +3.3.1-rc25 \ No newline at end of file diff --git a/mythic-docker/src/rabbitmq/check_container_status.go b/mythic-docker/src/rabbitmq/check_container_status.go index 50687876c..163bd2ba6 100644 --- a/mythic-docker/src/rabbitmq/check_container_status.go +++ b/mythic-docker/src/rabbitmq/check_container_status.go @@ -108,7 +108,7 @@ type rabbitmqAPIQuery struct { func createGraphQLSpectatorAPITokenAndSendOnStartMessage(containerName string) { operations := []databaseStructs.Operation{} - err := database.DB.Select(&operations, `SELECT id FROM operation WHERE deleted=false and completed=true`) + err := database.DB.Select(&operations, `SELECT id FROM operation WHERE deleted=false and complete=false`) if err != nil { logging.LogError(err, "Failed to fetch operations") return diff --git a/mythic-docker/src/rabbitmq/recv_c2_sync.go b/mythic-docker/src/rabbitmq/recv_c2_sync.go index 1f6bee68c..dbd1b49df 100644 --- a/mythic-docker/src/rabbitmq/recv_c2_sync.go +++ b/mythic-docker/src/rabbitmq/recv_c2_sync.go @@ -9,6 +9,7 @@ import ( "github.com/its-a-feature/Mythic/logging" "github.com/its-a-feature/Mythic/utils" amqp "github.com/rabbitmq/amqp091-go" + "strings" ) // C2_SYNC STRUCTS @@ -311,4 +312,50 @@ func autoStartC2Profile(c2Profile databaseStructs.C2profile) { } } } + autoReHostFiles(c2Profile) +} + +func autoReHostFiles(c2Profile databaseStructs.C2profile) { + fileHostedTagType := databaseStructs.TagType{ + Name: "FileHosted", + } + err := database.DB.Get(&fileHostedTagType, `SELECT id FROM tagtype WHERE name=$1`, fileHostedTagType.Name) + if err != nil { + logging.LogError(err, "failed to get existing tag types") + return + } + currentTags := []databaseStructs.Tag{} + err = database.DB.Select(¤tTags, `SELECT * FROM tag WHERE tagtype_id=$1`, fileHostedTagType.ID) + if err != nil { + logging.LogError(err, "failed to get existing tags for FileHosted tagtype") + return + } + for _, tag := range currentTags { + dataStruct := tag.Data.StructValue() + for key, _ := range dataStruct { + if strings.HasPrefix(key, fmt.Sprintf("%s; ", c2Profile.Name)) { + newTagMap := dataStruct[key].(map[string]interface{}) + c2HostFileResponse, err := RabbitMQConnection.SendC2RPCHostFile(C2HostFileMessage{ + Name: newTagMap["c2_profile"].(string), + FileUUID: newTagMap["agent_file_id"].(string), + HostURL: newTagMap["host_url"].(string), + Remove: false, + }) + if err != nil { + logging.LogError(err, "failed to send host file message to c2 profile") + go SendAllOperationsMessage(fmt.Sprintf( + "%s failed to start hosting file:\n%s", newTagMap["c2_profile"].(string), + err.Error()), tag.Operation, "", database.MESSAGE_LEVEL_WARNING) + continue + } + if !c2HostFileResponse.Success { + logging.LogError(err, "c2 profile failed to start hosting file") + go SendAllOperationsMessage(fmt.Sprintf( + "%s failed to start hosting file:\n%s", newTagMap["c2_profile"].(string), + c2HostFileResponse.Error), tag.Operation, "", database.MESSAGE_LEVEL_WARNING) + continue + } + } + } + } } diff --git a/mythic-docker/src/webserver/controllers/c2profile_host_file_webhook.go b/mythic-docker/src/webserver/controllers/c2profile_host_file_webhook.go index 6efdd8546..9daf54008 100644 --- a/mythic-docker/src/webserver/controllers/c2profile_host_file_webhook.go +++ b/mythic-docker/src/webserver/controllers/c2profile_host_file_webhook.go @@ -7,7 +7,6 @@ import ( "github.com/its-a-feature/Mythic/database" databaseStructs "github.com/its-a-feature/Mythic/database/structs" "github.com/its-a-feature/Mythic/logging" - "github.com/its-a-feature/Mythic/rabbitmq" ) type C2HostFileMessageInput struct { @@ -84,27 +83,6 @@ func C2HostFileMessageWebhook(c *gin.Context) { }) return } - c2HostFileResponse, err := rabbitmq.RabbitMQConnection.SendC2RPCHostFile(rabbitmq.C2HostFileMessage{ - Name: c2Profile.Name, - FileUUID: input.Input.FileUUID, - HostURL: input.Input.HostURL, - Remove: input.Input.Remove, - }) - if err != nil { - logging.LogError(err, "Failed to send RPC call to c2 profile in C2ProfileHostFileWebhook", "c2_profile", c2Profile.Name) - c.JSON(http.StatusOK, C2HostFileMessageResponse{ - Status: "error", - Error: "Failed to send RPC message to c2 profile", - }) - return - } - if !c2HostFileResponse.Success { - c.JSON(http.StatusOK, C2HostFileMessageResponse{ - Status: "error", - Error: c2HostFileResponse.Error, - }) - return - } go tagFileAs(hostFile.ID, operatorOperation.CurrentOperator.Username, hostFile.OperationID, tagTypeHostedByC2, map[string]interface{}{ c2Profile.Name + "; " + input.Input.HostURL: map[string]interface{}{ "c2_profile": c2Profile.Name, diff --git a/mythic-docker/src/webserver/controllers/utils.go b/mythic-docker/src/webserver/controllers/utils.go index d01a0faf5..74c682d6c 100644 --- a/mythic-docker/src/webserver/controllers/utils.go +++ b/mythic-docker/src/webserver/controllers/utils.go @@ -195,12 +195,53 @@ Target Host: %s`, newTagMap["c2_profile"].(string) == oldTagMap["c2_profile"].(string) && (newTagMap["host_url"].(string) == "" || newTagMap["host_url"].(string) == oldTagMap["host_url"].(string)) { + c2HostFileResponse, err := rabbitmq.RabbitMQConnection.SendC2RPCHostFile(rabbitmq.C2HostFileMessage{ + Name: newTagMap["c2_profile"].(string), + FileUUID: newTagMap["agent_file_id"].(string), + HostURL: newTagMap["host_url"].(string), + Remove: remove, + }) + if err != nil { + logging.LogError(err, "failed to send message to container to stop hosting it") + go rabbitmq.SendAllOperationsMessage(fmt.Sprintf( + "%s failed to stop hosting file:\n%s", newTagMap["c2_profile"].(string), + err.Error()), operationID, "", database.MESSAGE_LEVEL_WARNING) + continue + } + if !c2HostFileResponse.Success { + logging.LogError(err, "c2 profile failed to stop hosting file") + go rabbitmq.SendAllOperationsMessage(fmt.Sprintf( + "%s failed to stop hosting file:\n%s", newTagMap["c2_profile"].(string), + c2HostFileResponse.Error), operationID, "", database.MESSAGE_LEVEL_WARNING) + continue + } delete(updateTagData, key) } } } } else { for key, val := range tagData { + newTagMap := val.(map[string]interface{}) + c2HostFileResponse, err := rabbitmq.RabbitMQConnection.SendC2RPCHostFile(rabbitmq.C2HostFileMessage{ + Name: newTagMap["c2_profile"].(string), + FileUUID: newTagMap["agent_file_id"].(string), + HostURL: newTagMap["host_url"].(string), + Remove: remove, + }) + if err != nil { + logging.LogError(err, "failed to send host file message to c2 profile") + go rabbitmq.SendAllOperationsMessage(fmt.Sprintf( + "%s failed to start hosting file:\n%s", newTagMap["c2_profile"].(string), + err.Error()), operationID, "", database.MESSAGE_LEVEL_WARNING) + continue + } + if !c2HostFileResponse.Success { + logging.LogError(err, "c2 profile failed to start hosting file") + go rabbitmq.SendAllOperationsMessage(fmt.Sprintf( + "%s failed to start hosting file:\n%s", newTagMap["c2_profile"].(string), + c2HostFileResponse.Error), operationID, "", database.MESSAGE_LEVEL_WARNING) + continue + } updateTagData[key] = val } }