Skip to content

Commit

Permalink
Updating to better reflected deleted payloads not making callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
its-a-feature committed Oct 18, 2024
1 parent dfad0de commit 2086115
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ 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.-rc17] - 2024-10-18

### Changed

- Updated the file delete call to invalidate existing cached info to prevent new callbacks

## [3.3.1-rc16] - 2024-10-14

### Changed
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.3.1-rc16
3.3.1-rc17
2 changes: 1 addition & 1 deletion mythic-docker/.docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.21 as builder
FROM golang:1.21 AS builder

WORKDIR /usr/src/app

Expand Down
2 changes: 1 addition & 1 deletion mythic-docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#FROM ghcr.io/its-a-feature/mythic_server:v0.0.3.8

FROM golang:1.21 as builder
FROM golang:1.21 AS builder

WORKDIR /usr/src/app

Expand Down
2 changes: 1 addition & 1 deletion mythic-docker/src/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.3.1-rc16
3.3.1-rc17
25 changes: 18 additions & 7 deletions mythic-docker/src/rabbitmq/util_agent_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ func InvalidateAllCachedUUIDInfo() {
cachedUUIDInfoMap = make(map[string]*cachedUUIDInfo)
}

func InvalidateCachedUUIDInfo(uuid string) {
cachedUUIDInfoMapMutex.Lock()
defer cachedUUIDInfoMapMutex.Unlock()
for key, _ := range cachedUUIDInfoMap {
if strings.HasPrefix(key, uuid) {
delete(cachedUUIDInfoMap, key)
}
}
}

var cachedUUIDInfoMap = make(map[string]*cachedUUIDInfo)

