Skip to content

Commit

Permalink
updating MythicRPC commands for Callback Search/Add/Remove
Browse files Browse the repository at this point in the history
  • Loading branch information
its-a-feature committed Dec 14, 2024
1 parent 2991f53 commit eddbd55
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 27 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -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.3.1-rc32] - 2024-12-14

### Changed

- Updated MythicRPCCallbackSearch to specify a list of payload types
- Updated MythicRPCCallbackAddCommand and MythicRPCCallbackRemoveCommand to take in a list of callback ids

## [3.3.1-rc31] - 2024-12-13

### 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-rc31
3.3.1-rc32
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-rc31
3.3.1-rc32
13 changes: 13 additions & 0 deletions mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_add_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type MythicRPCCallbackAddCommandMessage struct {
AgentCallbackID string `json:"agent_callback_id"`
Commands []string `json:"commands"` // required
PayloadType string `json:"payload_type"`
CallbackIDs []int `json:"callback_ids"`
}
type MythicRPCCallbackAddCommandMessageResponse struct {
Success bool `json:"success"`
Expand Down Expand Up @@ -85,6 +86,18 @@ func MythicRPCCallbackAddCommand(input MythicRPCCallbackAddCommandMessage) Mythi
response.Error = "No callback supplied"
return response
}
if len(input.CallbackIDs) > 0 {
for _, c := range input.CallbackIDs {
err := CallbackAddCommand(c, PayloadTypeID, OperatorID, input.Commands)
if err != nil {
logging.LogError(err, "Failed to add commands to callback")
response.Error = err.Error()
return response
}
}
response.Success = true
return response
}
err := CallbackAddCommand(CallbackID, PayloadTypeID, OperatorID, input.Commands)
if err != nil {
logging.LogError(err, "Failed to add commands to callback")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type MythicRPCCallbackRemoveCommandMessage struct {
AgentCallbackID string `json:"agent_callback_id"`
Commands []string `json:"commands"` // required
PayloadType string `json:"payload_type"`
CallbackIDs []int `json:"callback_ids"`
}
type MythicRPCCallbackRemoveCommandMessageResponse struct {
Success bool `json:"success"`
Expand All @@ -26,7 +27,7 @@ func init() {
Exchange: MYTHIC_EXCHANGE,
Queue: MYTHIC_RPC_CALLBACK_REMOVE_COMMAND,
RoutingKey: MYTHIC_RPC_CALLBACK_REMOVE_COMMAND,
Handler: processMythicRPCCallbackAddCommand,
Handler: processMythicRPCCallbackRemoveCommand,
})
}