func MarkCallbackInfoInactive(callbackID int) {
Expand Down Expand Up @@ -353,8 +363,7 @@ func recursiveProcessAgentMessage(agentMessageInput AgentMessageRawInput) recurs
// 4. look up c2 profile and information about UUID
uuidInfo, err := LookupEncryptionData(agentMessageInput.C2Profile, messageUUID.String(), agentMessageInput.UpdateCheckinTime)
if err != nil {
errorMessage := fmt.Sprintf("Failed to correlate UUID, %s, to something Mythic knows.\n", messageUUID.String())
errorMessage += fmt.Sprintf("%s is likely a Callback or Payload from a Mythic instance that was deleted or had the database reset.\n", messageUUID.String())
errorMessage := err.Error() + "\n"
errorMessage += fmt.Sprintf("Connection from %s via %s\n", agentMessageInput.RemoteIP, agentMessageInput.C2Profile)
go SendAllOperationsMessage(errorMessage, uuidInfo.OperationID, messageUUID.String(), database.MESSAGE_LEVEL_WARNING)
logging.LogError(err, errorMessage)
Expand Down Expand Up @@ -709,7 +718,7 @@ func LookupEncryptionData(c2profile string, messageUUID string, updateCheckinTim
newCache.CallbackDisplayID = callback.DisplayID
newCache.LastCheckinTime = callback.LastCheckin
newCache.OperationID = callback.OperationID
} else if err := database.DB.Get(&payload, `SELECT
} else if err = database.DB.Get(&payload, `SELECT
payload.id, payload.operation_id,
payload.deleted, payload.description, payload.uuid,
payloadtype.id "payloadtype.id",
Expand Down Expand Up @@ -745,7 +754,7 @@ func LookupEncryptionData(c2profile string, messageUUID string, updateCheckinTim
// we also need to get the crypto keys from the c2 profile for this payload
foundCryptoParam := false
cryptoParam := databaseStructs.C2profileparametersinstance{}
if err := database.DB.Get(&cryptoParam, `SELECT
if err = database.DB.Get(&cryptoParam, `SELECT
c2profileparametersinstance.enc_key,
c2profileparametersinstance.dec_key,
c2profileparametersinstance.value,
Expand All @@ -766,7 +775,7 @@ func LookupEncryptionData(c2profile string, messageUUID string, updateCheckinTim
newCache.CryptoType = cryptoParam.Value
}
payloadCryptoParam := databaseStructs.Buildparameterinstance{}
if err := database.DB.Get(&payloadCryptoParam, `SELECT
if err = database.DB.Get(&payloadCryptoParam, `SELECT
enc_key, dec_key, value
FROM buildparameterinstance
WHERE dec_key IS NOT NULL AND payload_id=$1`, payload.ID); err == sql.ErrNoRows {
Expand All @@ -784,7 +793,7 @@ func LookupEncryptionData(c2profile string, messageUUID string, updateCheckinTim
newCache.PayloadEncKey = payloadCryptoParam.EncKey
newCache.CryptoType = payloadCryptoParam.Value
}
} else if err := database.DB.Get(&stager, `SELECT
} else if err = database.DB.Get(&stager, `SELECT
staginginfo.id, staginginfo.enc_key, staginginfo.dec_key, staginginfo.crypto_type,
payload.id "payload.id",
payload.operation_id "payload.operation_id",
Expand Down Expand Up @@ -820,7 +829,9 @@ func LookupEncryptionData(c2profile string, messageUUID string, updateCheckinTim
} else {
// we couldn't find a match for the UUID
logging.LogError(err, "Failed to find UUID in callbacks, staging, or payloads")
return &newCache, errors.New(fmt.Sprintf("Failed to find UUID (%s) in callbacks, staging, or payloads", messageUUID))
errorMessage := fmt.Sprintf("Failed to correlate UUID, %s, to something Mythic knows.\n", messageUUID)
errorMessage += fmt.Sprintf("%s is likely a Callback or Payload from a Mythic instance that was deleted or had the database reset.\n", messageUUID)
return &newCache, errors.New(errorMessage)
}
if newCache.TranslationContainerID > 0 {
if err := database.DB.Get(&newCache.TranslationContainerName, `SELECT
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package webcontroller

import (
"github.com/its-a-feature/Mythic/rabbitmq"
"net/http"
"os"
"time"
Expand Down Expand Up @@ -72,14 +73,16 @@ func DeleteFileWebhook(c *gin.Context) {
}
if filemeta.IsPayload {
payload := databaseStructs.Payload{}
if err := database.DB.Get(&payload, `SELECT id FROM payload WHERE file_id=$1`, filemeta.ID); err != nil {
if err := database.DB.Get(&payload, `SELECT id, uuid FROM payload WHERE file_id=$1`, filemeta.ID); err != nil {
logging.LogError(err, "Failed to fetch payload for associated file_id")
} else {
payload.Deleted = true
deletedPayloadIDs = append(deletedPayloadIDs, payload.ID)
if _, err := database.DB.Exec(`UPDATE payload SET deleted=true WHERE id=$1`, payload.ID); err != nil {
logging.LogError(err, "Failed to update payload deleted status")
}
// make sure to invalidate existing cache entries based on this payload UUID so new callbacks can't be created
go rabbitmq.InvalidateCachedUUIDInfo(payload.UuID)
}
}
if filemeta.EventGroupID.Valid {
Expand All @@ -104,14 +107,15 @@ func DeleteFileWebhook(c *gin.Context) {
deletedFileIDs = append(deletedFileIDs, file.ID)
if file.IsPayload {
payload := databaseStructs.Payload{}
if err := database.DB.Get(&payload, `SELECT id FROM payload WHERE file_id=$1`, file.ID); err != nil {
if err := database.DB.Get(&payload, `SELECT id, uuid FROM payload WHERE file_id=$1`, file.ID); err != nil {
logging.LogError(err, "Failed to fetch payload for associated file_id")
} else {
payload.Deleted = true
deletedPayloadIDs = append(deletedPayloadIDs, payload.ID)
if _, err := database.DB.Exec(`UPDATE payload SET deleted=true WHERE id=$1`, payload.ID); err != nil {
logging.LogError(err, "Failed to update payload deleted status")
}
go rabbitmq.InvalidateCachedUUIDInfo(payload.UuID)
}
}
if _, err := database.DB.Exec(`UPDATE filemeta SET deleted=true WHERE id=$1`, file.ID); err != nil {
Expand Down

0 comments on commit 2086115

Please sign in to comment.