Expand Down Expand Up @@ -85,6 +86,18 @@ func MythicRPCCallbackRemoveCommand(input MythicRPCCallbackRemoveCommandMessage)
response.Error = "No callback supplied"
return response
}
if len(input.CallbackIDs) > 0 {
for _, c := range input.CallbackIDs {
err := CallbackRemoveCommand(c, PayloadTypeID, OperatorID, input.Commands)
if err != nil {
logging.LogError(err, "Failed to remove commands to callback")
response.Error = err.Error()
return response
}
}
response.Success = true
return response
}
err := CallbackRemoveCommand(CallbackID, PayloadTypeID, OperatorID, input.Commands)
if err != nil {
logging.LogError(err, "Failed to remove commands to callback")
Expand Down
64 changes: 40 additions & 24 deletions mythic-docker/src/rabbitmq/recv_mythic_rpc_callback_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package rabbitmq
import (
"encoding/json"
"github.com/mitchellh/mapstructure"
"slices"
"strings"
"time"

Expand All @@ -13,23 +14,24 @@ import (
)

type MythicRPCCallbackSearchMessage struct {
AgentCallbackUUID string `json:"agent_callback_id"`
AgentCallbackID int `json:"callback_id"`
SearchCallbackID *int `json:"search_callback_id"`
SearchCallbackDisplayID *int `json:"search_callback_display_id"`
SearchCallbackUUID *string `json:"search_callback_uuid"`
SearchCallbackUser *string `json:"user,omitempty"`
SearchCallbackHost *string `json:"host,omitempty"`
SearchCallbackPID *int `json:"pid,omitempty"`
SearchCallbackExtraInfo *string `json:"extra_info,omitempty"`
SearchCallbackSleepInfo *string `json:"sleep_info,omitempty"`
SearchCallbackIP *string `json:"ip,omitempty"`
SearchCallbackExternalIP *string `json:"external_ip,omitempty"`
SearchCallbackIntegrityLevel *int `json:"integrity_level,omitempty"`
SearchCallbackOs *string `json:"os,omitempty"`
SearchCallbackDomain *string `json:"domain,omitempty"`
SearchCallbackArchitecture *string `json:"architecture,omitempty"`
SearchCallbackDescription *string `json:"description,omitempty"`
AgentCallbackUUID string `json:"agent_callback_id"`
AgentCallbackID int `json:"callback_id"`
SearchCallbackID *int `json:"search_callback_id"`
SearchCallbackDisplayID *int `json:"search_callback_display_id"`
SearchCallbackUUID *string `json:"search_callback_uuid"`
SearchCallbackUser *string `json:"user,omitempty"`
SearchCallbackHost *string `json:"host,omitempty"`
SearchCallbackPID *int `json:"pid,omitempty"`
SearchCallbackExtraInfo *string `json:"extra_info,omitempty"`
SearchCallbackSleepInfo *string `json:"sleep_info,omitempty"`
SearchCallbackIP *string `json:"ip,omitempty"`
SearchCallbackExternalIP *string `json:"external_ip,omitempty"`
SearchCallbackIntegrityLevel *int `json:"integrity_level,omitempty"`
SearchCallbackOs *string `json:"os,omitempty"`
SearchCallbackDomain *string `json:"domain,omitempty"`
SearchCallbackArchitecture *string `json:"architecture,omitempty"`
SearchCallbackDescription *string `json:"description,omitempty"`
SearchCallbackPayloadTypes *[]string `json:"payload_types,omitempty"`
}
type MythicRPCCallbackSearchMessageResult struct {
ID int `mapstructure:"id" json:"id"`
Expand All @@ -46,7 +48,9 @@ type MythicRPCCallbackSearchMessageResult struct {
Description string `mapstructure:"description" json:"description"`
OperatorID int `mapstructure:"operator_id" json:"operator_id"`
Active bool `mapstructure:"active" json:"active"`
Dead bool `mapstructure:"dead" json:"dead"`
RegisteredPayloadUUID string `mapstructure:"registered_payload_uuid" json:"registered_payload_uuid"`
PayloadType string `mapstructure:"payloadtype" json:"payloadtype"`
IntegrityLevel int `mapstructure:"integrity_level" json:"integrity_level"`
Locked bool `mapstructure:"locked" json:"locked"`
LockedOperatorID int `mapstructure:"locked_operator_id" json:"locked_operator_id"`
Expand Down Expand Up @@ -106,9 +110,11 @@ func MythicRPCCallbackSearch(input MythicRPCCallbackSearchMessage) MythicRPCCall
}
searchString := `SELECT
callback.*,
payload.uuid "payload.uuid"
payload.uuid "payload.uuid",
payloadtype.name "payload.payloadtype.name"
FROM callback
JOIN payload on callback.registered_payload_id = payload.id
JOIN payloadtype on payload.payload_type_id = payloadtype.id
WHERE callback.operation_id=:operation_id `
// if we're not actually searching for another callback, just set ours
if input.SearchCallbackDisplayID != nil || input.SearchCallbackID != nil || input.SearchCallbackUUID != nil {
Expand Down Expand Up @@ -175,17 +181,27 @@ func MythicRPCCallbackSearch(input MythicRPCCallbackSearchMessage) MythicRPCCall
}
for rows.Next() {
result := MythicRPCCallbackSearchMessageResult{}
if err = rows.StructScan(&searchResults); err != nil {
err = rows.StructScan(&searchResults)
if err != nil {
logging.LogError(err, "Failed to get row from callbacks for search")
} else if err = mapstructure.Decode(searchResults, &result); err != nil {
continue
}
err = mapstructure.Decode(searchResults, &result)
if err != nil {
logging.LogError(err, "Failed to map callback search results into array")
response.Error = err.Error()
return response
} else {
result.RegisteredPayloadUUID = searchResults.Payload.UuID
result.LockedOperatorID = int(searchResults.LockedOperatorID.Int64)
response.Results = append(response.Results, result)
}
if input.SearchCallbackPayloadTypes != nil && len(*input.SearchCallbackPayloadTypes) > 0 {
if !slices.Contains(*input.SearchCallbackPayloadTypes, searchResults.Payload.Payloadtype.Name) {
continue
}
}
result.RegisteredPayloadUUID = searchResults.Payload.UuID
result.LockedOperatorID = int(searchResults.LockedOperatorID.Int64)
result.PayloadType = searchResults.Payload.Payloadtype.Name
response.Results = append(response.Results, result)

}
response.Success = true
return response
Expand Down

0 comments on commit eddbd55

Please sign in to comment.