├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── SECURITY.md ├── agent_structs ├── InteractiveTask │ └── InteractiveTaskEnum.go ├── constants.go ├── structs_callback_alive.go ├── structs_dynamic_query_function.go ├── structs_dynamic_typedArray_parse_function.go ├── structs_payload_build.go ├── structs_payload_sync.go ├── structs_resync.go ├── structs_task_args.go ├── structs_task_messages.go ├── structs_tasking.go └── utils.go ├── authstructs ├── get_idp_metadata.go ├── get_idp_redirect.go ├── get_nonidp_metadata.go ├── get_nonidp_redirect.go ├── process_idp_response.go ├── process_nonidp_response.go └── utils.go ├── c2_structs ├── c2_sync.go ├── structs_config_check.go ├── structs_get_debug_output.go ├── structs_get_ioc.go ├── structs_get_redirector_rules.go ├── structs_host_file.go ├── structs_opsec_check.go ├── structs_resync.go ├── structs_sample_message.go ├── structs_start_server.go ├── structs_stop_server.go └── utils.go ├── config └── config.go ├── eventingstructs ├── conditional_check.go ├── custom_function.go ├── response_intercept.go ├── task_intercept.go └── utils.go ├── go.mod ├── go.sum ├── grpc ├── initialize.go ├── pushC2.go └── services │ ├── pushC2GRPC.pb.go │ ├── pushC2GRPC_grpc.pb.go │ ├── translationContainerGRPC.pb.go │ └── translationContainerGRPC_grpc.pb.go ├── init.go ├── logging └── initialize.go ├── loggingstructs ├── new_artifact_log.go ├── new_callback_log.go ├── new_credential_log.go ├── new_file_log.go ├── new_keylog_log.go ├── new_payload_log.go ├── new_response_log.go ├── new_task_log.go └── utils.go ├── mythicrpc ├── send_mythic_rpc_agentstorage_create.go ├── send_mythic_rpc_agentstorage_remove.go ├── send_mythic_rpc_agentstorage_search.go ├── send_mythic_rpc_apitoken_create.go ├── send_mythic_rpc_artifact_create.go ├── send_mythic_rpc_artifact_search.go ├── send_mythic_rpc_c2_update_status.go ├── send_mythic_rpc_callback_add_command.go ├── send_mythic_rpc_callback_create.go ├── send_mythic_rpc_callback_decrypt_bytes.go ├── send_mythic_rpc_callback_display_to_real_id_search.go ├── send_mythic_rpc_callback_edge_search.go ├── send_mythic_rpc_callback_encrypt_bytes.go ├── send_mythic_rpc_callback_next_checkin_range.go ├── send_mythic_rpc_callback_remove_command.go ├── send_mythic_rpc_callback_search.go ├── send_mythic_rpc_callback_search_command.go ├── send_mythic_rpc_callback_update.go ├── send_mythic_rpc_callbacktoken_create.go ├── send_mythic_rpc_callbacktoken_remove.go ├── send_mythic_rpc_command_search.go ├── send_mythic_rpc_credential_create.go ├── send_mythic_rpc_credential_search.go ├── send_mythic_rpc_file_create.go ├── send_mythic_rpc_file_get_content.go ├── send_mythic_rpc_file_search.go ├── send_mythic_rpc_file_update.go ├── send_mythic_rpc_filebrowser_create.go ├── send_mythic_rpc_filebrowser_parse_path.go ├── send_mythic_rpc_filebrowser_remove.go ├── send_mythic_rpc_keylog_create.go ├── send_mythic_rpc_keylog_search.go ├── send_mythic_rpc_operationeventlog_create.go ├── send_mythic_rpc_other_service_rpc.go ├── send_mythic_rpc_payload_add_comand.go ├── send_mythic_rpc_payload_create_from_scratch.go ├── send_mythic_rpc_payload_create_from_uuid.go ├── send_mythic_rpc_payload_get_content.go ├── send_mythic_rpc_payload_remove_comand.go ├── send_mythic_rpc_payload_search.go ├── send_mythic_rpc_payload_update_build_step.go ├── send_mythic_rpc_payloadonhost_create.go ├── send_mythic_rpc_process_create.go ├── send_mythic_rpc_process_search.go ├── send_mythic_rpc_proxy_start.go ├── send_mythic_rpc_proxy_stop.go ├── send_mythic_rpc_response_create.go ├── send_mythic_rpc_response_search.go ├── send_mythic_rpc_tag_create.go ├── send_mythic_rpc_tag_search.go ├── send_mythic_rpc_tagtype_get_or_create.go ├── send_mythic_rpc_task_create.go ├── send_mythic_rpc_task_create_subtask group.go ├── send_mythic_rpc_task_create_subtask.go ├── send_mythic_rpc_task_display_to_real_id_search.go ├── send_mythic_rpc_task_search.go ├── send_mythic_rpc_task_update.go ├── send_mythic_rpc_token_create.go ├── send_mythic_rpc_token_remove.go └── structs.go ├── rabbitmq ├── constants.go ├── initialize.go ├── recv_auth_rpc_get_idp_metadata.go ├── recv_auth_rpc_get_idp_redirect.go ├── recv_auth_rpc_get_nonidp_metadata.go ├── recv_auth_rpc_get_nonidp_redirect.go ├── recv_auth_rpc_process_idp_response.go ├── recv_auth_rpc_process_nonidp_response.go ├── recv_c2_rpc_config_check.go ├── recv_c2_rpc_get_debug_output.go ├── recv_c2_rpc_get_ioc.go ├── recv_c2_rpc_get_redirector_rules.go ├── recv_c2_rpc_host_file.go ├── recv_c2_rpc_opsec_check.go ├── recv_c2_rpc_resync.go ├── recv_c2_rpc_sample_message.go ├── recv_c2_rpc_start_server.go ├── recv_c2_rpc_stop_server.go ├── recv_consuming_container_rpc_resync.go ├── recv_container_on_start.go ├── recv_container_rpc_get_file.go ├── recv_container_rpc_list_files.go ├── recv_container_rpc_remove_file.go ├── recv_container_rpc_write_file.go ├── recv_eventing_conditional_check.go ├── recv_eventing_custom_function.go ├── recv_eventing_response_intercept.go ├── recv_eventing_task_intercept.go ├── recv_mythic_rpc_other_service_rpc.go ├── recv_pt_build.go ├── recv_pt_check_if_callbacks_alive.go ├── recv_pt_dynamic_query_function.go ├── recv_pt_on_new_callback.go ├── recv_pt_process_response.go ├── recv_pt_rpc_resync.go ├── recv_pt_rpc_typedarray_parse_function.go ├── recv_pt_task_completion.go ├── recv_pt_task_create.go ├── recv_pt_task_opsec_post.go ├── recv_pt_task_opsec_pre.go ├── recv_tr_custom_to_mythic_format.go ├── recv_tr_decrypt_bytes.go ├── recv_tr_encrypt_bytes.go ├── recv_tr_generate_encryption_keys.go ├── recv_tr_mythic_to_custom_format.go ├── recv_tr_rpc_resync.go ├── send_c2_rpc_update_status.go ├── send_c2_sync_data.go ├── send_consuming_container_sync_data.go ├── send_pt_sync_data.go ├── send_tr_sync_data.go ├── structs.go └── utils.go ├── translationstructs ├── structs_custom_to_mythic_format.go ├── structs_decrypt_bytes.go ├── structs_encrypt_bytes.go ├── structs_generate_encryption_keys.go ├── structs_generic.go ├── structs_mythic_to_custom_format.go ├── structs_tr_resync.go ├── structs_tr_sync.go └── utils.go ├── utils ├── helpers │ └── helpers.go ├── mythicutils │ └── mythicutils.go └── sharedStructs │ └── sharedStructs.go └── webhookstructs ├── alert_webhook.go ├── custom_webhook.go ├── new_callback_webhook.go ├── new_feedback_webhook.go ├── startup_webhook.go ├── structs.go └── utils.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | .DS_Store 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | .idea/ 17 | .vscode/ 18 | 19 | # Dependency directories (remove the comment below to include it) 20 | # vendor/ 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Mythic Meta Configuration Information 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MythicContainer 2 | GoLang package for creating Mythic Payload Types, C2 Profiles, Translation Services, WebHook listeners, and Loggers 3 | 4 | ## Install 5 | ```shell 6 | go get http://github.com/MythicMeta/MythicContainer 7 | ``` 8 | 9 | ## Usage 10 | 11 | Import the package, `github.com/MythicMeta/MythicContainer` and run the service via `MythicContainer.StartAndRunForever`. 12 | You can import as many Payload Types, C2 Profiles, Translation Services, WebHook listeners, and Loggers as you want as long as you call their `Initialize()` function and supply their corresponding service type when starting as shown below. 13 | ```go 14 | package main 15 | 16 | import ( 17 | httpfunctions "PoseidonContainer/http/c2functions" 18 | "PoseidonContainer/my_logger" 19 | "PoseidonContainer/my_webhooks" 20 | mytranslatorfunctions "PoseidonContainer/no_actual_translation/translationfunctions" 21 | poseidonfunctions "PoseidonContainer/poseidon/agentfunctions" 22 | poseidontcpfunctions "PoseidonContainer/poseidon_tcp/c2functions" 23 | servicewrapperfunctions "PoseidonContainer/service_wrapper/agentfunctions" 24 | "github.com/MythicMeta/MythicContainer" 25 | ) 26 | 27 | func main() { 28 | // load up the agent functions directory so all the init() functions execute 29 | poseidonfunctions.Initialize() 30 | httpfunctions.Initialize() 31 | poseidontcpfunctions.Initialize() 32 | servicewrapperfunctions.Initialize() 33 | mytranslatorfunctions.Initialize() 34 | my_webhooks.Initialize() 35 | my_logger.Initialize() 36 | // sync over definitions and listen 37 | MythicContainer.StartAndRunForever([]MythicContainer.MythicServices{ 38 | MythicContainer.MythicServicePayload, 39 | MythicContainer.MythicServiceC2, 40 | MythicContainer.MythicServiceTranslationContainer, 41 | MythicContainer.MythicServiceWebhook, 42 | MythicContainer.MythicServiceLogger, 43 | }) 44 | } 45 | ``` -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The following the table details the supported versions of Mythic. 6 | 7 | | Version | Supported | 8 | |---------| ------------------ | 9 | | 1.0.0 | :white_check_mark: | 10 | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | If you find a vulnerability with Mythic, please reach out via twitter (@its_a_feature_), open an issue on this GitHub repo, or reach out via the Bloodhound Slack to the user @its_a_feature_. 15 | 16 | Please make sure you include what the vulnerability/issue is and have either replication steps or a proof of concept for me to look at. 17 | I'll do my best to reproduce it locally and hopefully get a fix within 48 hours. If it's not something I can easily fix, we can work on a timeline. 18 | I can't offer any cash prize for finding issues, but I can get a swag bag sent out to you. 19 | 20 | If it's something that you send privately to me, please don't publicly report it until we're able to determine a fix. -------------------------------------------------------------------------------- /agent_structs/InteractiveTask/InteractiveTaskEnum.go: -------------------------------------------------------------------------------- 1 | package InteractiveTask 2 | 3 | type MessageType int 4 | 5 | const ( 6 | Input MessageType = iota 7 | Output 8 | Error 9 | Exit 10 | Escape //^[ 0x1B 11 | CtrlA //^A - 0x01 - start 12 | CtrlB //^B - 0x02 - back 13 | CtrlC //^C - 0x03 - interrupt process 14 | CtrlD //^D - 0x04 - delete (exit if nothing sitting on input) 15 | CtrlE //^E - 0x05 - end 16 | CtrlF //^F - 0x06 - forward 17 | CtrlG //^G - 0x07 - cancel search 18 | Backspace //^H - 0x08 - backspace 19 | Tab //^I - 0x09 - tab 20 | CtrlK //^K - 0x0B - kill line forwards 21 | CtrlL //^L - 0x0C - clear screen 22 | CtrlN //^N - 0x0E - next history 23 | CtrlP //^P - 0x10 - previous history 24 | CtrlQ //^Q - 0x11 - unpause output 25 | CtrlR //^R - 0x12 - search history 26 | CtrlS //^S - 0x13 - pause output 27 | CtrlU //^U - 0x15 - kill line backwards 28 | CtrlW //^W - 0x17 - kill word backwards 29 | CtrlY //^Y - 0x19 - yank 30 | CtrlZ //^Z - 0x1A - suspend process 31 | end 32 | ) 33 | 34 | func IsValid(value int) bool { 35 | return value >= 0 && value < int(end) 36 | } 37 | -------------------------------------------------------------------------------- /agent_structs/constants.go: -------------------------------------------------------------------------------- 1 | package agentstructs 2 | 3 | const ( 4 | SUPPORTED_OS_MACOS = "macOS" 5 | SUPPORTED_OS_WINDOWS = "Windows" 6 | SUPPORTED_OS_LINUX = "Linux" 7 | SUPPORTED_OS_CHROME = "Chrome" 8 | SUPPORTED_OS_WEBSHELL = "WebShell" 9 | ) 10 | 11 | const ( 12 | SUPPORTED_UI_FEATURE_TASK_PROCESS_INTERACTIVE_TASKS = "task:process_interactive_tasks" 13 | SUPPORTED_UI_FEATURE_TASK_RESPONSE_INTERACTIVE = "task_response:interactive" 14 | SUPPORTED_UI_FEATURE_CALLBACK_TABLE_EXIT = "callback_table:exit" 15 | SUPPORTED_UI_FEATURE_FILE_BROWSER_LIST = "file_browser:list" 16 | SUPPORTED_UI_FEATURE_FILE_BROWSER_REMOVE = "file_browser:remove" 17 | SUPPORTED_UI_FEATURE_FILE_BROWSER_UPLOAD = "file_browser:upload" 18 | SUPPORTED_UI_FEATURE_FILE_BROWSER_DOWNLOAD = "file_browser:download" 19 | SUPPORTED_UI_FEATURE_PROCESS_BROWSER_LIST = "process_browser:list" 20 | SUPPORTED_UI_FEATURE_PROCESS_BROWSER_KILL = "process_browser:kill" 21 | SUPPORTED_UI_FEATURE_PROCESS_BROWSER_INJECT = "process_browser:inject" 22 | SUPPORTED_UI_FEATURE_PROCESS_BROWSER_STEAL_TOKEN = "process_browser:steal_token" 23 | SUPPORTED_UI_FEATURE_PROCESS_BROWSER_LIST_TOKENS = "process_browser:list_tokens" 24 | ) 25 | 26 | type AgentType string 27 | 28 | const ( 29 | AgentTypeAgent AgentType = "agent" 30 | AgentTypeWrapper = "wrapper" 31 | AgentTypeService = "service" 32 | AgentTypeCommandAugment = "command_augment" 33 | ) 34 | 35 | type MessageFormat string 36 | 37 | const ( 38 | MessageFormatJSON MessageFormat = "json" 39 | MessageFormatXML = "xml" 40 | ) 41 | -------------------------------------------------------------------------------- /agent_structs/structs_callback_alive.go: -------------------------------------------------------------------------------- 1 | package agentstructs 2 | 3 | import "time" 4 | 5 | type PTCallbacksToCheck struct { 6 | ID int `json:"id"` 7 | DisplayID int `json:"display_id"` 8 | AgentCallbackID string `json:"agent_callback_id"` 9 | InitialCheckin time.Time `json:"initial_checkin"` 10 | LastCheckin time.Time `json:"last_checkin"` 11 | SleepInfo string `json:"sleep_info"` 12 | ActiveC2Profiles []string `json:"active_c2_profiles"` 13 | } 14 | type PTCheckIfCallbacksAliveMessage struct { 15 | ContainerName string `json:"container_name"` 16 | Callbacks []PTCallbacksToCheck `json:"callbacks"` 17 | } 18 | type PTCallbacksToCheckResponse struct { 19 | ID int `json:"id"` 20 | Alive bool `json:"alive"` 21 | } 22 | type PTCheckIfCallbacksAliveMessageResponse struct { 23 | Success bool `json:"success"` 24 | Error string `json:"error"` 25 | Callbacks []PTCallbacksToCheckResponse 26 | } 27 | -------------------------------------------------------------------------------- /agent_structs/structs_dynamic_query_function.go: -------------------------------------------------------------------------------- 1 | package agentstructs 2 | 3 | type PTRPCDynamicQueryFunctionMessage struct { 4 | // Command - the command name for the query function called 5 | Command string `json:"command" binding:"required"` 6 | // ParameterName - the specific parameter for the query function called 7 | ParameterName string `json:"parameter_name" binding:"required"` 8 | // PayloadType - the name of the payload type of the callback for the query function called 9 | PayloadType string `json:"payload_type" binding:"required"` 10 | // CommandPayloadType - the name of the payload type associated with this command 11 | CommandPayloadType string `json:"command_payload_type"` 12 | // Callback - the ID of the callback where this query function is called 13 | Callback int `json:"callback" binding:"required"` 14 | // PayloadOS - the string OS selected during payload creation 15 | PayloadOS string `json:"payload_os"` 16 | // PayloadUUID - the UUID of the backing payload that can be used to fetch more information about the payload 17 | PayloadUUID string `json:"payload_uuid"` 18 | // CallbackDisplayID - the number seen on the active callbacks page for the callback in question 19 | CallbackDisplayID int `json:"callback_display_id"` 20 | // AgentCallbackID - the UUID of the callback known by the agent 21 | AgentCallbackID string `json:"agent_callback_id"` 22 | // Secrets - User supplied secrets 23 | Secrets map[string]interface{} `json:"secrets"` 24 | // OtherParameters - other user supplied parameters 25 | OtherParameters map[string]interface{} `json:"other_parameters"` 26 | } 27 | type PTRPCDynamicQueryFunctionMessageComplexChoice struct { 28 | DisplayValue string `json:"display_value"` 29 | Value string `json:"value"` 30 | } 31 | type PTRPCDynamicQueryFunctionMessageResponse struct { 32 | // Success - indicating if the query function succeeded or not 33 | Success bool `json:"success"` 34 | // Error - if there was an error, return that message here for the user 35 | Error string `json:"error"` 36 | // Choices - the resulting choices for the user based on the dynamic query function 37 | Choices []string `json:"choices"` 38 | // ComplexChoices - the ability to specify a value and display value for more complex usability 39 | //ComplexChoices []PTRPCDynamicQueryFunctionMessageComplexChoice `json:"complex_choices"` 40 | } 41 | -------------------------------------------------------------------------------- /agent_structs/structs_dynamic_typedArray_parse_function.go: -------------------------------------------------------------------------------- 1 | package agentstructs 2 | 3 | type PTRPCTypedArrayParseFunctionMessage struct { 4 | // Command - the command name for the query function called 5 | Command string `json:"command" binding:"required"` 6 | // ParameterName - the specific parameter for the query function called 7 | ParameterName string `json:"parameter_name" binding:"required"` 8 | // PayloadType - the name of the payload type for the callback where query function called 9 | PayloadType string `json:"payload_type" binding:"required"` 10 | // CommandPayloadType - the name of the payload type for the command issued 11 | CommandPayloadType string `json:"command_payload_type"` 12 | // Callback - the ID of the callback where this query function is called 13 | Callback int `json:"callback" binding:"required"` 14 | // InputArray - the structured input array that the user provided 15 | InputArray []string `json:"input_array"` 16 | } 17 | 18 | type PTRPCTypedArrayParseMessageResponse struct { 19 | // Success - indicating if the query function succeeded or not 20 | Success bool `json:"success"` 21 | // Error - if there was an error, return that message here for the user 22 | Error string `json:"error"` 23 | // TypedArray - the resulting typed array based on the formatted normal array 24 | TypedArray [][]string `json:"typed_array"` 25 | } 26 | -------------------------------------------------------------------------------- /agent_structs/structs_resync.go: -------------------------------------------------------------------------------- 1 | package agentstructs 2 | 3 | // PT_RESYNC STRUCTS 4 | 5 | type PTRPCReSyncMessage struct { 6 | Name string `json:"payload_type"` 7 | } 8 | 9 | type PTRPCReSyncMessageResponse struct { 10 | Success bool `json:"success"` 11 | Error string `json:"error"` 12 | } 13 | -------------------------------------------------------------------------------- /agent_structs/structs_tasking.go: -------------------------------------------------------------------------------- 1 | package agentstructs 2 | 3 | type FileBrowserTask struct { 4 | Path string `json:"path" mapstructure:"path"` 5 | FullPath string `json:"full_path" mapstructure:"full_path"` 6 | Filename string `json:"file" mapstructure:"file"` 7 | Host string `json:"host" mapstructure:"host"` 8 | } 9 | -------------------------------------------------------------------------------- /authstructs/get_idp_metadata.go: -------------------------------------------------------------------------------- 1 | package authstructs 2 | 3 | type GetIDPMetadataMessage struct { 4 | ContainerName string `json:"container_name"` 5 | ServerName string `json:"server_name"` 6 | IDPName string `json:"idp_name"` 7 | } 8 | type GetIDPMetadataMessageResponse struct { 9 | Success bool `json:"success"` 10 | Error string `json:"error"` 11 | Metadata string `json:"metadata"` 12 | } 13 | -------------------------------------------------------------------------------- /authstructs/get_idp_redirect.go: -------------------------------------------------------------------------------- 1 | package authstructs 2 | 3 | type GetIDPRedirectMessage struct { 4 | ContainerName string `json:"container_name"` 5 | ServerName string `json:"server_name"` 6 | IDPName string `json:"idp_name"` 7 | RequestURL string `json:"request_url"` 8 | RequestHeaders map[string]string `json:"request_headers"` 9 | RequestCookies map[string]string `json:"request_cookies"` 10 | RequestQuery map[string]string `json:"request_query"` 11 | } 12 | type GetIDPRedirectMessageResponse struct { 13 | Success bool `json:"success"` 14 | Error string `json:"error"` 15 | RedirectURL string `json:"redirect_url"` 16 | RedirectHeaders map[string]string `json:"redirect_headers"` 17 | RedirectCookies map[string]string `json:"redirect_cookies"` 18 | } 19 | -------------------------------------------------------------------------------- /authstructs/get_nonidp_metadata.go: -------------------------------------------------------------------------------- 1 | package authstructs 2 | 3 | type GetNonIDPMetadataMessage struct { 4 | ContainerName string `json:"container_name"` 5 | ServerName string `json:"server_name"` 6 | NonIDPName string `json:"nonidp_name"` 7 | } 8 | type GetNonIDPMetadataMessageResponse struct { 9 | Success bool `json:"success"` 10 | Error string `json:"error"` 11 | Metadata string `json:"metadata"` 12 | } 13 | -------------------------------------------------------------------------------- /authstructs/get_nonidp_redirect.go: -------------------------------------------------------------------------------- 1 | package authstructs 2 | 3 | type GetNonIDPRedirectMessage struct { 4 | ContainerName string `json:"container_name"` 5 | ServerName string `json:"server_name"` 6 | NonIDPName string `json:"nonidp_name"` 7 | } 8 | type GetNonIDPRedirectMessageResponse struct { 9 | Success bool `json:"success"` 10 | Error string `json:"error"` 11 | RequestFields []string `json:"request_fields"` 12 | } 13 | -------------------------------------------------------------------------------- /authstructs/process_idp_response.go: -------------------------------------------------------------------------------- 1 | package authstructs 2 | 3 | type ProcessIDPResponseMessage struct { 4 | ContainerName string `json:"container_name"` 5 | ServerName string `json:"server_name"` 6 | IDPName string `json:"idp_name"` 7 | RequestURL string `json:"request_url"` 8 | RequestHeaders map[string]string `json:"request_headers"` 9 | RequestCookies map[string]string `json:"request_cookies"` 10 | RequestQuery map[string]string `json:"request_query"` 11 | RequestBody string `json:"request_body"` 12 | } 13 | type ProcessIDPResponseMessageResponse struct { 14 | SuccessfulAuthentication bool `json:"successful_authentication"` 15 | Error string `json:"error"` 16 | Email string `json:"email"` 17 | } 18 | -------------------------------------------------------------------------------- /authstructs/process_nonidp_response.go: -------------------------------------------------------------------------------- 1 | package authstructs 2 | 3 | type ProcessNonIDPResponseMessage struct { 4 | ContainerName string `json:"container_name"` 5 | ServerName string `json:"server_name"` 6 | NonIDPName string `json:"idp_name"` 7 | RequestValues map[string]string `json:"request_values"` 8 | } 9 | type ProcessNonIDPResponseMessageResponse struct { 10 | SuccessfulAuthentication bool `json:"successful_authentication"` 11 | Error string `json:"error"` 12 | Email string `json:"email"` 13 | } 14 | -------------------------------------------------------------------------------- /c2_structs/structs_config_check.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | // C2_CONFIG_CHECK STRUCTS 4 | 5 | type C2ConfigCheckMessage struct { 6 | C2Parameters 7 | } 8 | 9 | type C2ConfigCheckMessageResponse struct { 10 | Success bool `json:"success"` 11 | Error string `json:"error"` 12 | Message string `json:"message"` 13 | RestartInternalServer bool `json:"restart_internal_server"` 14 | } 15 | -------------------------------------------------------------------------------- /c2_structs/structs_get_debug_output.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | // C2_GET_DEBUG_OUTPUT STRUCTS 4 | 5 | type C2GetDebugOutputMessage struct { 6 | Name string `json:"c2_profile_name"` 7 | } 8 | 9 | type C2GetDebugOutputMessageResponse struct { 10 | Success bool `json:"success"` 11 | Error string `json:"error"` 12 | Message string `json:"message"` 13 | InternalServerRunning bool `json:"server_running"` 14 | RestartInternalServer bool `json:"restart_internal_server"` 15 | } 16 | -------------------------------------------------------------------------------- /c2_structs/structs_get_ioc.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | // C2_GET_IOC STRUCTS 4 | 5 | // C2GetIOCMessage given the following C2 configuration, determine the IOCs that a defender should look for 6 | type C2GetIOCMessage struct { 7 | C2Parameters 8 | } 9 | 10 | // IOC identify the type of ioc with Type and the actual IOC value 11 | // An example could be a Type of URL with the actual IOC value being the configured callback URL with URI parameters 12 | type IOC struct { 13 | Type string `json:"type" mapstructure:"type"` 14 | IOC string `json:"ioc" mapstructure:"ioc"` 15 | } 16 | 17 | // C2GetIOCMessageResponse the resulting set of IOCs that a defender should look out for based on the 18 | // C2GetIOCMessage configuration 19 | type C2GetIOCMessageResponse struct { 20 | Success bool `json:"success"` 21 | Error string `json:"error"` 22 | IOCs []IOC `json:"iocs"` 23 | RestartInternalServer bool `json:"restart_internal_server"` 24 | } 25 | -------------------------------------------------------------------------------- /c2_structs/structs_get_redirector_rules.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | // C2_REDIRECTOR_RULES STRUCTS 4 | 5 | type C2_GET_REDIRECTOR_RULE_STATUS = string 6 | 7 | type C2GetRedirectorRuleMessage struct { 8 | C2Parameters 9 | } 10 | 11 | type C2GetRedirectorRuleMessageResponse struct { 12 | Success bool `json:"success"` 13 | Error string `json:"error"` 14 | Message string `json:"message"` 15 | RestartInternalServer bool `json:"restart_internal_server"` 16 | } 17 | -------------------------------------------------------------------------------- /c2_structs/structs_host_file.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | type C2_HOST_FILE_STATUS = string 4 | 5 | type C2HostFileMessage struct { 6 | Name string `json:"c2_profile_name"` 7 | FileUUID string `json:"file_uuid"` 8 | HostURL string `json:"host_url"` 9 | Remove bool `json:"remove"` 10 | } 11 | 12 | type C2HostFileMessageResponse struct { 13 | Success bool `json:"success"` 14 | Error string `json:"error"` 15 | RestartInternalServer bool `json:"restart_internal_server"` 16 | } 17 | -------------------------------------------------------------------------------- /c2_structs/structs_opsec_check.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | // C2_OPSEC_CHECKS STRUCTS 4 | 5 | type C2OPSECMessage struct { 6 | C2Parameters 7 | } 8 | 9 | type C2OPSECMessageResponse struct { 10 | Success bool `json:"success"` 11 | Error string `json:"error"` 12 | Message string `json:"message"` 13 | RestartInternalServer bool `json:"restart_internal_server"` 14 | } 15 | -------------------------------------------------------------------------------- /c2_structs/structs_resync.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | // C2_RESYNC STRUCTS 4 | 5 | type C2RPCReSyncMessage struct { 6 | Name string `json:"c2_profile_name"` 7 | } 8 | 9 | type C2RPCReSyncMessageResponse struct { 10 | Success bool `json:"success"` 11 | Error string `json:"error"` 12 | } 13 | -------------------------------------------------------------------------------- /c2_structs/structs_sample_message.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | // C2_SAMPLE_MESSAGE STRUCTS 4 | 5 | // C2SampleMessageMessage - Generate sample C2 Traffic based on this configuration so that the 6 | // operator and developer can more easily troubleshoot 7 | type C2SampleMessageMessage struct { 8 | C2Parameters 9 | } 10 | 11 | // C2SampleMessageResponse - Provide a string representation of the C2 Traffic that the corresponding 12 | // C2SampleMessageMessage configuration would generate 13 | type C2SampleMessageResponse struct { 14 | Success bool `json:"success"` 15 | Error string `json:"error"` 16 | Message string `json:"message"` 17 | RestartInternalServer bool `json:"restart_internal_server"` 18 | } 19 | -------------------------------------------------------------------------------- /c2_structs/structs_start_server.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | // C2_START_SERVER STRUCTS 4 | 5 | type C2RPCStartServerMessage struct { 6 | Name string `json:"c2_profile_name"` 7 | } 8 | 9 | type C2RPCStartServerMessageResponse struct { 10 | Success bool `json:"success"` 11 | Error string `json:"error"` 12 | Message string `json:"message"` 13 | InternalServerRunning bool `json:"server_running"` 14 | } 15 | -------------------------------------------------------------------------------- /c2_structs/structs_stop_server.go: -------------------------------------------------------------------------------- 1 | package c2structs 2 | 3 | // C2_STOP_SERVER STRUCTS 4 | 5 | type C2RPCStopServerMessage struct { 6 | Name string `json:"c2_profile_name"` 7 | } 8 | 9 | type C2RPCStopServerMessageResponse struct { 10 | Success bool `json:"success"` 11 | Error string `json:"error"` 12 | Message string `json:"message"` 13 | InternalServerRunning bool `json:"server_running"` 14 | } 15 | -------------------------------------------------------------------------------- /eventingstructs/conditional_check.go: -------------------------------------------------------------------------------- 1 | package eventingstructs 2 | 3 | type ConditionalCheckEventingMessage struct { 4 | EventStepInstanceID int `json:"eventstepinstance_id"` 5 | FunctionName string `json:"function_name"` 6 | ContainerName string `json:"container_name"` 7 | Environment map[string]interface{} `json:"environment"` 8 | Inputs map[string]interface{} `json:"inputs"` 9 | ActionData map[string]interface{} `json:"action_data"` 10 | } 11 | type ConditionalCheckEventingMessageResponse struct { 12 | EventStepInstanceID int `json:"eventstepinstance_id" mapstructure:"eventstepinstance_id"` 13 | Success bool `json:"success" mapstructure:"success"` 14 | StdOut string `json:"stdout" mapstructure:"stdout"` 15 | StdErr string `json:"stderr" mapstructure:"stderr"` 16 | Outputs map[string]interface{} `json:"outputs" mapstructure:"outputs"` 17 | SkipStep bool `json:"skip_step" mapstructure:"skip_step"` 18 | } 19 | -------------------------------------------------------------------------------- /eventingstructs/custom_function.go: -------------------------------------------------------------------------------- 1 | package eventingstructs 2 | 3 | type NewCustomEventingMessage struct { 4 | EventStepInstanceID int `json:"eventstepinstance_id"` 5 | FunctionName string `json:"function_name"` 6 | ContainerName string `json:"container_name"` 7 | Environment map[string]interface{} `json:"environment"` 8 | Inputs map[string]interface{} `json:"inputs"` 9 | ActionData map[string]interface{} `json:"action_data"` 10 | } 11 | type NewCustomEventingMessageResponse struct { 12 | EventStepInstanceID int `json:"eventstepinstance_id"` 13 | Success bool `json:"success"` 14 | StdOut string `json:"stdout"` 15 | StdErr string `json:"stderr"` 16 | Outputs map[string]interface{} `json:"outputs"` 17 | } 18 | -------------------------------------------------------------------------------- /eventingstructs/response_intercept.go: -------------------------------------------------------------------------------- 1 | package eventingstructs 2 | 3 | type ResponseInterceptMessage struct { 4 | EventStepInstanceID int `json:"eventstepinstance_id"` 5 | ResponseID int `json:"response_id"` 6 | CallbackID int `json:"callback_id"` 7 | CallbackDisplayID int `json:"callback_display_id"` 8 | AgentCallbackID string `json:"agent_callback_id"` 9 | ContainerName string `json:"container_name"` 10 | Environment map[string]interface{} `json:"environment"` 11 | Inputs map[string]interface{} `json:"inputs"` 12 | ActionData map[string]interface{} `json:"action_data"` 13 | } 14 | 15 | type ResponseInterceptMessageResponse struct { 16 | EventStepInstanceID int `json:"eventstepinstance_id" mapstructure:"eventstepinstance_id"` 17 | ResponseID int `json:"response_id" mapstructure:"response_id"` 18 | Success bool `json:"success" mapstructure:"success"` 19 | StdOut string `json:"stdout" mapstructure:"stdout"` 20 | StdErr string `json:"stderr" mapstructure:"stderr"` 21 | Outputs map[string]interface{} `json:"outputs" mapstructure:"outputs"` 22 | Response string `json:"response" mapstructure:"response"` 23 | } 24 | -------------------------------------------------------------------------------- /eventingstructs/task_intercept.go: -------------------------------------------------------------------------------- 1 | package eventingstructs 2 | 3 | type TaskInterceptMessage struct { 4 | EventStepInstanceID int `json:"eventstepinstance_id"` 5 | TaskID int `json:"task_id"` 6 | CallbackID int `json:"callback_id"` 7 | ContainerName string `json:"container_name"` 8 | Environment map[string]interface{} `json:"environment"` 9 | Inputs map[string]interface{} `json:"inputs"` 10 | ActionData map[string]interface{} `json:"action_data"` 11 | } 12 | 13 | type TaskInterceptMessageResponse struct { 14 | EventStepInstanceID int `json:"eventstepinstance_id" mapstructure:"eventstepinstance_id"` 15 | TaskID int `json:"task_id" mapstructure:"task_id"` 16 | Success bool `json:"success" mapstructure:"success"` 17 | StdOut string `json:"stdout" mapstructure:"stdout"` 18 | StdErr string `json:"stderr" mapstructure:"stderr"` 19 | BlockTask bool `json:"block_task" mapstructure:"block_task"` 20 | BypassRole OPSEC_ROLE `json:"bypass_role" mapstructure:"bypass_role"` 21 | BypassMessage string `json:"bypass_message" mapstructure:"bypass_message"` 22 | Outputs map[string]interface{} `json:"outputs" mapstructure:"outputs"` 23 | } 24 | type OPSEC_ROLE string 25 | 26 | const ( 27 | OPSEC_ROLE_LEAD OPSEC_ROLE = "lead" 28 | OPSEC_ROLE_OPERATOR = "operator" 29 | OPSEC_ROLE_OTHER_OPERATOR = "other_operator" 30 | ) 31 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/MythicMeta/MythicContainer 2 | 3 | go 1.22 4 | 5 | toolchain go1.22.2 6 | 7 | require ( 8 | github.com/google/uuid v1.6.0 9 | github.com/mitchellh/mapstructure v1.5.0 10 | github.com/rabbitmq/amqp091-go v1.10.0 11 | github.com/rs/zerolog v1.33.0 12 | github.com/spf13/viper v1.19.0 13 | google.golang.org/grpc v1.65.0 14 | google.golang.org/protobuf v1.34.2 15 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 16 | ) 17 | 18 | require ( 19 | github.com/fsnotify/fsnotify v1.7.0 // indirect 20 | github.com/hashicorp/hcl v1.0.0 // indirect 21 | github.com/magiconair/properties v1.8.7 // indirect 22 | github.com/mattn/go-colorable v0.1.13 // indirect 23 | github.com/mattn/go-isatty v0.0.20 // indirect 24 | github.com/pelletier/go-toml/v2 v2.2.2 // indirect 25 | github.com/sagikazarmark/locafero v0.6.0 // indirect 26 | github.com/sagikazarmark/slog-shim v0.1.0 // indirect 27 | github.com/sourcegraph/conc v0.3.0 // indirect 28 | github.com/spf13/afero v1.11.0 // indirect 29 | github.com/spf13/cast v1.6.0 // indirect 30 | github.com/spf13/pflag v1.0.5 // indirect 31 | github.com/subosito/gotenv v1.6.0 // indirect 32 | go.uber.org/multierr v1.11.0 // indirect 33 | golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect 34 | golang.org/x/net v0.26.0 // indirect 35 | golang.org/x/sys v0.21.0 // indirect 36 | golang.org/x/text v0.16.0 // indirect 37 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect 38 | gopkg.in/ini.v1 v1.67.0 // indirect 39 | gopkg.in/yaml.v3 v3.0.1 // indirect 40 | ) 41 | -------------------------------------------------------------------------------- /grpc/pushC2.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "math" 7 | "time" 8 | 9 | "github.com/MythicMeta/MythicContainer/config" 10 | "github.com/MythicMeta/MythicContainer/logging" 11 | "google.golang.org/grpc" 12 | "google.golang.org/grpc/credentials/insecure" 13 | ) 14 | 15 | func GetNewPushC2ClientConnection() *grpc.ClientConn { 16 | opts := []grpc.DialOption{} 17 | opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) 18 | opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt))) 19 | opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(math.MaxInt))) 20 | if config.MythicConfig.MythicServerHost == "" { 21 | log.Fatalf("[-] Missing MYTHIC_SERVER_HOST environment variable point to mythic server IP") 22 | } 23 | connectionString := fmt.Sprintf("%s:%d", config.MythicConfig.MythicServerHost, config.MythicConfig.MythicServerGRPCPort) 24 | for { 25 | logging.LogDebug("Attempting to connect to grpc...") 26 | if conn, err := grpc.Dial(connectionString, opts...); err != nil { 27 | logging.LogError(err, "Failed to connect to GRPC port for Mythic, trying again...", "connection", connectionString) 28 | } else { 29 | return conn 30 | } 31 | time.Sleep(grpcReconnectDelay * time.Second) 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /init.go: -------------------------------------------------------------------------------- 1 | package MythicContainer 2 | 3 | import ( 4 | "github.com/MythicMeta/MythicContainer/logging" 5 | "github.com/MythicMeta/MythicContainer/rabbitmq" 6 | "os" 7 | ) 8 | 9 | type MythicServices = string 10 | 11 | const ( 12 | MythicServicePayload MythicServices = "payload" 13 | MythicServiceLogger MythicServices = "logger" 14 | MythicServiceWebhook MythicServices = "webhook" 15 | MythicServiceC2 MythicServices = "c2" 16 | MythicServiceTranslationContainer MythicServices = "translation" 17 | MythicServiceEventing MythicServices = "eventing" 18 | MythicServiceAuth MythicServices = "auth" 19 | ) 20 | 21 | func StartAndRunForever(services []MythicServices) { 22 | if len(services) == 0 { 23 | logging.LogError(nil, "Must supply at least one MythicService to start") 24 | os.Exit(0) 25 | } 26 | 27 | rabbitmq.Initialize() 28 | rabbitmq.StartServices(services) 29 | 30 | forever := make(chan bool) 31 | <-forever 32 | } 33 | -------------------------------------------------------------------------------- /loggingstructs/new_artifact_log.go: -------------------------------------------------------------------------------- 1 | package loggingstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | "time" 8 | ) 9 | 10 | type NewArtifactLog struct { 11 | loggingMessageBase 12 | Data NewArtifactLogData `json:"data"` 13 | } 14 | type NewArtifactLogData struct { 15 | ID int `json:"id"` 16 | TaskID *int `json:"task_id,omitempty"` 17 | Timestamp time.Time `json:"timestamp"` 18 | Artifact []byte `json:"artifact"` 19 | BaseArtifact string `json:"base_artifact"` 20 | OperationID int `json:"operation_id"` 21 | Host string `json:"host"` 22 | } 23 | 24 | func init() { 25 | AllLoggingData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 26 | RabbitmqRoutingKey: LOG_TYPE_ARTIFACT, 27 | RabbitmqProcessingFunction: processNewArtifactLog, 28 | }) 29 | } 30 | 31 | func processNewArtifactLog(input []byte) { 32 | inputStruct := NewArtifactLog{} 33 | if err := json.Unmarshal(input, &inputStruct); err != nil { 34 | logging.LogError(err, "Failed to process message") 35 | } else { 36 | for _, webhook := range AllLoggingData.GetAllNames() { 37 | if AllLoggingData.Get(webhook).GetLoggingDefinition().NewArtifactFunction != nil { 38 | AllLoggingData.Get(webhook).GetLoggingDefinition().NewArtifactFunction(inputStruct) 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /loggingstructs/new_credential_log.go: -------------------------------------------------------------------------------- 1 | package loggingstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | "time" 8 | ) 9 | 10 | type NewCredentialLog struct { 11 | loggingMessageBase 12 | Data NewCredentialLogData `json:"data"` 13 | } 14 | type NewCredentialLogData struct { 15 | ID int `json:"id"` 16 | Type string `json:"type"` 17 | TaskID *int `json:"task_id"` 18 | Account string `json:"account"` 19 | Realm string `json:"realm"` 20 | OperationID int `json:"operation_id"` 21 | Timestamp time.Time `json:"timestamp"` 22 | Credential string `json:"credential"` 23 | OperatorID int `json:"operator_id"` 24 | Comment string `json:"comment"` 25 | Deleted bool `json:"deleted"` 26 | Metadata string `json:"metadata"` 27 | } 28 | 29 | func init() { 30 | AllLoggingData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 31 | RabbitmqRoutingKey: LOG_TYPE_CREDENTIAL, 32 | RabbitmqProcessingFunction: processNewCredentialLog, 33 | }) 34 | } 35 | 36 | func processNewCredentialLog(input []byte) { 37 | inputStruct := NewCredentialLog{} 38 | if err := json.Unmarshal(input, &inputStruct); err != nil { 39 | logging.LogError(err, "Failed to process message") 40 | } else { 41 | for _, webhook := range AllLoggingData.GetAllNames() { 42 | if AllLoggingData.Get(webhook).GetLoggingDefinition().NewCredentialFunction != nil { 43 | AllLoggingData.Get(webhook).GetLoggingDefinition().NewCredentialFunction(inputStruct) 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /loggingstructs/new_keylog_log.go: -------------------------------------------------------------------------------- 1 | package loggingstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | "time" 8 | ) 9 | 10 | type NewKeylogLog struct { 11 | loggingMessageBase 12 | Data NewKeylogLogData `json:"data"` 13 | } 14 | type NewKeylogLogData struct { 15 | ID int `json:"id" mapstructure:"id"` 16 | TaskID int `json:"task_id" mapstructure:"task_id"` 17 | Keystrokes []byte `json:"keystrokes" mapstructure:"keystrokes"` 18 | Window string `json:"window" mapstructure:"window"` 19 | Timestamp time.Time `json:"timestamp" mapstructure:"timestamp"` 20 | OperationID int `json:"operation_id" mapstructure:"operation_id"` 21 | User string `json:"user" mapstructure:"user"` 22 | } 23 | 24 | func init() { 25 | AllLoggingData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 26 | RabbitmqRoutingKey: LOG_TYPE_KEYLOG, 27 | RabbitmqProcessingFunction: processNewKeylogLog, 28 | }) 29 | } 30 | 31 | func processNewKeylogLog(input []byte) { 32 | inputStruct := NewKeylogLog{} 33 | if err := json.Unmarshal(input, &inputStruct); err != nil { 34 | logging.LogError(err, "Failed to process message") 35 | } else { 36 | for _, webhook := range AllLoggingData.GetAllNames() { 37 | if AllLoggingData.Get(webhook).GetLoggingDefinition().NewKeylogFunction != nil { 38 | AllLoggingData.Get(webhook).GetLoggingDefinition().NewKeylogFunction(inputStruct) 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /loggingstructs/new_payload_log.go: -------------------------------------------------------------------------------- 1 | package loggingstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | "time" 8 | ) 9 | 10 | type NewPayloadLog struct { 11 | loggingMessageBase 12 | Data NewPayloadLogData `json:"data"` 13 | } 14 | type NewPayloadLogData struct { 15 | ID int `json:"id"` 16 | UUID string `json:"uuid"` 17 | Description string `json:"description"` 18 | OperatorID int `json:"operator_id"` 19 | CreationTime time.Time `json:"creation_time"` 20 | PayloadTypeID int `json:"payload_type_id"` 21 | OperationID int `json:"operation_id"` 22 | WrappedPayloadID *int `json:"wrapped_payload_id"` 23 | Deleted bool `json:"deleted"` 24 | BuildContainer string `json:"build_container"` 25 | BuildPhase string `json:"build_phase"` 26 | BuildMessage string `json:"build_message"` 27 | BuildStderr string `json:"build_stderr"` 28 | BuildStdout string `json:"build_stdout"` 29 | CallbackAlert bool `json:"callback_alert"` 30 | AutoGenerated bool `json:"auto_generated"` 31 | OS string `json:"os"` 32 | TaskID *int `json:"task_id"` 33 | FileID *int `json:"file_id"` 34 | Timestamp time.Time `json:"timestamp"` 35 | } 36 | 37 | func init() { 38 | AllLoggingData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 39 | RabbitmqRoutingKey: LOG_TYPE_PAYLOAD, 40 | RabbitmqProcessingFunction: processNewPayloadLog, 41 | }) 42 | } 43 | 44 | func processNewPayloadLog(input []byte) { 45 | inputStruct := NewPayloadLog{} 46 | if err := json.Unmarshal(input, &inputStruct); err != nil { 47 | logging.LogError(err, "Failed to process message") 48 | } else { 49 | for _, webhook := range AllLoggingData.GetAllNames() { 50 | if AllLoggingData.Get(webhook).GetLoggingDefinition().NewPayloadFunction != nil { 51 | AllLoggingData.Get(webhook).GetLoggingDefinition().NewPayloadFunction(inputStruct) 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /loggingstructs/new_response_log.go: -------------------------------------------------------------------------------- 1 | package loggingstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | ) 8 | 9 | type NewResponseLog struct { 10 | loggingMessageBase 11 | Data ResponseLogData `json:"data"` 12 | } 13 | 14 | type ResponseLogData struct { 15 | ID int `json:"id" mapstructure:"id"` 16 | Response []byte `json:"response" mapstructure:"response"` 17 | TaskID int `json:"task_id" mapstructure:"task_id"` 18 | TaskDisplayID int `json:"task_display_id" mapstructure:"task_display_id"` 19 | Timestamp string `json:"timestamp" mapstructure:"timestamp"` 20 | } 21 | 22 | func init() { 23 | AllLoggingData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 24 | RabbitmqRoutingKey: LOG_TYPE_RESPONSE, 25 | RabbitmqProcessingFunction: processResponseLog, 26 | }) 27 | } 28 | 29 | func processResponseLog(input []byte) { 30 | inputStruct := NewResponseLog{} 31 | if err := json.Unmarshal(input, &inputStruct); err != nil { 32 | logging.LogError(err, "Failed to process message") 33 | } else { 34 | for _, webhook := range AllLoggingData.GetAllNames() { 35 | if AllLoggingData.Get(webhook).GetLoggingDefinition().NewResponseFunction != nil { 36 | AllLoggingData.Get(webhook).GetLoggingDefinition().NewResponseFunction(inputStruct) 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /loggingstructs/new_task_log.go: -------------------------------------------------------------------------------- 1 | package loggingstructs 2 | 3 | import ( 4 | "encoding/json" 5 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | ) 9 | 10 | type NewTaskLog struct { 11 | loggingMessageBase 12 | Data NewTaskLogData `json:"data"` 13 | } 14 | type NewTaskLogData = agentstructs.PTTaskMessageTaskData 15 | 16 | func init() { 17 | AllLoggingData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 18 | RabbitmqRoutingKey: LOG_TYPE_TASK, 19 | RabbitmqProcessingFunction: processNewTaskLog, 20 | }) 21 | } 22 | 23 | func processNewTaskLog(input []byte) { 24 | inputStruct := NewTaskLog{} 25 | if err := json.Unmarshal(input, &inputStruct); err != nil { 26 | logging.LogError(err, "Failed to process message") 27 | } else { 28 | for _, webhook := range AllLoggingData.GetAllNames() { 29 | if AllLoggingData.Get(webhook).GetLoggingDefinition().NewTaskFunction != nil { 30 | AllLoggingData.Get(webhook).GetLoggingDefinition().NewTaskFunction(inputStruct) 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_agentstorage_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCAgentstorageCreateMessage struct { 11 | // UniqueID (Required) - a unique identifier for this entry provided by you, the dev 12 | UniqueID string `json:"unique_id"` 13 | // DataToStore (Required) - the data you want to store as bytes 14 | DataToStore []byte `json:"data"` 15 | } 16 | type MythicRPCAgentstorageCreateMessageResponse struct { 17 | Success bool `json:"success"` 18 | Error string `json:"error"` 19 | } 20 | 21 | // SendMythicRPCAgentStorageCreate - Create a new entry in the agentstorage table within Mythic. 22 | // This can be used to store arbitrary data that the agent/c2 profile might need later on and used a way to share data. 23 | func SendMythicRPCAgentStorageCreate(input MythicRPCAgentstorageCreateMessage) (*MythicRPCAgentstorageCreateMessageResponse, error) { 24 | response := MythicRPCAgentstorageCreateMessageResponse{} 25 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 26 | rabbitmq.MYTHIC_EXCHANGE, 27 | rabbitmq.MYTHIC_RPC_AGENTSTORAGE_CREATE, 28 | input, 29 | ); err != nil { 30 | logging.LogError(err, "Failed to send RPC message") 31 | return nil, err 32 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 33 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 34 | return nil, err 35 | } else { 36 | return &response, nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_agentstorage_remove.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCAgentstorageRemoveMessage struct { 11 | // UniqueID (Required) - The unique identifier to search for in the database to remove 12 | UniqueID string `json:"unique_id"` 13 | } 14 | type MythicRPCAgentstorageRemoveMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | 19 | // SendMythicRPCAgentStorageRemove - Remove a specific entry from the agentstorage table within Mythic. 20 | func SendMythicRPCAgentStorageRemove(input MythicRPCAgentstorageRemoveMessage) (*MythicRPCAgentstorageRemoveMessageResponse, error) { 21 | response := MythicRPCAgentstorageRemoveMessageResponse{} 22 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 23 | rabbitmq.MYTHIC_EXCHANGE, 24 | rabbitmq.MYTHIC_RPC_AGENTSTORAGE_REMOVE, 25 | input, 26 | ); err != nil { 27 | logging.LogError(err, "Failed to send RPC message") 28 | return nil, err 29 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 30 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 31 | return nil, err 32 | } else { 33 | return &response, nil 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_agentstorage_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCAgentstorageSearchMessage struct { 11 | // SearchUniqueID (Required) - The unique identifier you supplied when creating the data that you're searching for 12 | SearchUniqueID string `json:"unique_id"` // required 13 | } 14 | type MythicRPCAgentstorageSearchMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | AgentStorageMessages []MythicRPCAgentstorageSearchResult `json:"agentstorage_messages"` 18 | } 19 | type MythicRPCAgentstorageSearchResult struct { 20 | UniqueID string `json:"unique_id"` 21 | Data []byte `json:"data"` 22 | } 23 | 24 | // SendMythicRPCAgentStorageSearch - Search for a specific entry within the agentstorage table and fetch the results. 25 | func SendMythicRPCAgentStorageSearch(input MythicRPCAgentstorageSearchMessage) (*MythicRPCAgentstorageSearchMessageResponse, error) { 26 | response := MythicRPCAgentstorageSearchMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_AGENTSTORAGE_SEARCH, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_apitoken_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | // MythicRPCAPITokenCreateMessage needs at least one parameter to generate an appropriate apitoken, the rest are unnecessary 11 | type MythicRPCAPITokenCreateMessage struct { 12 | AgentTaskID *string `json:"agent_task_id"` 13 | AgentCallbackID *string `json:"agent_callback_id"` 14 | PayloadUUID *string `json:"payload_uuid"` 15 | OperationID *int `json:"operation_id"` 16 | } 17 | 18 | // Every mythicRPC function call must return a response that includes the following two values 19 | type MythicRPCAPITokenCreateMessageResponse struct { 20 | Success bool `json:"success"` 21 | Error string `json:"error"` 22 | APIToken string `json:"apitoken"` 23 | } 24 | 25 | func SendMythicRPCAPITokenCreate(input MythicRPCAPITokenCreateMessage) (*MythicRPCAPITokenCreateMessageResponse, error) { 26 | response := MythicRPCAPITokenCreateMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_APITOKEN_CREATE, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_artifact_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCArtifactCreateMessage struct { 11 | // TaskID (Required) - the task associated with this new artifact for Mythic to track 12 | TaskID int `json:"task_id"` 13 | // ArtifactMessage (Required) - the actual artifact string you want to store 14 | ArtifactMessage string `json:"message"` 15 | // BaseArtifactType (Required) - what kind of artifact is it? Process Create? File Removal? etc 16 | BaseArtifactType string `json:"base_artifact"` 17 | // ArtifactHost (Optional) - what's the hostname for where this artifact happened? If none is specified, it's assumed to be the same host where the task ran 18 | ArtifactHost *string `json:"host,omitempty"` 19 | } 20 | type MythicRPCArtifactCreateMessageResponse struct { 21 | Success bool `json:"success"` 22 | Error string `json:"error"` 23 | } 24 | 25 | // SendMythicRPCArtifactCreate - Create a new artifact for Mythic to track. 26 | func SendMythicRPCArtifactCreate(input MythicRPCArtifactCreateMessage) (*MythicRPCArtifactCreateMessageResponse, error) { 27 | response := MythicRPCArtifactCreateMessageResponse{} 28 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 29 | rabbitmq.MYTHIC_EXCHANGE, 30 | rabbitmq.MYTHIC_RPC_ARTIFACT_CREATE, 31 | input, 32 | ); err != nil { 33 | logging.LogError(err, "Failed to send RPC message") 34 | return nil, err 35 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 36 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 37 | return nil, err 38 | } else { 39 | return &response, nil 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_artifact_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCArtifactSearchMessage struct { 11 | // TaskID (Required) - What is the current task that's searching for artifact information. 12 | TaskID int `json:"task_id"` 13 | // SearchArtifacts (Required) - Additional structure of data used to search artifacts. 14 | SearchArtifacts MythicRPCArtifactearchArtifactData `json:"artifact"` 15 | } 16 | type MythicRPCArtifactSearchMessageResponse struct { 17 | Success bool `json:"success"` 18 | Error string `json:"error"` 19 | Artifacts []MythicRPCArtifactearchArtifactData `json:"artifacts"` 20 | } 21 | type MythicRPCArtifactearchArtifactData struct { 22 | // Host (Optional) - When searching, you can filter your artifacts by the hostname. 23 | // As a response, this will always be populated. 24 | Host *string `json:"host" ` // optional 25 | // ArtifactType (Optional) - When searching, you can filter your artifacts by the type of artifact. 26 | // As a response, this will always be populated. 27 | ArtifactType *string `json:"artifact_type"` //optional 28 | // ArtifactMessage (Optional) - When searching, you can filter your artifacts by what the message contains. 29 | // As a response, this will always be populated. 30 | ArtifactMessage *string `json:"artifact_message"` //optional 31 | // TaskID (Optional) - When searching, you can filter your artifacts to those created by a certain task. 32 | // As a response, this will always be populated. 33 | TaskID *int `json:"task_id"` //optional 34 | } 35 | 36 | // SendMythicRPCArtifactSearch - Search for artifacts that are tracked by Mythic. 37 | func SendMythicRPCArtifactSearch(input MythicRPCArtifactSearchMessage) (*MythicRPCArtifactSearchMessageResponse, error) { 38 | response := MythicRPCArtifactSearchMessageResponse{} 39 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 40 | rabbitmq.MYTHIC_EXCHANGE, 41 | rabbitmq.MYTHIC_RPC_ARTIFACT_SEARCH, 42 | input, 43 | ); err != nil { 44 | logging.LogError(err, "Failed to send RPC message") 45 | return nil, err 46 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 47 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 48 | return nil, err 49 | } else { 50 | return &response, nil 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_c2_update_status.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCC2UpdateStatusMessage struct { 11 | C2Profile string `json:"c2_profile"` // required 12 | InternalServerRunning bool `json:"server_running"` // required 13 | Error string `json:"error"` 14 | } 15 | type MythicRPCC2UpdateStatusMessageResponse struct { 16 | Success bool `json:"success"` 17 | Error string `json:"error"` 18 | } 19 | 20 | // SendMythicRPCCallbackCreate - Register a new callback within Mythic 21 | func SendMythicRPCC2UpdateStatus(input MythicRPCC2UpdateStatusMessage) (*MythicRPCC2UpdateStatusMessageResponse, error) { 22 | response := MythicRPCC2UpdateStatusMessageResponse{} 23 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 24 | rabbitmq.MYTHIC_EXCHANGE, 25 | rabbitmq.MYTHIC_RPC_C2_UPDATE_STATUS, 26 | input, 27 | ); err != nil { 28 | logging.LogError(err, "Failed to send RPC message") 29 | return nil, err 30 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 31 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 32 | return nil, err 33 | } else { 34 | return &response, nil 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_callback_add_command.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCallbackAddCommandMessage struct { 11 | // TaskID - What task is trying to add commands. This will add commands to the callback associated with this task. 12 | TaskID int `json:"task_id"` // required 13 | // AgentCallbackID - Agent Callback UUID of callback to add commands to if TaskID isn't specified 14 | AgentCallbackID string `json:"agent_callback_id"` 15 | // PayloadType - The payload type of the associated commands to load if they're for a payload type (or command augment) container other than the one for the callback 16 | PayloadType string `json:"payload_type"` 17 | // Commands (Required) - The names of the commands you want to add. If they're already added, then they are skipped. 18 | Commands []string `json:"commands"` // required 19 | // CallbackIDs allows you to specify a list of CallbackID values to add commands to multiple callbacks at once 20 | CallbackIDs []int `json:"callback_ids"` 21 | } 22 | type MythicRPCCallbackAddCommandMessageResponse struct { 23 | Success bool `json:"success"` 24 | Error string `json:"error"` 25 | } 26 | 27 | // SendMythicRPCCallbackAddCommand - Register new commands as being "loaded" into the current callback. This makes them 28 | // available for tasking through the UI. 29 | func SendMythicRPCCallbackAddCommand(input MythicRPCCallbackAddCommandMessage) (*MythicRPCCallbackAddCommandMessageResponse, error) { 30 | response := MythicRPCCallbackAddCommandMessageResponse{} 31 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 32 | rabbitmq.MYTHIC_EXCHANGE, 33 | rabbitmq.MYTHIC_RPC_CALLBACK_ADD_COMMAND, 34 | input, 35 | ); err != nil { 36 | logging.LogError(err, "Failed to send RPC message") 37 | return nil, err 38 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 39 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 40 | return nil, err 41 | } else { 42 | return &response, nil 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_callback_decrypt_bytes.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCallbackDecryptBytesMessage struct { 11 | // AgentCallbackUUID (Required) - The UUID for the callback that will decrypt the message. Can also be a PayloadUUID or StagingUUID, but requires the C2Profile field as well 12 | AgentCallbackUUID string `json:"agent_callback_id"` 13 | // Message (Required) - The actual encrypted message you want to decrypt 14 | Message []byte `json:"message"` 15 | // IncludesUUID (Optional) - Does the Message include the UUID or not? 16 | IncludesUUID bool `json:"include_uuid"` 17 | // IsBase64Encoded (Optional) - Is the Message base64 encoded, or is it just the raw bytes? 18 | IsBase64Encoded bool `json:"base64_message"` 19 | // C2Profile (optional) - If using a Payload UUID then the C2 Profile is required 20 | C2Profile string `json:"c2_profile"` 21 | } 22 | type MythicRPCCallbackDecryptBytesMessageResponse struct { 23 | Success bool `json:"success"` 24 | Error string `json:"error"` 25 | Message []byte `json:"message"` 26 | } 27 | 28 | // SendMythicRPCCallbackDecryptBytes - Ask Mythic to look up the associated callback and decrypt a message for that callback 29 | func SendMythicRPCCallbackDecryptBytes(input MythicRPCCallbackDecryptBytesMessage) (*MythicRPCCallbackDecryptBytesMessageResponse, error) { 30 | response := MythicRPCCallbackDecryptBytesMessageResponse{} 31 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 32 | rabbitmq.MYTHIC_EXCHANGE, 33 | rabbitmq.MYTHIC_RPC_CALLBACK_DECRYPT_BYTES, 34 | input, 35 | ); err != nil { 36 | logging.LogError(err, "Failed to send RPC message") 37 | return nil, err 38 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 39 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 40 | return nil, err 41 | } else { 42 | return &response, nil 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_callback_display_to_real_id_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCallbackDisplayToRealIdSearchMessage struct { 11 | // CallbackDisplayID (Required) - The display id that the operator sees for a callback (i.e. 1, 2, 3, etc). 12 | // The display ID is always incremental within each operation. So, each operation will have a callback1 for example. 13 | CallbackDisplayID int `json:"callback_display_id"` 14 | // OperationName (Optional) - The name of the operation associated with the callback. 15 | // Either OperationName or OperationID must be supplied to give context for the CallbackDisplayID 16 | OperationName *string `json:"operation_name"` 17 | // OperationID (Opational) - The ID of the operation associated with the callback. 18 | // Either OperationName or OperationID must be supplied to give context for the CallbackDisplayID 19 | OperationID *int `json:"operation_id"` 20 | } 21 | 22 | // Every mythicRPC function call must return a response that includes the following two values 23 | type MythicRPCCallbackDisplayToRealIdSearchMessageResponse struct { 24 | Success bool `json:"success"` 25 | Error string `json:"error"` 26 | CallbackID int `json:"callback_id"` 27 | } 28 | 29 | // SendMythicRPCCallbackDisplayToRealIdSearch - Convert a generic CallbackDisplayID to a unique CallbackID for use with other RPC calls. 30 | func SendMythicRPCCallbackDisplayToRealIdSearch(input MythicRPCCallbackDisplayToRealIdSearchMessage) (*MythicRPCCallbackDisplayToRealIdSearchMessageResponse, error) { 31 | response := MythicRPCCallbackDisplayToRealIdSearchMessageResponse{} 32 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 33 | rabbitmq.MYTHIC_EXCHANGE, 34 | rabbitmq.MYTHIC_RPC_CALLBACK_DISPLAY_TO_REAL_ID_SEARCH, 35 | input, 36 | ); err != nil { 37 | logging.LogError(err, "Failed to send RPC message") 38 | return nil, err 39 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 40 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 41 | return nil, err 42 | } else { 43 | return &response, nil 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_callback_edge_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | "time" 6 | 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | "github.com/MythicMeta/MythicContainer/rabbitmq" 9 | ) 10 | 11 | type MythicRPCCallbackEdgeSearchMessage struct { 12 | AgentCallbackUUID string `json:"agent_callback_id"` 13 | AgentCallbackID int `json:"callback_id"` 14 | SearchC2ProfileName *string `json:"search_c2_profile_name"` 15 | SearchActiveEdgesOnly *bool `json:"search_active_edges_only"` 16 | } 17 | type MythicRPCCallbackEdgeSearchMessageResult struct { 18 | ID int `mapstructure:"id" json:"id"` 19 | StartTimestamp time.Time `mapstructure:"start_timestamp" json:"start_timestamp"` 20 | EndTimestamp time.Time `mapstructure:"end_timestamp" json:"end_timestamp"` 21 | Source MythicRPCCallbackSearchMessageResult `mapstructure:"source" json:"source"` 22 | Destination MythicRPCCallbackSearchMessageResult `mapstructure:"destination" json:"destination"` 23 | C2Profile string `mapstructure:"c2profile" json:"c2profile"` 24 | } 25 | type MythicRPCCallbackEdgeSearchMessageResponse struct { 26 | Success bool `json:"success"` 27 | Error string `json:"error"` 28 | Results []MythicRPCCallbackEdgeSearchMessageResult `json:"results"` 29 | } 30 | 31 | func SendMythicRPCCallbackEdgeSearch(input MythicRPCCallbackEdgeSearchMessage) (*MythicRPCCallbackEdgeSearchMessageResponse, error) { 32 | response := MythicRPCCallbackEdgeSearchMessageResponse{} 33 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 34 | rabbitmq.MYTHIC_EXCHANGE, 35 | rabbitmq.MYTHIC_RPC_CALLBACK_EDGE_SEARCH, 36 | input, 37 | ); err != nil { 38 | logging.LogError(err, "Failed to send RPC message") 39 | return nil, err 40 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 41 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 42 | return nil, err 43 | } else { 44 | return &response, nil 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_callback_encrypt_bytes.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCallbackEncryptBytesMessage struct { 11 | // AgentCallbackUUID (Required) - The UUID for the callback that will encrypt the message. Can also be a PayloadUUID or StagingUUID, but requires the C2Profile field as well 12 | AgentCallbackUUID string `json:"agent_callback_id"` //required 13 | // Message (Required) - The actual encrypted message you want to encrypt 14 | Message []byte `json:"message"` 15 | // IncludeUUID (Optional) - Should the encrypted message include the UUID in front? 16 | IncludeUUID bool `json:"include_uuid"` 17 | // Base64ReturnMessage (Optional) - Should the resulting Message be base64 encoded or left as raw bytes? 18 | Base64ReturnMessage bool `json:"base64_message"` 19 | // C2Profile (optional) - If using a Payload UUID then the C2 Profile is required 20 | C2Profile string `json:"c2_profile"` 21 | } 22 | type MythicRPCCallbackEncryptBytesMessageResponse struct { 23 | Success bool `json:"success"` 24 | Error string `json:"error"` 25 | Message []byte `json:"message"` 26 | } 27 | 28 | // SendMythicRPCCallbackEncryptBytes - Ask Mythic to encrypt a message for a specific callback UUID. 29 | func SendMythicRPCCallbackEncryptBytes(input MythicRPCCallbackEncryptBytesMessage) (*MythicRPCCallbackEncryptBytesMessageResponse, error) { 30 | response := MythicRPCCallbackEncryptBytesMessageResponse{} 31 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 32 | rabbitmq.MYTHIC_EXCHANGE, 33 | rabbitmq.MYTHIC_RPC_CALLBACK_ENCRYPT_BYTES, 34 | input, 35 | ); err != nil { 36 | logging.LogError(err, "Failed to send RPC message") 37 | return nil, err 38 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 39 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 40 | return nil, err 41 | } else { 42 | return &response, nil 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_callback_next_checkin_range.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | "time" 6 | 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | "github.com/MythicMeta/MythicContainer/rabbitmq" 9 | ) 10 | 11 | type MythicRPCCallbackNextCheckinRangeMessage struct { 12 | SleepInterval int `json:"sleep_interval"` 13 | SleepJitter int `json:"sleep_jitter"` 14 | LastCheckin time.Time `json:"last_checkin"` 15 | } 16 | 17 | type MythicRPCCallbackNextCheckinRangeMessageResponse struct { 18 | Success bool `json:"success"` 19 | Error string `json:"error"` 20 | Min time.Time `json:"min"` 21 | Max time.Time `json:"max"` 22 | } 23 | 24 | // SendMythicRPCCallbackEncryptBytes - Ask Mythic to encrypt a message for a specific callback UUID. 25 | func SendMythicRPCCallbackNextCheckinRange(input MythicRPCCallbackNextCheckinRangeMessage) (*MythicRPCCallbackNextCheckinRangeMessageResponse, error) { 26 | response := MythicRPCCallbackNextCheckinRangeMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_CALLBACK_NEXT_CHECKIN_RANGE, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_callback_remove_command.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCallbackRemoveCommandMessage struct { 11 | // TaskID (Required) - The task id that's going to remove commands from the associated callback. 12 | TaskID int `json:"task_id"` // required 13 | // AgentCallbackID - Agent Callback UUID of callback to add commands to if TaskID isn't specified 14 | AgentCallbackID string `json:"agent_callback_id"` 15 | // PayloadType - The payload type of the associated commands to load if they're for a payload type (or command augment) container other than the one for the callback 16 | PayloadType string `json:"payload_type"` 17 | // Commands (Required) - The list of command names to be removed from the callback. If the command isn't loaded 18 | // within the callback, then it's skipped 19 | Commands []string `json:"commands"` // required 20 | // CallbackIDs allows you to specify a list of CallbackID values to remove commands from multiple callbacks at once 21 | CallbackIDs []int `json:"callback_ids"` 22 | } 23 | type MythicRPCCallbackRemoveCommandMessageResponse struct { 24 | Success bool `json:"success"` 25 | Error string `json:"error"` 26 | } 27 | 28 | // SendMythicRPCCallbackRemoveCommand - Remove commands from a certain callback. This is helpful if you want to 29 | // unload certain functionality that might have been temporarily loaded in the first place. 30 | func SendMythicRPCCallbackRemoveCommand(input MythicRPCCallbackRemoveCommandMessage) (*MythicRPCCallbackRemoveCommandMessageResponse, error) { 31 | response := MythicRPCCallbackRemoveCommandMessageResponse{} 32 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 33 | rabbitmq.MYTHIC_EXCHANGE, 34 | rabbitmq.MYTHIC_RPC_CALLBACK_REMOVE_COMMAND, 35 | input, 36 | ); err != nil { 37 | logging.LogError(err, "Failed to send RPC message") 38 | return nil, err 39 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 40 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 41 | return nil, err 42 | } else { 43 | return &response, nil 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_callback_search_command.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCallbackSearchCommandMessage struct { 11 | CallbackID *int `json:"callback_id,omitempty"` 12 | TaskID *int `json:"task_id,omitempty"` 13 | SearchCommandNames *[]string `json:"command_names,omitempty"` 14 | SearchSupportedUIFeatures *string `json:"supported_ui_features,omitempty"` 15 | SearchScriptOnly *bool `json:"script_only,omitempty"` 16 | // this is an exact match search 17 | SearchAttributes map[string]interface{} `json:"params,omitempty"` 18 | } 19 | 20 | // Every mythicRPC function call must return a response that includes the following two values 21 | type MythicRPCCallbackSearchCommandMessageResponse struct { 22 | Success bool `json:"success"` 23 | Error string `json:"error"` 24 | Commands []MythicRPCCommandSearchCommandData `json:"commands"` 25 | } 26 | 27 | type MythicRPCCallbackSearchCommandData struct { 28 | Name string `json:"cmd"` 29 | Version int `json:"version"` 30 | Attributes map[string]interface{} `json:"attributes"` 31 | NeedsAdmin bool `json:"needs_admin"` 32 | HelpCmd string `json:"help_cmd"` 33 | Description string `json:"description"` 34 | SupportedUiFeatures []string `json:"supported_ui_features"` 35 | Author string `json:"author"` 36 | ScriptOnly bool `json:"script_only"` 37 | } 38 | 39 | func SendMythicRPCCallbackSearchCommand(input MythicRPCCallbackSearchCommandMessage) (*MythicRPCCallbackSearchCommandMessageResponse, error) { 40 | response := MythicRPCCallbackSearchCommandMessageResponse{} 41 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 42 | rabbitmq.MYTHIC_EXCHANGE, 43 | rabbitmq.MYTHIC_RPC_CALLBACK_SEARCH_COMMAND, 44 | input, 45 | ); err != nil { 46 | logging.LogError(err, "Failed to send RPC message") 47 | return nil, err 48 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 49 | logging.LogError(err, "Failed to parse SendMythicRPCCommandSearch response back to struct", "response", response) 50 | return nil, err 51 | } else { 52 | return &response, nil 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_callbacktoken_remove.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCallbackTokenRemoveMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | CallbackTokens []MythicRPCCallbackTokenRemoveCallbackTokenData `json:"callbacktokens"` 13 | } 14 | type MythicRPCCallbackTokenRemoveMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | type MythicRPCCallbackTokenRemoveCallbackTokenData = agentMessagePostResponseCallbackTokens 19 | 20 | func SendMythicRPCCallbackTokenRemove(input MythicRPCCallbackTokenRemoveMessage) (*MythicRPCCallbackTokenRemoveMessageResponse, error) { 21 | response := MythicRPCCallbackTokenRemoveMessageResponse{} 22 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 23 | rabbitmq.MYTHIC_EXCHANGE, 24 | rabbitmq.MYTHIC_RPC_CALLBACKTOKEN_REMOVE, 25 | input, 26 | ); err != nil { 27 | logging.LogError(err, "Failed to send RPC message") 28 | return nil, err 29 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 30 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 31 | return nil, err 32 | } else { 33 | return &response, nil 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_command_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCommandSearchMessage struct { 11 | SearchCommandNames *[]string `json:"command_names,omitempty"` 12 | SearchPayloadTypeName string `json:"payload_type_name"` 13 | SearchSupportedUIFeatures *string `json:"supported_ui_features,omitempty"` 14 | SearchScriptOnly *bool `json:"script_only,omitempty"` 15 | SearchOs *string `json:"os,omitempty"` 16 | // this is an exact match search 17 | SearchAttributes map[string]interface{} `json:"params,omitempty"` 18 | } 19 | 20 | // Every mythicRPC function call must return a response that includes the following two values 21 | type MythicRPCCommandSearchMessageResponse struct { 22 | Success bool `json:"success"` 23 | Error string `json:"error"` 24 | Commands []MythicRPCCommandSearchCommandData `json:"commands"` 25 | } 26 | 27 | type MythicRPCCommandSearchCommandData struct { 28 | Name string `json:"cmd"` 29 | Version int `json:"version"` 30 | Attributes map[string]interface{} `json:"attributes"` 31 | NeedsAdmin bool `json:"needs_admin"` 32 | HelpCmd string `json:"help_cmd"` 33 | Description string `json:"description"` 34 | SupportedUiFeatures []string `json:"supported_ui_features"` 35 | Author string `json:"author"` 36 | ScriptOnly bool `json:"script_only"` 37 | } 38 | 39 | func SendMythicRPCCommandSearch(input MythicRPCCommandSearchMessage) (*MythicRPCCommandSearchMessageResponse, error) { 40 | response := MythicRPCCommandSearchMessageResponse{} 41 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 42 | rabbitmq.MYTHIC_EXCHANGE, 43 | rabbitmq.MYTHIC_RPC_COMMAND_SEARCH, 44 | input, 45 | ); err != nil { 46 | logging.LogError(err, "Failed to send RPC message") 47 | return nil, err 48 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 49 | logging.LogError(err, "Failed to parse SendMythicRPCCommandSearch response back to struct", "response", response) 50 | return nil, err 51 | } else { 52 | return &response, nil 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_credential_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCredentialCreateMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | Credentials []MythicRPCCredentialCreateCredentialData `json:"credentials"` 13 | } 14 | type MythicRPCCredentialCreateMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | type MythicRPCCredentialCreateCredentialData = agentMessagePostResponseCredentials 19 | type agentMessagePostResponseCredentials struct { 20 | CredentialType string `json:"credential_type" mapstructure:"credential_type"` 21 | Realm string `json:"realm" mapstructure:"realm"` 22 | Account string `json:"account" mapstructure:"account"` 23 | Credential string `json:"credential" mapstructure:"credential"` 24 | Comment string `json:"comment" mapstructure:"comment"` 25 | ExtraData string `json:"metadata" mapstructure:"metadata"` 26 | } 27 | 28 | func SendMythicRPCCredentialCreate(input MythicRPCCredentialCreateMessage) (*MythicRPCCredentialCreateMessageResponse, error) { 29 | response := MythicRPCCredentialCreateMessageResponse{} 30 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 31 | rabbitmq.MYTHIC_EXCHANGE, 32 | rabbitmq.MYTHIC_RPC_CREDENTIAL_CREATE, 33 | input, 34 | ); err != nil { 35 | logging.LogError(err, "Failed to send RPC message") 36 | return nil, err 37 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 38 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 39 | return nil, err 40 | } else { 41 | return &response, nil 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_credential_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCCredentialSearchMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | SearchCredentials MythicRPCCredentialSearchCredentialData `json:"credentials"` 13 | } 14 | type MythicRPCCredentialSearchMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | Credentials []MythicRPCCredentialSearchCredentialData `json:"credentials"` 18 | } 19 | type MythicRPCCredentialSearchCredentialData struct { 20 | Type *string `json:"type" ` // optional 21 | Account *string `json:"account" ` // optional 22 | Realm *string `json:"realm" ` // optional 23 | Credential *string `json:"credential"` // optional 24 | Comment *string `json:"comment"` // optional 25 | Metadata *string `json:"metadata"` // optional 26 | } 27 | 28 | func SendMythicRPCCredentialSearch(input MythicRPCCredentialSearchMessage) (*MythicRPCCredentialSearchMessageResponse, error) { 29 | response := MythicRPCCredentialSearchMessageResponse{} 30 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 31 | rabbitmq.MYTHIC_EXCHANGE, 32 | rabbitmq.MYTHIC_RPC_CREDENTIAL_SEARCH, 33 | input, 34 | ); err != nil { 35 | logging.LogError(err, "Failed to send RPC message") 36 | return nil, err 37 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 38 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 39 | return nil, err 40 | } else { 41 | return &response, nil 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_file_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | "github.com/MythicMeta/MythicContainer/utils/mythicutils" 9 | ) 10 | 11 | // MythicRPCFileCreateMessage Must supply one of TaskID, PayloadUUID, or AgentCallbackID so that Mythic can track the file for the right operation 12 | type MythicRPCFileCreateMessage struct { 13 | TaskID int `json:"task_id"` 14 | PayloadUUID string `json:"payload_uuid"` 15 | AgentCallbackID string `json:"agent_callback_id"` 16 | FileContents []byte `json:"-"` 17 | DeleteAfterFetch bool `json:"delete_after_fetch"` 18 | Filename string `json:"filename"` 19 | IsScreenshot bool `json:"is_screenshot"` 20 | IsDownloadFromAgent bool `json:"is_download"` 21 | RemotePathOnTarget string `json:"remote_path"` 22 | TargetHostName string `json:"host"` 23 | Comment string `json:"comment"` 24 | } 25 | type MythicRPCFileCreateMessageResponse struct { 26 | Success bool `json:"success"` 27 | Error string `json:"error"` 28 | AgentFileId string `json:"agent_file_id"` 29 | } 30 | 31 | func SendMythicRPCFileCreate(input MythicRPCFileCreateMessage) (*MythicRPCFileCreateMessageResponse, error) { 32 | response := MythicRPCFileCreateMessageResponse{} 33 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 34 | rabbitmq.MYTHIC_EXCHANGE, 35 | rabbitmq.MYTHIC_RPC_FILE_CREATE, 36 | input, 37 | ); err != nil { 38 | logging.LogError(err, "Failed to send RPC message") 39 | return nil, err 40 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 41 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 42 | return nil, err 43 | } else if response.Success { 44 | if err := mythicutils.SendFileToMythic(&input.FileContents, response.AgentFileId); err != nil { 45 | logging.LogError(err, "Failed to send file contents to Mythic") 46 | return nil, err 47 | } else { 48 | return &response, nil 49 | } 50 | } else { 51 | return &response, nil 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_file_get_content.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import "github.com/MythicMeta/MythicContainer/utils/mythicutils" 4 | 5 | type MythicRPCFileGetContentMessage struct { 6 | AgentFileID string `json:"file_id"` 7 | } 8 | 9 | // Every mythicRPC function call must return a response that includes the following two values 10 | type MythicRPCFileGetContentMessageResponse struct { 11 | Success bool `json:"success"` 12 | Error string `json:"error"` 13 | Content []byte `json:"content"` 14 | } 15 | 16 | func SendMythicRPCFileGetContent(input MythicRPCFileGetContentMessage) (*MythicRPCFileGetContentMessageResponse, error) { 17 | response := MythicRPCFileGetContentMessageResponse{} 18 | if content, err := mythicutils.GetFileFromMythic(input.AgentFileID); err != nil { 19 | response.Success = false 20 | response.Error = err.Error() 21 | return &response, nil 22 | } else { 23 | response.Success = true 24 | response.Content = *content 25 | return &response, nil 26 | } 27 | /* 28 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 29 | rabbitmq.MYTHIC_EXCHANGE, 30 | rabbitmq.MYTHIC_RPC_FILE_GET_CONTENT, 31 | input, 32 | ); err != nil { 33 | logging.LogError(err, "Failed to send RPC message") 34 | return nil, err 35 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 36 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 37 | return nil, err 38 | } else { 39 | return &response, nil 40 | } 41 | */ 42 | } 43 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_file_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | "time" 6 | 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | "github.com/MythicMeta/MythicContainer/rabbitmq" 9 | ) 10 | 11 | type MythicRPCFileSearchMessage struct { 12 | TaskID int `json:"task_id"` 13 | CallbackID int `json:"callback_id"` 14 | Filename string `json:"filename"` 15 | LimitByCallback bool `json:"limit_by_callback"` 16 | MaxResults int `json:"max_results"` 17 | Comment string `json:"comment"` 18 | AgentFileID string `json:"file_id"` 19 | IsPayload bool `json:"is_payload"` 20 | IsDownloadFromAgent bool `json:"is_download_from_agent"` 21 | IsScreenshot bool `json:"is_screenshot"` 22 | } 23 | type FileData struct { 24 | AgentFileId string `json:"agent_file_id"` 25 | Filename string `json:"filename"` 26 | Comment string `json:"comment"` 27 | Complete bool `json:"complete"` 28 | IsPayload bool `json:"is_payload"` 29 | IsDownloadFromAgent bool `json:"is_download_from_agent"` 30 | IsScreenshot bool `json:"is_screenshot"` 31 | FullRemotePath string `json:"full_remote_path"` 32 | Host string `json:"host"` 33 | TaskID int `json:"task_id"` 34 | Md5 string `json:"md5"` 35 | Sha1 string `json:"sha1"` 36 | Timestamp time.Time `json:"timestamp"` 37 | Command string `json:"cmd"` 38 | Tags []string `json:"tags"` 39 | } 40 | 41 | // Every mythicRPC function call must return a response that includes the following two values 42 | type MythicRPCFileSearchMessageResponse struct { 43 | Success bool `json:"success"` 44 | Error string `json:"error"` 45 | Files []FileData `json:"files"` 46 | } 47 | 48 | func SendMythicRPCFileSearch(input MythicRPCFileSearchMessage) (*MythicRPCFileSearchMessageResponse, error) { 49 | response := MythicRPCFileSearchMessageResponse{} 50 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 51 | rabbitmq.MYTHIC_EXCHANGE, 52 | rabbitmq.MYTHIC_RPC_FILE_SEARCH, 53 | input, 54 | ); err != nil { 55 | logging.LogError(err, "Failed to send RPC message") 56 | return nil, err 57 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 58 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 59 | return nil, err 60 | } else { 61 | return &response, nil 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_file_update.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | "github.com/MythicMeta/MythicContainer/utils/mythicutils" 9 | ) 10 | 11 | type MythicRPCFileUpdateMessage struct { 12 | AgentFileID string `json:"file_id"` 13 | Comment string `json:"comment"` 14 | Filename string `json:"filename"` 15 | AppendContents *[]byte `json:"append_contents,omitempty"` 16 | ReplaceContents *[]byte `json:"-"` 17 | Delete bool `json:"delete"` 18 | DeleteAfterFetch *bool `json:"delete_after_fetch"` 19 | } 20 | 21 | // Every mythicRPC function call must return a response that includes the following two values 22 | type MythicRPCFileUpdateMessageResponse struct { 23 | Success bool `json:"success"` 24 | Error string `json:"error"` 25 | } 26 | 27 | func SendMythicRPCFileUpdate(input MythicRPCFileUpdateMessage) (*MythicRPCFileUpdateMessageResponse, error) { 28 | response := MythicRPCFileUpdateMessageResponse{} 29 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 30 | rabbitmq.MYTHIC_EXCHANGE, 31 | rabbitmq.MYTHIC_RPC_FILE_UPDATE, 32 | input, 33 | ); err != nil { 34 | logging.LogError(err, "Failed to send RPC message") 35 | return nil, err 36 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 37 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 38 | return nil, err 39 | } else if response.Success { 40 | if input.ReplaceContents != nil { 41 | if err := mythicutils.SendFileToMythic(input.ReplaceContents, input.AgentFileID); err != nil { 42 | response.Success = false 43 | response.Error = err.Error() 44 | } 45 | } 46 | return &response, nil 47 | } else { 48 | return &response, nil 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_filebrowser_parse_path.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCFileBrowserParsePathMessage struct { 11 | Path string `json:"path"` 12 | } 13 | type MythicRPCFileBrowserParsePathMessageResponse struct { 14 | Success bool `json:"success"` 15 | Error string `json:"error"` 16 | AnalyzedPath AnalyzedPath `json:"analyzed_path"` 17 | } 18 | type AnalyzedPath struct { 19 | PathPieces []string `json:"path_pieces"` 20 | PathSeparator string `json:"path_separator"` 21 | Host string `json:"host"` 22 | } 23 | 24 | func SendMythicRPCFileBrowserParsePath(input MythicRPCFileBrowserParsePathMessage) (*MythicRPCFileBrowserParsePathMessageResponse, error) { 25 | response := MythicRPCFileBrowserParsePathMessageResponse{} 26 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 27 | rabbitmq.MYTHIC_EXCHANGE, 28 | rabbitmq.MYTHIC_RPC_FILEBROWSER_PARSE_PATH, 29 | input, 30 | ); err != nil { 31 | logging.LogError(err, "Failed to send RPC message") 32 | return nil, err 33 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 34 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 35 | return nil, err 36 | } else { 37 | return &response, nil 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_filebrowser_remove.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCFileBrowserRemoveMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | RemovedFiles []MythicRPCFileBrowserRemoveFileBrowserData `json:"removed_files"` 13 | } 14 | type MythicRPCFileBrowserRemoveMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | type MythicRPCFileBrowserRemoveFileBrowserData = agentMessagePostResponseRemovedFiles 19 | type agentMessagePostResponseRemovedFiles struct { 20 | Host *string `json:"host,omitempty" mapstructure:"host,omitempty"` 21 | Path string `json:"path" mapstructure:"path"` // full path to file removed 22 | } 23 | 24 | func SendMythicRPCFileBrowserRemove(input MythicRPCFileBrowserRemoveMessage) (*MythicRPCFileBrowserRemoveMessageResponse, error) { 25 | response := MythicRPCFileBrowserRemoveMessageResponse{} 26 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 27 | rabbitmq.MYTHIC_EXCHANGE, 28 | rabbitmq.MYTHIC_RPC_FILEBROWSER_REMOVE, 29 | input, 30 | ); err != nil { 31 | logging.LogError(err, "Failed to send RPC message") 32 | return nil, err 33 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 34 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 35 | return nil, err 36 | } else { 37 | return &response, nil 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_keylog_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCKeylogCreateMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | Keylogs []MythicRPCKeylogCreateProcessData `json:"keylogs"` 13 | } 14 | type MythicRPCKeylogCreateMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | type MythicRPCKeylogCreateProcessData = agentMessagePostResponseKeylogs 19 | type agentMessagePostResponseKeylogs struct { 20 | WindowTitle string `json:"window_title" mapstructure:"window_title"` 21 | User string `json:"user" mapstructure:"user"` 22 | Keystrokes string `json:"keystrokes" mapstructure:"keystrokes"` 23 | } 24 | 25 | func SendMythicRPCKeylogCreate(input MythicRPCKeylogCreateMessage) (*MythicRPCKeylogCreateMessageResponse, error) { 26 | response := MythicRPCKeylogCreateMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_KEYLOG_CREATE, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_keylog_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCKeylogSearchMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | SearchKeylogs MythicRPCKeylogSearchKeylogData `json:"keylogs"` 13 | } 14 | type MythicRPCKeylogSearchMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | Keylogs []MythicRPCKeylogSearchKeylogData `json:"keylogs"` 18 | } 19 | type MythicRPCKeylogSearchKeylogData struct { 20 | User *string `json:"user" ` // optional 21 | WindowTitle *string `json:"window_title" ` // optional 22 | Keystrokes *[]byte `json:"keystrokes" ` // optional 23 | } 24 | 25 | func SendMythicRPCKeylogSearch(input MythicRPCKeylogSearchMessage) (*MythicRPCKeylogSearchMessageResponse, error) { 26 | response := MythicRPCKeylogSearchMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_KEYLOG_SEARCH, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_operationeventlog_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MESSAGE_LEVEL = string 11 | 12 | const ( 13 | MESSAGE_LEVEL_INFO MESSAGE_LEVEL = "info" 14 | MESSAGE_LEVEL_WARNING = "warning" 15 | ) 16 | 17 | type MythicRPCOperationEventLogCreateMessage struct { 18 | // three optional ways to specify the operation 19 | TaskId *int `json:"task_id"` 20 | CallbackId *int `json:"callback_id"` 21 | CallbackAgentId *string `json:"callback_agent_id"` 22 | OperationId *int `json:"operation_id"` 23 | // the data to store 24 | Message string `json:"message"` 25 | MessageLevel MESSAGE_LEVEL `json:"level"` //info or warning 26 | } 27 | type MythicRPCOperationEventLogCreateMessageResponse struct { 28 | Success bool `json:"success"` 29 | Error string `json:"error"` 30 | } 31 | 32 | func SendMythicRPCOperationEventLogCreate(input MythicRPCOperationEventLogCreateMessage) (*MythicRPCOperationEventLogCreateMessageResponse, error) { 33 | response := MythicRPCOperationEventLogCreateMessageResponse{} 34 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 35 | rabbitmq.MYTHIC_EXCHANGE, 36 | rabbitmq.MYTHIC_RPC_EVENTLOG_CREATE, 37 | input, 38 | ); err != nil { 39 | logging.LogError(err, "Failed to send RPC message") 40 | return nil, err 41 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 42 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 43 | return nil, err 44 | } else { 45 | return &response, nil 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_other_service_rpc.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | "github.com/MythicMeta/MythicContainer/rabbitmq" 9 | ) 10 | 11 | type MythicRPCOtherServiceRPCMessage struct { 12 | ServiceName string `json:"service_name"` //required 13 | ServiceRPCFunction string `json:"service_function"` 14 | ServiceRPCFunctionArguments map[string]interface{} `json:"service_arguments"` 15 | } 16 | type MythicRPCOtherServiceRPCMessageResponse struct { 17 | Success bool `json:"success"` 18 | Error string `json:"error"` 19 | Result map[string]interface{} `json:"result"` 20 | } 21 | 22 | func getMythicRPCOtherServiceRPCRoutingKey(service string) string { 23 | return fmt.Sprintf("%s_%s", service, rabbitmq.MYTHIC_RPC_OTHER_SERVICES_RPC) 24 | } 25 | func SendMythicRPCOtherServiceRPC(input MythicRPCOtherServiceRPCMessage) (*MythicRPCOtherServiceRPCMessageResponse, error) { 26 | response := MythicRPCOtherServiceRPCMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | getMythicRPCOtherServiceRPCRoutingKey(input.ServiceName), 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_payload_add_comand.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCPayloadAddCommandMessage struct { 11 | PayloadUUID string `json:"payload_uuid"` //required 12 | Commands []string `json:"commands"` // required 13 | } 14 | type MythicRPCPayloadAddCommandMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | 19 | func SendMythicRPCPayloadAddCommand(input MythicRPCPayloadAddCommandMessage) (*MythicRPCPayloadAddCommandMessageResponse, error) { 20 | response := MythicRPCPayloadAddCommandMessageResponse{} 21 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 22 | rabbitmq.MYTHIC_EXCHANGE, 23 | rabbitmq.MYTHIC_RPC_PAYLOAD_ADD_COMMAND, 24 | input, 25 | ); err != nil { 26 | logging.LogError(err, "Failed to send RPC message") 27 | return nil, err 28 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 29 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 30 | return nil, err 31 | } else { 32 | return &response, nil 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_payload_create_from_scratch.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCPayloadCreateFromScratchMessage struct { 11 | TaskID int `json:"task_id"` 12 | PayloadConfiguration PayloadConfiguration `json:"payload_configuration"` 13 | RemoteHost *string `json:"remote_host"` 14 | } 15 | 16 | // Every mythicRPC function call must return a response that includes the following two values 17 | type MythicRPCPayloadCreateFromScratchMessageResponse struct { 18 | Success bool `json:"success"` 19 | Error string `json:"error"` 20 | NewPayloadUUID string `json:"new_payload_uuid"` 21 | } 22 | 23 | func SendMythicRPCPayloadCreateFromScratch(input MythicRPCPayloadCreateFromScratchMessage) (*MythicRPCPayloadCreateFromScratchMessageResponse, error) { 24 | response := MythicRPCPayloadCreateFromScratchMessageResponse{} 25 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 26 | rabbitmq.MYTHIC_EXCHANGE, 27 | rabbitmq.MYTHIC_RPC_PAYLOAD_CREATE_FROM_SCRATCH, 28 | input, 29 | ); err != nil { 30 | logging.LogError(err, "Failed to send RPC message") 31 | return nil, err 32 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 33 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 34 | return nil, err 35 | } else { 36 | return &response, nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_payload_create_from_uuid.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCPayloadCreateFromUUIDMessage struct { 11 | PayloadUUID string `json:"uuid"` 12 | TaskID int `json:"task_id"` 13 | NewDescription *string `json:"new_description"` 14 | NewFilename *string `json:"new_filename"` 15 | RemoteHost *string `json:"remote_host"` 16 | } 17 | 18 | // Every mythicRPC function call must return a response that includes the following two values 19 | type MythicRPCPayloadCreateFromUUIDMessageResponse struct { 20 | Success bool `json:"success"` 21 | Error string `json:"error"` 22 | NewPayloadUUID string `json:"new_payload_uuid"` 23 | } 24 | 25 | func SendMythicRPCPayloadCreateFromUuid(input MythicRPCPayloadCreateFromUUIDMessage) (*MythicRPCPayloadCreateFromUUIDMessageResponse, error) { 26 | response := MythicRPCPayloadCreateFromUUIDMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_PAYLOAD_CREATE_FROM_UUID, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_payload_get_content.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import "github.com/MythicMeta/MythicContainer/utils/mythicutils" 4 | 5 | type MythicRPCPayloadGetContentMessage struct { 6 | PayloadUUID string `json:"uuid"` 7 | } 8 | 9 | // Every mythicRPC function call must return a response that includes the following two values 10 | type MythicRPCPayloadGetContentMessageResponse struct { 11 | Success bool `json:"success"` 12 | Error string `json:"error"` 13 | Content []byte `json:"content"` 14 | } 15 | 16 | func SendMythicRPCPayloadGetContent(input MythicRPCPayloadGetContentMessage) (*MythicRPCPayloadGetContentMessageResponse, error) { 17 | response := MythicRPCPayloadGetContentMessageResponse{} 18 | if contents, err := mythicutils.GetFileFromMythic(input.PayloadUUID); err != nil { 19 | response.Error = err.Error() 20 | response.Success = false 21 | } else { 22 | response.Success = true 23 | response.Content = *contents 24 | } 25 | return &response, nil 26 | /* 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_PAYLOAD_GET_PAYLOAD_CONTENT, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | 41 | */ 42 | } 43 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_payload_remove_comand.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCPayloadRemoveCommandMessage struct { 11 | PayloadUUID string `json:"payload_uuid"` //required 12 | Commands []string `json:"commands"` // required 13 | } 14 | type MythicRPCPayloadRemoveCommandMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | 19 | func SendMythicRPCPayloadRemoveCommand(input MythicRPCPayloadRemoveCommandMessage) (*MythicRPCPayloadRemoveCommandMessageResponse, error) { 20 | response := MythicRPCPayloadRemoveCommandMessageResponse{} 21 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 22 | rabbitmq.MYTHIC_EXCHANGE, 23 | rabbitmq.MYTHIC_RPC_PAYLOAD_REMOVE_COMMAND, 24 | input, 25 | ); err != nil { 26 | logging.LogError(err, "Failed to send RPC message") 27 | return nil, err 28 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 29 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 30 | return nil, err 31 | } else { 32 | return &response, nil 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_payload_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCPayloadSearchMessage struct { 11 | CallbackID int `json:"callback_id"` 12 | PayloadUUID string `json:"uuid"` 13 | Description string `json:"description"` 14 | Filename string `json:"filename"` 15 | PayloadTypes []string `json:"payload_types"` 16 | IncludeAutoGeneratedPayloads bool `json:"include_auto_generated"` 17 | BuildParameters []MythicRPCPayloadSearchBuildParameter `json:"build_parameters"` 18 | } 19 | 20 | type MythicRPCPayloadSearchBuildParameter struct { 21 | PayloadType string `json:"payload_type"` 22 | BuildParameterValues map[string]string `json:"build_parameter_values"` 23 | } 24 | 25 | // Every mythicRPC function call must return a response that includes the following two values 26 | type MythicRPCPayloadSearchMessageResponse struct { 27 | Success bool `json:"success"` 28 | Error string `json:"error"` 29 | PayloadConfigurations []PayloadConfiguration `json:"payloads"` 30 | } 31 | 32 | func SendMythicRPCPayloadSearch(input MythicRPCPayloadSearchMessage) (*MythicRPCPayloadSearchMessageResponse, error) { 33 | response := MythicRPCPayloadSearchMessageResponse{} 34 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 35 | rabbitmq.MYTHIC_EXCHANGE, 36 | rabbitmq.MYTHIC_RPC_PAYLOAD_SEARCH, 37 | input, 38 | ); err != nil { 39 | logging.LogError(err, "Failed to send RPC message") 40 | return nil, err 41 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 42 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 43 | return nil, err 44 | } else { 45 | return &response, nil 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_payload_update_build_step.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCPayloadUpdateBuildStepMessage struct { 11 | PayloadUUID string `json:"payload_uuid"` 12 | StepName string `json:"step_name"` 13 | StepStdout string `json:"step_stdout"` 14 | StepStderr string `json:"step_stderr"` 15 | StepSuccess bool `json:"step_success"` 16 | StepSkip bool `json:"step_skip"` 17 | } 18 | 19 | // Every mythicRPC function call must return a response that includes the following two values 20 | type MythicRPCPayloadUpdateBuildStepMessageResponse struct { 21 | Success bool `json:"success"` 22 | Error string `json:"error"` 23 | } 24 | 25 | func SendMythicRPCPayloadUpdateBuildStep(input MythicRPCPayloadUpdateBuildStepMessage) (*MythicRPCPayloadUpdateBuildStepMessageResponse, error) { 26 | response := MythicRPCPayloadUpdateBuildStepMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_PAYLOAD_UPDATE_BUILD_STEP, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse MythicRPCPayloadUpdateBuildStepMessageResponse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_payloadonhost_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCPayloadOnHostCreateMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | PayloadOnHost MythicRPCPayloadOnHostCreateData `json:"payload_on_host"` 13 | } 14 | type MythicRPCPayloadOnHostCreateMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | type MythicRPCPayloadOnHostCreateData struct { 19 | Host string `json:"host"` 20 | PayloadId *int `json:"payload_id"` 21 | PayloadUUID *string `json:"payload_uuid"` 22 | } 23 | 24 | func SendMythicRPCPayloadOnHostCreate(input MythicRPCPayloadOnHostCreateMessage) (*MythicRPCPayloadOnHostCreateMessageResponse, error) { 25 | response := MythicRPCPayloadOnHostCreateMessageResponse{} 26 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 27 | rabbitmq.MYTHIC_EXCHANGE, 28 | rabbitmq.MYTHIC_RPC_PAYLOADONHOST_CREATE, 29 | input, 30 | ); err != nil { 31 | logging.LogError(err, "Failed to send RPC message") 32 | return nil, err 33 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 34 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 35 | return nil, err 36 | } else { 37 | return &response, nil 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_process_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCProcessSearchMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | SearchProcess MythicRPCProcessSearchProcessData `json:"process"` 13 | } 14 | type MythicRPCProcessSearchMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | Processes []MythicRPCProcessSearchProcessData `json:"processes"` 18 | } 19 | type MythicRPCProcessSearchProcessData struct { 20 | Host *string `json:"host" ` // optional 21 | ProcessID *int `json:"process_id" ` // optional 22 | Architecture *string `json:"architecture"` // optional 23 | ParentProcessID *int `json:"parent_process_id" ` // optional 24 | BinPath *string `json:"bin_path" ` // optional 25 | Name *string `json:"name" ` // optional 26 | User *string `json:"user" ` // optional 27 | CommandLine *string `json:"command_line" ` // optional 28 | IntegrityLevel *int `json:"integrity_level" ` // optional 29 | Description *string `json:"description" ` // optional 30 | Signer *string `json:"signer"` // optional 31 | } 32 | 33 | func SendMythicRPCProcessSearch(input MythicRPCProcessSearchMessage) (*MythicRPCProcessSearchMessageResponse, error) { 34 | response := MythicRPCProcessSearchMessageResponse{} 35 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 36 | rabbitmq.MYTHIC_EXCHANGE, 37 | rabbitmq.MYTHIC_RPC_PROCESS_SEARCH, 38 | input, 39 | ); err != nil { 40 | logging.LogError(err, "Failed to send RPC message") 41 | return nil, err 42 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 43 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 44 | return nil, err 45 | } else { 46 | return &response, nil 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_proxy_start.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCProxyStartMessage struct { 11 | // TaskID - the TaskID that's starting the proxy connection 12 | TaskID int `json:"task_id"` 13 | // LocalPort - for SOCKS, this is the port to open on the Mythic server. 14 | // For interactive, this is the port to open on the Mythic server 15 | // For rpfwd, this is the port to open on the host where your agent is running. 16 | LocalPort int `json:"local_port"` 17 | // RemotePort - This only needs to be set for rpfwd - this is the remote port to connect to when the LocalPort gets a connection 18 | RemotePort int `json:"remote_port"` 19 | // RemoteIP - This only needs to be set for rpfwd - this is the remote ip to connect to when the LocalPort gets a connection 20 | RemoteIP string `json:"remote_ip"` 21 | // PortType - What type of proxy connection are you opening 22 | // CALLBACK_PORT_TYPE_SOCKS 23 | // CALLBACK_PORT_TYPE_RPORTFWD 24 | // CALLBACK_PORT_TYPE_INTERACTIVE 25 | PortType string `json:"port_type"` 26 | // Username - This only can be set for socks - this allows auth for connecting to the port opened on the Mythic server 27 | Username string `json:"username"` 28 | // Password - This only can be set for socks - this allows auth for connecting to the port opened on the Mythic server 29 | Password string `json:"password"` 30 | } 31 | type MythicRPCProxyStartMessageResponse struct { 32 | Success bool `json:"success"` 33 | Error string `json:"error"` 34 | LocalPort int `json:"local_port"` 35 | } 36 | 37 | func SendMythicRPCProxyStart(input MythicRPCProxyStartMessage) (*MythicRPCProxyStartMessageResponse, error) { 38 | response := MythicRPCProxyStartMessageResponse{} 39 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 40 | rabbitmq.MYTHIC_EXCHANGE, 41 | rabbitmq.MYTHIC_RPC_PROXY_START, 42 | input, 43 | ); err != nil { 44 | logging.LogError(err, "Failed to send RPC message") 45 | return nil, err 46 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 47 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 48 | return nil, err 49 | } else { 50 | return &response, nil 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_proxy_stop.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCProxyStopMessage struct { 11 | TaskID int `json:"task_id"` 12 | Port int `json:"port"` 13 | PortType string `json:"port_type"` 14 | Username string `json:"username"` 15 | Password string `json:"password"` 16 | } 17 | type MythicRPCProxyStopMessageResponse struct { 18 | Success bool `json:"success"` 19 | Error string `json:"error"` 20 | LocalPort int `json:"local_port"` 21 | } 22 | 23 | func SendMythicRPCProxyStop(input MythicRPCProxyStopMessage) (*MythicRPCProxyStopMessageResponse, error) { 24 | response := MythicRPCProxyStopMessageResponse{} 25 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 26 | rabbitmq.MYTHIC_EXCHANGE, 27 | rabbitmq.MYTHIC_RPC_PROXY_STOP, 28 | input, 29 | ); err != nil { 30 | logging.LogError(err, "Failed to send RPC message") 31 | return nil, err 32 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 33 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 34 | return nil, err 35 | } else { 36 | return &response, nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_response_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCResponseCreateMessage struct { 11 | TaskID int `json:"task_id"` 12 | Response []byte `json:"response"` 13 | } 14 | type MythicRPCResponseCreateMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | 19 | func SendMythicRPCResponseCreate(input MythicRPCResponseCreateMessage) (*MythicRPCResponseCreateMessageResponse, error) { 20 | response := MythicRPCResponseCreateMessageResponse{} 21 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 22 | rabbitmq.MYTHIC_EXCHANGE, 23 | rabbitmq.MYTHIC_RPC_RESPONSE_CREATE, 24 | input, 25 | ); err != nil { 26 | logging.LogError(err, "Failed to send RPC message") 27 | return nil, err 28 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 29 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 30 | return nil, err 31 | } else { 32 | return &response, nil 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_response_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCResponseSearchMessage struct { 11 | TaskID int `json:"task_id"` 12 | Response string `json:"response"` 13 | } 14 | type MythicRPCResponseSearchMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | Responses []MythicRPCResponse `json:"responses"` 18 | } 19 | type MythicRPCResponse struct { 20 | ResponseID int `json:"response_id"` 21 | Response []byte `json:"response"` 22 | TaskID int `json:"task_id"` 23 | } 24 | 25 | func SendMythicRPCResponseSearch(input MythicRPCResponseSearchMessage) (*MythicRPCResponseSearchMessageResponse, error) { 26 | response := MythicRPCResponseSearchMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_RESPONSE_SEARCH, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_tag_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTagCreateMessage struct { 11 | TagTypeID int `json:"tagtype_id"` 12 | URL string `json:"url"` 13 | Source string `json:"source"` 14 | Data map[string]interface{} `json:"data"` 15 | TaskID *int `json:"task_id"` 16 | FileID *int `json:"file_id"` 17 | CredentialID *int `json:"credential_id"` 18 | MythicTreeID *int `json:"mythic_tree_id"` 19 | } 20 | 21 | // Every mythicRPC function call must return a response that includes the following two values 22 | type MythicRPCTagCreateMessageResponse struct { 23 | Success bool `json:"success"` 24 | Error string `json:"error"` 25 | Tag MythicRPCTagData `json:"tag"` 26 | } 27 | 28 | func SendMythicRPCTagCreate(input MythicRPCTagCreateMessage) (*MythicRPCTagCreateMessageResponse, error) { 29 | response := MythicRPCTagCreateMessageResponse{} 30 | responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 31 | rabbitmq.MYTHIC_EXCHANGE, 32 | rabbitmq.MYTHIC_RPC_TAG_CREATE, 33 | input, 34 | ) 35 | if err != nil { 36 | logging.LogError(err, "Failed to send RPC message") 37 | return nil, err 38 | } 39 | err = json.Unmarshal(responseBytes, &response) 40 | if err != nil { 41 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 42 | return nil, err 43 | } 44 | return &response, nil 45 | } 46 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_tagtype_get_or_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTagTypeGetOrCreateMessage struct { 11 | TaskID int `json:"task_id"` 12 | GetOrCreateTagTypeID *int `json:"get_or_create_tag_type_id"` 13 | GetOrCreateTagTypeName *string `json:"get_or_create_tag_type_name"` 14 | GetOrCreateTagTypeDescription *string `json:"get_or_create_tag_type_description"` 15 | GetOrCreateTagTypeColor *string `json:"get_or_create_tag_type_color"` 16 | } 17 | 18 | // Every mythicRPC function call must return a response that includes the following two values 19 | type MythicRPCTagTypeGetOrCreateMessageResponse struct { 20 | Success bool `json:"success"` 21 | Error string `json:"error"` 22 | TagType MythicRPCTagTypeData `json:"tagtype"` 23 | } 24 | 25 | func SendMythicRPCTagTypeGetOrCreate(input MythicRPCTagTypeGetOrCreateMessage) (*MythicRPCTagTypeGetOrCreateMessageResponse, error) { 26 | response := MythicRPCTagTypeGetOrCreateMessageResponse{} 27 | responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_TAGTYPE_GET_OR_CREATE, 30 | input, 31 | ) 32 | if err != nil { 33 | logging.LogError(err, "Failed to send RPC message") 34 | return nil, err 35 | } 36 | err = json.Unmarshal(responseBytes, &response) 37 | if err != nil { 38 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 39 | return nil, err 40 | } 41 | return &response, nil 42 | } 43 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_task_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTaskCreateMessage struct { 11 | AgentCallbackID string `json:"agent_callback_id"` 12 | CommandName string `json:"command_name"` 13 | Params string `json:"params"` 14 | ParameterGroupName *string `json:"parameter_group_name,omitempty"` 15 | Token *int `json:"token,omitempty"` 16 | } 17 | 18 | // Every mythicRPC function call must return a response that includes the following two values 19 | type MythicRPCTaskCreateMessageResponse struct { 20 | Success bool `json:"success"` 21 | Error string `json:"error"` 22 | TaskID int `json:"task_id"` 23 | TaskDisplayID int `json:"task_display_id"` 24 | } 25 | 26 | func SendMythicRPCTaskCreate(input MythicRPCTaskCreateMessage) (*MythicRPCTaskCreateMessageResponse, error) { 27 | response := MythicRPCTaskCreateMessageResponse{} 28 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 29 | rabbitmq.MYTHIC_EXCHANGE, 30 | rabbitmq.MYTHIC_RPC_TASK_CREATE, 31 | input, 32 | ); err != nil { 33 | logging.LogError(err, "Failed to send RPC message") 34 | return nil, err 35 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 36 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 37 | return nil, err 38 | } else { 39 | return &response, nil 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_task_create_subtask group.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTaskCreateSubtaskGroupMessage struct { 11 | TaskID int `json:"task_id"` // required 12 | GroupName string `json:"group_name"` // required 13 | GroupCallbackFunction *string `json:"group_callback_function,omitempty"` 14 | Tasks []MythicRPCTaskCreateSubtaskGroupTasks `json:"tasks"` // required 15 | 16 | } 17 | 18 | type MythicRPCTaskCreateSubtaskGroupTasks struct { 19 | SubtaskCallbackFunction *string `json:"subtask_callback_function,omitempty"` 20 | CommandName string `json:"command_name"` // required 21 | Params string `json:"params"` // required 22 | ParameterGroupName *string `json:"parameter_group_name,omitempty"` 23 | Token *int `json:"token,omitempty"` 24 | } 25 | 26 | // Every mythicRPC function call must return a response that includes the following two values 27 | type MythicRPCTaskCreateSubtaskGroupMessageResponse struct { 28 | Success bool `json:"success"` 29 | Error string `json:"error"` 30 | TaskIDs []int `json:"task_ids"` 31 | } 32 | 33 | func SendMythicRPCTaskCreateSubtaskGroup(input MythicRPCTaskCreateSubtaskGroupMessage) (*MythicRPCTaskCreateSubtaskGroupMessageResponse, error) { 34 | response := MythicRPCTaskCreateSubtaskGroupMessageResponse{} 35 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 36 | rabbitmq.MYTHIC_EXCHANGE, 37 | rabbitmq.MYTHIC_RPC_TASK_CREATE_SUBTASK_GROUP, 38 | input, 39 | ); err != nil { 40 | logging.LogError(err, "Failed to send RPC message") 41 | return nil, err 42 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 43 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 44 | return nil, err 45 | } else { 46 | return &response, nil 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_task_create_subtask.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTaskCreateSubtaskMessage struct { 11 | TaskID int `json:"task_id"` 12 | SubtaskCallbackFunction *string `json:"subtask_callback_function,omitempty"` 13 | CommandName string `json:"command_name"` 14 | Params string `json:"params"` 15 | ParameterGroupName *string `json:"parameter_group_name,omitempty"` 16 | Token *int `json:"token,omitempty"` 17 | } 18 | 19 | // Every mythicRPC function call must return a response that includes the following two values 20 | type MythicRPCTaskCreateSubtaskMessageResponse struct { 21 | Success bool `json:"success"` 22 | Error string `json:"error"` 23 | TaskID int `json:"task_id"` 24 | } 25 | 26 | func SendMythicRPCTaskCreateSubtask(input MythicRPCTaskCreateSubtaskMessage) (*MythicRPCTaskCreateSubtaskMessageResponse, error) { 27 | response := MythicRPCTaskCreateSubtaskMessageResponse{} 28 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 29 | rabbitmq.MYTHIC_EXCHANGE, 30 | rabbitmq.MYTHIC_RPC_TASK_CREATE_SUBTASK, 31 | input, 32 | ); err != nil { 33 | logging.LogError(err, "Failed to send RPC message") 34 | return nil, err 35 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 36 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 37 | return nil, err 38 | } else { 39 | return &response, nil 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_task_display_to_real_id_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTaskDisplayToRealIdSearchMessage struct { 11 | TaskDisplayID int `json:"task_display_id"` 12 | OperationName *string `json:"operation_name"` 13 | OperationID *int `json:"operation_id"` 14 | } 15 | 16 | // Every mythicRPC function call must return a response that includes the following two values 17 | type MythicRPCTaskDisplayToRealIdSearchMessageResponse struct { 18 | Success bool `json:"success"` 19 | Error string `json:"error"` 20 | TaskID int `json:"task_id"` 21 | } 22 | 23 | func SendMythicRPCTaskDisplayToRealIdSearch(input MythicRPCTaskDisplayToRealIdSearchMessage) (*MythicRPCTaskDisplayToRealIdSearchMessageResponse, error) { 24 | response := MythicRPCTaskDisplayToRealIdSearchMessageResponse{} 25 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 26 | rabbitmq.MYTHIC_EXCHANGE, 27 | rabbitmq.MYTHIC_RPC_TASK_DISPLAY_TO_REAL_ID_SEARCH, 28 | input, 29 | ); err != nil { 30 | logging.LogError(err, "Failed to send RPC message") 31 | return nil, err 32 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 33 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 34 | return nil, err 35 | } else { 36 | return &response, nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_task_search.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTaskSearchMessage struct { 11 | TaskID int `json:"task_id"` 12 | SearchTaskID *int `json:"search_task_id"` 13 | SearchTaskDisplayID *int `json:"search_task_display_id"` 14 | SearchAgentTaskID *string `json:"agent_task_id,omitempty"` 15 | SearchHost *string `json:"host,omitempty"` 16 | SearchCallbackID *int `json:"callback_id,omitempty"` 17 | SearchCompleted *bool `json:"completed,omitempty"` 18 | SearchCommandNames *[]string `json:"command_names,omitempty"` 19 | SearchParams *string `json:"params,omitempty"` 20 | SearchParentTaskID *int `json:"parent_task_id,omitempty"` 21 | } 22 | 23 | // Every mythicRPC function call must return a response that includes the following two values 24 | type MythicRPCTaskSearchMessageResponse struct { 25 | Success bool `json:"success"` 26 | Error string `json:"error"` 27 | Tasks []PTTaskMessageTaskData `json:"tasks"` 28 | } 29 | 30 | func SendMythicRPCTaskSearch(input MythicRPCTaskSearchMessage) (*MythicRPCTaskSearchMessageResponse, error) { 31 | response := MythicRPCTaskSearchMessageResponse{} 32 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 33 | rabbitmq.MYTHIC_EXCHANGE, 34 | rabbitmq.MYTHIC_RPC_TASK_SEARCH, 35 | input, 36 | ); err != nil { 37 | logging.LogError(err, "Failed to send RPC message") 38 | return nil, err 39 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 40 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 41 | return nil, err 42 | } else { 43 | return &response, nil 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_task_update.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTaskUpdateMessage struct { 11 | TaskID int `json:"task_id"` 12 | UpdateStatus *string `json:"update_status,omitempty"` 13 | UpdateStdout *string `json:"update_stdout,omitempty"` 14 | UpdateStderr *string `json:"update_stderr,omitempty"` 15 | UpdateCommandName *string `json:"update_command_name,omitempty"` 16 | UpdateCompleted *bool `json:"update_completed,omitempty"` 17 | } 18 | 19 | // Every mythicRPC function call must return a response that includes the following two values 20 | type MythicRPCTaskUpdateMessageResponse struct { 21 | Success bool `json:"success"` 22 | Error string `json:"error"` 23 | } 24 | 25 | func SendMythicRPCTaskUpdate(input MythicRPCTaskUpdateMessage) (*MythicRPCTaskUpdateMessageResponse, error) { 26 | response := MythicRPCTaskUpdateMessageResponse{} 27 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 28 | rabbitmq.MYTHIC_EXCHANGE, 29 | rabbitmq.MYTHIC_RPC_TASK_UPDATE, 30 | input, 31 | ); err != nil { 32 | logging.LogError(err, "Failed to send RPC message") 33 | return nil, err 34 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 35 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 36 | return nil, err 37 | } else { 38 | return &response, nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_token_create.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTokenCreateMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | Tokens []MythicRPCTokenCreateTokenData `json:"tokens"` 13 | } 14 | type MythicRPCTokenCreateMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | type MythicRPCTokenCreateTokenData = agentMessagePostResponseToken 19 | 20 | func SendMythicRPCTokenCreate(input MythicRPCTokenCreateMessage) (*MythicRPCTokenCreateMessageResponse, error) { 21 | response := MythicRPCTokenCreateMessageResponse{} 22 | for i := 0; i < len(input.Tokens); i++ { 23 | input.Tokens[i].Action = "add" 24 | } 25 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 26 | rabbitmq.MYTHIC_EXCHANGE, 27 | rabbitmq.MYTHIC_RPC_TOKEN_CREATE, 28 | input, 29 | ); err != nil { 30 | logging.LogError(err, "Failed to send RPC message") 31 | return nil, err 32 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 33 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 34 | return nil, err 35 | } else { 36 | return &response, nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mythicrpc/send_mythic_rpc_token_remove.go: -------------------------------------------------------------------------------- 1 | package mythicrpc 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/rabbitmq" 8 | ) 9 | 10 | type MythicRPCTokenRemoveMessage struct { 11 | TaskID int `json:"task_id"` //required 12 | Tokens []MythicRPCTokenRemoveTokenData `json:"tokens"` 13 | } 14 | type MythicRPCTokenRemoveMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | } 18 | type MythicRPCTokenRemoveTokenData = agentMessagePostResponseToken 19 | 20 | func SendMythicRPCTokenRemove(input MythicRPCTokenRemoveMessage) (*MythicRPCTokenRemoveMessageResponse, error) { 21 | response := MythicRPCTokenRemoveMessageResponse{} 22 | for i := 0; i < len(input.Tokens); i++ { 23 | input.Tokens[i].Action = "remove" 24 | } 25 | if responseBytes, err := rabbitmq.RabbitMQConnection.SendRPCStructMessage( 26 | rabbitmq.MYTHIC_EXCHANGE, 27 | rabbitmq.MYTHIC_RPC_TOKEN_REMOVE, 28 | input, 29 | ); err != nil { 30 | logging.LogError(err, "Failed to send RPC message") 31 | return nil, err 32 | } else if err := json.Unmarshal(responseBytes, &response); err != nil { 33 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 34 | return nil, err 35 | } else { 36 | return &response, nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rabbitmq/recv_auth_rpc_get_idp_metadata.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/authstructs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | "slices" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | authstructs.AllAuthData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: AUTH_RPC_GET_IDP_METADATA, 15 | RabbitmqProcessingFunction: processAuthRPCGetIDPMetadata, 16 | }) 17 | } 18 | 19 | func processAuthRPCGetIDPMetadata(msg []byte) interface{} { 20 | input := authstructs.GetIDPMetadataMessage{} 21 | responseMsg := authstructs.GetIDPMetadataMessageResponse{ 22 | Success: false, 23 | Error: "Not implemented, not getting metadata", 24 | } 25 | if err := json.Unmarshal(msg, &input); err != nil { 26 | logging.LogError(err, "Failed to unmarshal JSON into struct") 27 | responseMsg.Success = false 28 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 29 | } else { 30 | return AuthRPCGetIDPMetadata(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func AuthRPCGetIDPMetadata(input authstructs.GetIDPMetadataMessage) authstructs.GetIDPMetadataMessageResponse { 36 | responseMsg := authstructs.GetIDPMetadataMessageResponse{ 37 | Success: false, 38 | Error: "Failed to find right container with a non-nil function", 39 | } 40 | for _, eventing := range authstructs.AllAuthData.GetAllNames() { 41 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().Name == input.ContainerName { 42 | if slices.Contains(authstructs.AllAuthData.Get(eventing).GetAuthDefinition().IDPServices, input.IDPName) { 43 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().GetIDPMetadata != nil { 44 | response := authstructs.AllAuthData.Get(eventing).GetAuthDefinition().GetIDPMetadata(input) 45 | return response 46 | } 47 | } 48 | } 49 | } 50 | return responseMsg 51 | } 52 | -------------------------------------------------------------------------------- /rabbitmq/recv_auth_rpc_get_idp_redirect.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/authstructs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | "slices" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | authstructs.AllAuthData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: AUTH_RPC_GET_IDP_REDIRECT, 15 | RabbitmqProcessingFunction: processAuthRPCGetIDPRedirect, 16 | }) 17 | } 18 | 19 | func processAuthRPCGetIDPRedirect(msg []byte) interface{} { 20 | input := authstructs.GetIDPRedirectMessage{} 21 | responseMsg := authstructs.GetIDPRedirectMessageResponse{ 22 | Success: false, 23 | Error: "Not implemented, not getting debug output", 24 | } 25 | if err := json.Unmarshal(msg, &input); err != nil { 26 | logging.LogError(err, "Failed to unmarshal JSON into struct") 27 | responseMsg.Success = false 28 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 29 | } else { 30 | return AuthRPCGetIDPRedirect(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func AuthRPCGetIDPRedirect(input authstructs.GetIDPRedirectMessage) authstructs.GetIDPRedirectMessageResponse { 36 | responseMsg := authstructs.GetIDPRedirectMessageResponse{ 37 | Success: false, 38 | Error: "Failed to find right container with a non-nil function", 39 | } 40 | for _, eventing := range authstructs.AllAuthData.GetAllNames() { 41 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().Name == input.ContainerName { 42 | if slices.Contains(authstructs.AllAuthData.Get(eventing).GetAuthDefinition().IDPServices, input.IDPName) { 43 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().GetIDPRedirect != nil { 44 | return authstructs.AllAuthData.Get(eventing).GetAuthDefinition().GetIDPRedirect(input) 45 | } 46 | } 47 | 48 | } 49 | } 50 | return responseMsg 51 | } 52 | -------------------------------------------------------------------------------- /rabbitmq/recv_auth_rpc_get_nonidp_metadata.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/authstructs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | "slices" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | authstructs.AllAuthData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: AUTH_RPC_GET_NONIDP_METADATA, 15 | RabbitmqProcessingFunction: processAuthRPCGetNonIDPMetadata, 16 | }) 17 | } 18 | 19 | func processAuthRPCGetNonIDPMetadata(msg []byte) interface{} { 20 | input := authstructs.GetNonIDPMetadataMessage{} 21 | responseMsg := authstructs.GetNonIDPMetadataMessageResponse{ 22 | Success: false, 23 | Error: "Not implemented, not getting metadata", 24 | } 25 | if err := json.Unmarshal(msg, &input); err != nil { 26 | logging.LogError(err, "Failed to unmarshal JSON into struct") 27 | responseMsg.Success = false 28 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 29 | } else { 30 | return AuthRPCGetNonIDPMetadata(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func AuthRPCGetNonIDPMetadata(input authstructs.GetNonIDPMetadataMessage) authstructs.GetNonIDPMetadataMessageResponse { 36 | responseMsg := authstructs.GetNonIDPMetadataMessageResponse{ 37 | Success: false, 38 | Error: "Failed to find right container with a non-nil function", 39 | } 40 | for _, eventing := range authstructs.AllAuthData.GetAllNames() { 41 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().Name == input.ContainerName { 42 | if slices.Contains(authstructs.AllAuthData.Get(eventing).GetAuthDefinition().NonIDPServices, input.NonIDPName) { 43 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().GetNonIDPMetadata != nil { 44 | response := authstructs.AllAuthData.Get(eventing).GetAuthDefinition().GetNonIDPMetadata(input) 45 | return response 46 | } 47 | } 48 | } 49 | } 50 | return responseMsg 51 | } 52 | -------------------------------------------------------------------------------- /rabbitmq/recv_auth_rpc_get_nonidp_redirect.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/authstructs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | "slices" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | authstructs.AllAuthData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: AUTH_RPC_GET_NONIDP_REDIRECT, 15 | RabbitmqProcessingFunction: processAuthRPCGetNonIDPRedirect, 16 | }) 17 | } 18 | 19 | func processAuthRPCGetNonIDPRedirect(msg []byte) interface{} { 20 | input := authstructs.GetNonIDPRedirectMessage{} 21 | responseMsg := authstructs.GetNonIDPRedirectMessageResponse{ 22 | Success: false, 23 | Error: "Not implemented, not getting debug output", 24 | } 25 | if err := json.Unmarshal(msg, &input); err != nil { 26 | logging.LogError(err, "Failed to unmarshal JSON into struct") 27 | responseMsg.Success = false 28 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 29 | } else { 30 | return AuthRPCGetNonIDPRedirect(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func AuthRPCGetNonIDPRedirect(input authstructs.GetNonIDPRedirectMessage) authstructs.GetNonIDPRedirectMessageResponse { 36 | responseMsg := authstructs.GetNonIDPRedirectMessageResponse{ 37 | Success: false, 38 | Error: "Failed to find right container with a non-nil function", 39 | } 40 | for _, eventing := range authstructs.AllAuthData.GetAllNames() { 41 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().Name == input.ContainerName { 42 | if slices.Contains(authstructs.AllAuthData.Get(eventing).GetAuthDefinition().NonIDPServices, input.NonIDPName) { 43 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().GetNonIDPRedirect != nil { 44 | return authstructs.AllAuthData.Get(eventing).GetAuthDefinition().GetNonIDPRedirect(input) 45 | } 46 | } 47 | 48 | } 49 | } 50 | return responseMsg 51 | } 52 | -------------------------------------------------------------------------------- /rabbitmq/recv_auth_rpc_process_idp_response.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/authstructs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | "slices" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | authstructs.AllAuthData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: AUTH_RPC_PROCESS_IDP_RESPONSE, 15 | RabbitmqProcessingFunction: processAuthRPCProcessIDPResponse, 16 | }) 17 | } 18 | 19 | func processAuthRPCProcessIDPResponse(msg []byte) interface{} { 20 | input := authstructs.ProcessIDPResponseMessage{} 21 | responseMsg := authstructs.ProcessIDPResponseMessageResponse{ 22 | SuccessfulAuthentication: false, 23 | Error: "Not implemented, not authing", 24 | } 25 | if err := json.Unmarshal(msg, &input); err != nil { 26 | logging.LogError(err, "Failed to unmarshal JSON into struct") 27 | responseMsg.SuccessfulAuthentication = false 28 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 29 | } else { 30 | return AuthRPCProcessIDPResponse(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func AuthRPCProcessIDPResponse(input authstructs.ProcessIDPResponseMessage) authstructs.ProcessIDPResponseMessageResponse { 36 | responseMsg := authstructs.ProcessIDPResponseMessageResponse{ 37 | SuccessfulAuthentication: false, 38 | Error: "Failed to find right container with a non-nil function", 39 | } 40 | for _, eventing := range authstructs.AllAuthData.GetAllNames() { 41 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().Name == input.ContainerName { 42 | if slices.Contains(authstructs.AllAuthData.Get(eventing).GetAuthDefinition().IDPServices, input.IDPName) { 43 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().ProcessIDPResponse != nil { 44 | return authstructs.AllAuthData.Get(eventing).GetAuthDefinition().ProcessIDPResponse(input) 45 | } 46 | } 47 | 48 | } 49 | } 50 | return responseMsg 51 | } 52 | -------------------------------------------------------------------------------- /rabbitmq/recv_auth_rpc_process_nonidp_response.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/authstructs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | "slices" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | authstructs.AllAuthData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: AUTH_RPC_PROCESS_NONIDP_RESPONSE, 15 | RabbitmqProcessingFunction: processAuthRPCProcessNonIDPResponse, 16 | }) 17 | } 18 | 19 | func processAuthRPCProcessNonIDPResponse(msg []byte) interface{} { 20 | input := authstructs.ProcessNonIDPResponseMessage{} 21 | responseMsg := authstructs.ProcessNonIDPResponseMessageResponse{ 22 | SuccessfulAuthentication: false, 23 | Error: "Not implemented, not authing", 24 | } 25 | if err := json.Unmarshal(msg, &input); err != nil { 26 | logging.LogError(err, "Failed to unmarshal JSON into struct") 27 | responseMsg.SuccessfulAuthentication = false 28 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 29 | } else { 30 | return AuthRPCProcessNonIDPResponse(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func AuthRPCProcessNonIDPResponse(input authstructs.ProcessNonIDPResponseMessage) authstructs.ProcessNonIDPResponseMessageResponse { 36 | responseMsg := authstructs.ProcessNonIDPResponseMessageResponse{ 37 | SuccessfulAuthentication: false, 38 | Error: "Failed to find right container with a non-nil function", 39 | } 40 | for _, eventing := range authstructs.AllAuthData.GetAllNames() { 41 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().Name == input.ContainerName { 42 | if slices.Contains(authstructs.AllAuthData.Get(eventing).GetAuthDefinition().NonIDPServices, input.NonIDPName) { 43 | if authstructs.AllAuthData.Get(eventing).GetAuthDefinition().ProcessNonIDPResponse != nil { 44 | return authstructs.AllAuthData.Get(eventing).GetAuthDefinition().ProcessNonIDPResponse(input) 45 | } 46 | } 47 | 48 | } 49 | } 50 | return responseMsg 51 | } 52 | -------------------------------------------------------------------------------- /rabbitmq/recv_c2_rpc_config_check.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/c2_structs" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | "github.com/MythicMeta/MythicContainer/logging" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | c2structs.AllC2Data.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: C2_RPC_CONFIG_CHECK_ROUTING_KEY, 15 | RabbitmqProcessingFunction: processC2RPCConfigCheck, 16 | }) 17 | } 18 | 19 | // All rabbitmq methods must take byte inputs and return an interface. 20 | // However, we can cast these to the input and return types defined in this file 21 | func processC2RPCConfigCheck(msg []byte) interface{} { 22 | input := c2structs.C2ConfigCheckMessage{} 23 | responseMsg := c2structs.C2ConfigCheckMessageResponse{} 24 | if err := json.Unmarshal(msg, &input); err != nil { 25 | logging.LogError(err, "Failed to unmarshal JSON into struct") 26 | responseMsg.Success = false 27 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 28 | } else { 29 | // actually do config checks on configCheck 30 | return C2RPCConfigCheck(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func C2RPCConfigCheck(input c2structs.C2ConfigCheckMessage) c2structs.C2ConfigCheckMessageResponse { 36 | responseMsg := c2structs.C2ConfigCheckMessageResponse{ 37 | Success: true, 38 | Error: "No Config Check performed - passing by default", 39 | } 40 | c2Mutex.Lock() 41 | if c2structs.AllC2Data.Get(input.Name).GetC2Definition().ConfigCheckFunction != nil { 42 | responseMsg = c2structs.AllC2Data.Get(input.Name).GetC2Definition().ConfigCheckFunction(input) 43 | } 44 | c2Mutex.Unlock() 45 | if responseMsg.RestartInternalServer { 46 | go restartC2Server(input.Name) 47 | } 48 | return responseMsg 49 | } 50 | -------------------------------------------------------------------------------- /rabbitmq/recv_c2_rpc_get_ioc.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/c2_structs" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | "github.com/MythicMeta/MythicContainer/logging" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | c2structs.AllC2Data.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: C2_RPC_GET_IOC_ROUTING_KEY, 15 | RabbitmqProcessingFunction: processC2RPCGetIOC, 16 | }) 17 | } 18 | 19 | // All rabbitmq methods must take byte inputs and return an interface. 20 | // However, we can cast these to the input and return types defined in this file 21 | func processC2RPCGetIOC(msg []byte) interface{} { 22 | input := c2structs.C2GetIOCMessage{} 23 | responseMsg := c2structs.C2GetIOCMessageResponse{} 24 | if err := json.Unmarshal(msg, &input); err != nil { 25 | logging.LogError(err, "Failed to unmarshal JSON into struct") 26 | responseMsg.Success = false 27 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 28 | } else { 29 | // actually do C2RPCGetIOC 30 | return C2RPCGetIOC(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func C2RPCGetIOC(input c2structs.C2GetIOCMessage) c2structs.C2GetIOCMessageResponse { 36 | responseMsg := c2structs.C2GetIOCMessageResponse{ 37 | Success: true, 38 | Error: "No IOCs configured", 39 | } 40 | c2Mutex.Lock() 41 | if c2structs.AllC2Data.Get(input.Name).GetC2Definition().GetIOCFunction != nil { 42 | responseMsg = c2structs.AllC2Data.Get(input.Name).GetC2Definition().GetIOCFunction(input) 43 | } 44 | c2Mutex.Unlock() 45 | if responseMsg.RestartInternalServer { 46 | go restartC2Server(input.Name) 47 | } 48 | return responseMsg 49 | } 50 | -------------------------------------------------------------------------------- /rabbitmq/recv_c2_rpc_get_redirector_rules.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/c2_structs" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | "github.com/MythicMeta/MythicContainer/logging" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | c2structs.AllC2Data.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: C2_RPC_REDIRECTOR_RULES_ROUTING_KEY, 15 | RabbitmqProcessingFunction: processC2RPCGetRedirectorRules, 16 | }) 17 | } 18 | 19 | func processC2RPCGetRedirectorRules(msg []byte) interface{} { 20 | input := c2structs.C2GetRedirectorRuleMessage{} 21 | responseMsg := c2structs.C2GetRedirectorRuleMessageResponse{} 22 | if err := json.Unmarshal(msg, &input); err != nil { 23 | logging.LogError(err, "Failed to unmarshal JSON into struct") 24 | responseMsg.Success = false 25 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 26 | } else { 27 | return C2RPCGetRedirectorRules(input) 28 | } 29 | return responseMsg 30 | } 31 | 32 | func C2RPCGetRedirectorRules(input c2structs.C2GetRedirectorRuleMessage) c2structs.C2GetRedirectorRuleMessageResponse { 33 | responseMsg := c2structs.C2GetRedirectorRuleMessageResponse{ 34 | Success: false, 35 | Error: "Not implemented, not getting redirector rules", 36 | } 37 | c2Mutex.Lock() 38 | if c2structs.AllC2Data.Get(input.Name).GetC2Definition().GetRedirectorRulesFunction != nil { 39 | responseMsg = c2structs.AllC2Data.Get(input.Name).GetC2Definition().GetRedirectorRulesFunction(input) 40 | } 41 | c2Mutex.Unlock() 42 | if responseMsg.RestartInternalServer { 43 | go restartC2Server(input.Name) 44 | } 45 | return responseMsg 46 | } 47 | -------------------------------------------------------------------------------- /rabbitmq/recv_c2_rpc_host_file.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/c2_structs" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | "github.com/MythicMeta/MythicContainer/logging" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | c2structs.AllC2Data.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: C2_RPC_HOST_FILE, 15 | RabbitmqProcessingFunction: processC2RPCHostFile, 16 | }) 17 | } 18 | 19 | func processC2RPCHostFile(msg []byte) interface{} { 20 | input := c2structs.C2HostFileMessage{} 21 | responseMsg := c2structs.C2HostFileMessageResponse{} 22 | if err := json.Unmarshal(msg, &input); err != nil { 23 | logging.LogError(err, "Failed to unmarshal JSON into struct") 24 | responseMsg.Success = false 25 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 26 | } else { 27 | return C2RPCHostFile(input) 28 | } 29 | return responseMsg 30 | } 31 | 32 | func C2RPCHostFile(input c2structs.C2HostFileMessage) c2structs.C2HostFileMessageResponse { 33 | responseMsg := c2structs.C2HostFileMessageResponse{ 34 | Success: false, 35 | Error: "Not implemented, not hosting a file", 36 | } 37 | c2Mutex.Lock() 38 | if c2structs.AllC2Data.Get(input.Name).GetC2Definition().HostFileFunction != nil { 39 | responseMsg = c2structs.AllC2Data.Get(input.Name).GetC2Definition().HostFileFunction(input) 40 | } 41 | c2Mutex.Unlock() 42 | if responseMsg.RestartInternalServer { 43 | go restartC2Server(input.Name) 44 | } 45 | return responseMsg 46 | } 47 | -------------------------------------------------------------------------------- /rabbitmq/recv_c2_rpc_opsec_check.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/c2_structs" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | "github.com/MythicMeta/MythicContainer/logging" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | c2structs.AllC2Data.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: C2_RPC_OPSEC_CHECKS_ROUTING_KEY, 15 | RabbitmqProcessingFunction: processC2RPCOpsecCheck, 16 | }) 17 | } 18 | 19 | func processC2RPCOpsecCheck(msg []byte) interface{} { 20 | input := c2structs.C2OPSECMessage{} 21 | responseMsg := c2structs.C2OPSECMessageResponse{} 22 | if err := json.Unmarshal(msg, &input); err != nil { 23 | logging.LogError(err, "Failed to unmarshal JSON into struct") 24 | responseMsg.Success = false 25 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 26 | } else { 27 | return C2RPCOpsecCheck(input) 28 | } 29 | 30 | return responseMsg 31 | } 32 | 33 | func C2RPCOpsecCheck(input c2structs.C2OPSECMessage) c2structs.C2OPSECMessageResponse { 34 | responseMsg := c2structs.C2OPSECMessageResponse{ 35 | Success: true, 36 | Error: "No OPSEC Check performed - passing by default", 37 | } 38 | c2Mutex.Lock() 39 | if c2structs.AllC2Data.Get(input.Name).GetC2Definition().OPSECCheckFunction != nil { 40 | responseMsg = c2structs.AllC2Data.Get(input.Name).GetC2Definition().OPSECCheckFunction(input) 41 | } 42 | c2Mutex.Unlock() 43 | if responseMsg.RestartInternalServer { 44 | go restartC2Server(input.Name) 45 | } 46 | return responseMsg 47 | } 48 | -------------------------------------------------------------------------------- /rabbitmq/recv_c2_rpc_resync.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/c2_structs" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | "github.com/MythicMeta/MythicContainer/logging" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | c2structs.AllC2Data.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: C2_RPC_RESYNC_ROUTING_KEY, 15 | RabbitmqProcessingFunction: processC2RPCReSync, 16 | }) 17 | } 18 | 19 | // All rabbitmq methods must take byte inputs and return an interface. 20 | // However, we can cast these to the input and return types defined in this file 21 | func processC2RPCReSync(msg []byte) interface{} { 22 | input := c2structs.C2RPCReSyncMessage{} 23 | responseMsg := c2structs.C2RPCReSyncMessageResponse{} 24 | if err := json.Unmarshal(msg, &input); err != nil { 25 | logging.LogError(err, "Failed to unmarshal JSON into struct") 26 | responseMsg.Success = false 27 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 28 | } else { 29 | // actually do config checks on configCheck 30 | return C2RPCReSync(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func C2RPCReSync(input c2structs.C2RPCReSyncMessage) c2structs.C2RPCReSyncMessageResponse { 36 | response := c2structs.C2RPCReSyncMessageResponse{ 37 | Success: true, 38 | Error: "", 39 | } 40 | SyncAllC2Data(&input.Name) 41 | return response 42 | } 43 | -------------------------------------------------------------------------------- /rabbitmq/recv_c2_rpc_sample_message.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/c2_structs" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | "github.com/MythicMeta/MythicContainer/logging" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | c2structs.AllC2Data.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: C2_RPC_SAMPLE_MESSAGE_ROUTING_KEY, 15 | RabbitmqProcessingFunction: processC2RPCSampleMessage, 16 | }) 17 | } 18 | 19 | // All rabbitmq methods must take byte inputs and return an interface. 20 | // However, we can cast these to the input and return types defined in this file 21 | func processC2RPCSampleMessage(msg []byte) interface{} { 22 | input := c2structs.C2SampleMessageMessage{} 23 | responseMsg := c2structs.C2SampleMessageResponse{} 24 | if err := json.Unmarshal(msg, &input); err != nil { 25 | logging.LogError(err, "Failed to unmarshal JSON into struct") 26 | responseMsg.Success = false 27 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 28 | } else { 29 | // actually do C2RPCGetIOC 30 | return C2RPCSampleMessage(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func C2RPCSampleMessage(input c2structs.C2SampleMessageMessage) c2structs.C2SampleMessageResponse { 36 | responseMsg := c2structs.C2SampleMessageResponse{ 37 | Success: true, 38 | Error: "No Sample Message configured", 39 | } 40 | c2Mutex.Lock() 41 | if c2structs.AllC2Data.Get(input.Name).GetC2Definition().SampleMessageFunction != nil { 42 | responseMsg = c2structs.AllC2Data.Get(input.Name).GetC2Definition().SampleMessageFunction(input) 43 | } 44 | c2Mutex.Unlock() 45 | if responseMsg.RestartInternalServer { 46 | go restartC2Server(input.Name) 47 | } 48 | return responseMsg 49 | } 50 | -------------------------------------------------------------------------------- /rabbitmq/recv_pt_build.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | "github.com/MythicMeta/MythicContainer/utils/mythicutils" 9 | ) 10 | 11 | func WrapPayloadBuild(msg []byte) { 12 | //payloadMsg := map[string]interface{}{} 13 | payloadBuildMsg := agentstructs.PayloadBuildMessage{} 14 | err := json.Unmarshal(msg, &payloadBuildMsg) 15 | if err != nil { 16 | logging.LogError(err, "Failed to process payload build message") 17 | return 18 | } 19 | var payloadBuildResponse agentstructs.PayloadBuildResponse 20 | payloadBuildFunc := agentstructs.AllPayloadData.Get(payloadBuildMsg.PayloadType).GetBuildFunction() 21 | if payloadBuildFunc == nil { 22 | logging.LogError(nil, "Failed to get payload build function. Do you have a function called 'build'?") 23 | payloadBuildResponse.Success = false 24 | } else { 25 | if payloadBuildMsg.WrappedPayloadUUID != nil && *payloadBuildMsg.WrappedPayloadUUID != "" { 26 | fileContents, err := mythicutils.GetFileFromMythic(*payloadBuildMsg.WrappedPayloadUUID) 27 | if err != nil { 28 | payloadBuildResponse.Success = false 29 | payloadBuildResponse.BuildStdErr = "Failed to get file contents of wrapped payload" 30 | } else { 31 | payloadBuildMsg.WrappedPayload = fileContents 32 | payloadBuildResponse = payloadBuildFunc(payloadBuildMsg) 33 | } 34 | } else { 35 | payloadBuildResponse = payloadBuildFunc(payloadBuildMsg) 36 | } 37 | } 38 | // handle sending off the payload via a web request separately from the rest of the message 39 | if payloadBuildResponse.Payload != nil { 40 | if err := mythicutils.SendFileToMythic(payloadBuildResponse.Payload, payloadBuildMsg.PayloadFileUUID); err != nil { 41 | logging.LogError(err, "Failed to send payload back to Mythic via web request") 42 | payloadBuildResponse.BuildMessage = payloadBuildResponse.BuildMessage + "\nFailed to send payload back to Mythic: " + err.Error() 43 | payloadBuildResponse.Success = false 44 | } 45 | } 46 | for { 47 | err = RabbitMQConnection.SendStructMessage( 48 | MYTHIC_EXCHANGE, 49 | PT_BUILD_RESPONSE_ROUTING_KEY, 50 | "", 51 | payloadBuildResponse, 52 | false, 53 | ) 54 | if err != nil { 55 | logging.LogError(err, "Failed to send payload response back to Mythic") 56 | continue 57 | } 58 | logging.LogDebug("Finished processing payload build message") 59 | return 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /rabbitmq/recv_pt_check_if_callbacks_alive.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | ) 9 | 10 | func init() { 11 | agentstructs.AllPayloadData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 12 | RabbitmqRoutingKey: PT_CHECK_IF_CALLBACKS_ALIVE, 13 | RabbitmqProcessingFunction: processPtCheckIfCallbacksAliveMessages, 14 | }) 15 | } 16 | 17 | func processPtCheckIfCallbacksAliveMessages(msg []byte) interface{} { 18 | incomingMessage := agentstructs.PTCheckIfCallbacksAliveMessage{} 19 | response := agentstructs.PTCheckIfCallbacksAliveMessageResponse{} 20 | err := json.Unmarshal(msg, &incomingMessage) 21 | if err != nil { 22 | logging.LogError(err, "Failed to unmarshal JSON into struct") 23 | response.Success = false 24 | response.Error = "Failed to unmarshal JSON message into structs" 25 | return response 26 | } 27 | response.Success = false 28 | checkIfCallbacksAliveFunc := agentstructs.AllPayloadData.Get(incomingMessage.ContainerName).GetCheckIfCallbacksAliveFunction() 29 | if checkIfCallbacksAliveFunc == nil { 30 | response.Success = true 31 | } else { 32 | response = checkIfCallbacksAliveFunc(incomingMessage) 33 | } 34 | return response 35 | } 36 | -------------------------------------------------------------------------------- /rabbitmq/recv_pt_dynamic_query_function.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 9 | ) 10 | 11 | func init() { 12 | agentstructs.AllPayloadData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 13 | RabbitmqRoutingKey: PT_RPC_COMMAND_DYNAMIC_QUERY_FUNCTION, 14 | RabbitmqProcessingFunction: processPtRPCDynamicQueryFunctionMessages, 15 | }) 16 | } 17 | 18 | func processPtRPCDynamicQueryFunctionMessages(msg []byte) interface{} { 19 | incomingMessage := agentstructs.PTRPCDynamicQueryFunctionMessage{} 20 | response := agentstructs.PTRPCDynamicQueryFunctionMessageResponse{ 21 | Success: false, 22 | } 23 | if err := json.Unmarshal(msg, &incomingMessage); err != nil { 24 | logging.LogError(err, "Failed to unmarshal JSON into struct") 25 | response.Error = "Failed to unmarshal JSON message into structs" 26 | return response 27 | } else { 28 | for _, command := range agentstructs.AllPayloadData.Get(incomingMessage.CommandPayloadType).GetCommands() { 29 | if command.Name == incomingMessage.Command { 30 | for _, param := range command.CommandParameters { 31 | if incomingMessage.ParameterName == param.Name { 32 | if param.DynamicQueryFunction != nil { 33 | response.Choices = param.DynamicQueryFunction(incomingMessage) 34 | response.Success = true 35 | return response 36 | } else { 37 | response.Choices = []string{} 38 | response.Error = "Function was nil" 39 | return response 40 | } 41 | } 42 | } 43 | response.Error = "Failed to find right parameter for command" 44 | return response 45 | } 46 | } 47 | response.Error = fmt.Sprintf("Failed to find command %s", incomingMessage.Command) 48 | return response 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rabbitmq/recv_pt_on_new_callback.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | ) 9 | 10 | func init() { 11 | agentstructs.AllPayloadData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 12 | RabbitmqRoutingKey: PT_ON_NEW_CALLBACK, 13 | RabbitmqProcessingFunction: processPtOnNewCallbackMessages, 14 | }) 15 | } 16 | 17 | func processPtOnNewCallbackMessages(msg []byte) { 18 | incomingMessage := agentstructs.PTOnNewCallbackAllData{} 19 | response := agentstructs.PTOnNewCallbackResponse{} 20 | err := json.Unmarshal(msg, &incomingMessage) 21 | if err != nil { 22 | logging.LogError(err, "Failed to unmarshal JSON into struct") 23 | response.Success = false 24 | response.Error = "Failed to unmarshal JSON message into structs" 25 | sendOnNewCallbackResponse(response) 26 | return 27 | } 28 | response.Success = false 29 | response.AgentCallbackID = incomingMessage.Callback.AgentCallbackID 30 | 31 | onNewCallbackFunc := agentstructs.AllPayloadData.Get(incomingMessage.PayloadType).GetOnNewCallbackFunction() 32 | if onNewCallbackFunc == nil { 33 | logging.LogInfo("Failed to get onNewCallbackFunc function. Do you have a function called 'onNewCallbackFunc'? This is an optional function for a payload type to automatically execute tasking and MythicRPC commands when a new callback happens.") 34 | response.Success = true 35 | } else { 36 | response = onNewCallbackFunc(incomingMessage) 37 | } 38 | sendOnNewCallbackResponse(response) 39 | return 40 | 41 | } 42 | 43 | func sendOnNewCallbackResponse(response agentstructs.PTOnNewCallbackResponse) { 44 | for { 45 | err := RabbitMQConnection.SendStructMessage( 46 | MYTHIC_EXCHANGE, 47 | PT_ON_NEW_CALLBACK_RESPONSE_ROUTING_KEY, 48 | "", 49 | response, 50 | false, 51 | ) 52 | if err != nil { 53 | logging.LogError(err, "Failed to send payload response back to Mythic") 54 | continue 55 | } 56 | return 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rabbitmq/recv_pt_process_response.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 9 | ) 10 | 11 | func init() { 12 | agentstructs.AllPayloadData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 13 | RabbitmqRoutingKey: PT_TASK_PROCESS_RESPONSE, 14 | RabbitmqProcessingFunction: processPtProcessResponseMessages, 15 | }) 16 | } 17 | 18 | func processPtProcessResponseMessages(msg []byte) { 19 | incomingMessage := agentstructs.PtTaskProcessResponseMessage{} 20 | response := agentstructs.PTTaskProcessResponseMessageResponse{ 21 | Success: false, 22 | } 23 | if err := json.Unmarshal(msg, &incomingMessage); err != nil { 24 | logging.LogError(err, "Failed to unmarshal JSON into struct") 25 | response.Error = "Failed to unmarshal JSON message into structs" 26 | sendTaskProcessResponseResponse(response) 27 | return 28 | } else { 29 | for _, command := range agentstructs.AllPayloadData.Get(incomingMessage.TaskData.CommandPayloadType).GetCommands() { 30 | if command.Name == incomingMessage.TaskData.Task.CommandName { 31 | if err := prepTaskArgs(command, incomingMessage.TaskData); err != nil { 32 | response.Error = err.Error() 33 | sendTaskProcessResponseResponse(response) 34 | return 35 | } 36 | if command.TaskFunctionProcessResponse != nil { 37 | response = command.TaskFunctionProcessResponse(incomingMessage) 38 | } else { 39 | response.Error = fmt.Sprintf("Failed to find process response function for command %s", incomingMessage.TaskData.Task.CommandName) 40 | } 41 | response.TaskID = incomingMessage.TaskData.Task.ID 42 | sendTaskProcessResponseResponse(response) 43 | return 44 | } 45 | } 46 | response.Error = fmt.Sprintf("Failed to find command %s", incomingMessage.TaskData.Task.CommandName) 47 | sendTaskProcessResponseResponse(response) 48 | return 49 | } 50 | } 51 | 52 | func sendTaskProcessResponseResponse(response agentstructs.PTTaskProcessResponseMessageResponse) { 53 | for { 54 | err := RabbitMQConnection.SendStructMessage( 55 | MYTHIC_EXCHANGE, 56 | PT_TASK_PROCESS_RESPONSE_RESPONSE, 57 | "", 58 | response, 59 | false, 60 | ) 61 | if err != nil { 62 | logging.LogError(err, "Failed to send payload response back to Mythic") 63 | continue 64 | } 65 | return 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /rabbitmq/recv_pt_rpc_resync.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 8 | ) 9 | 10 | // Register this RPC method with rabbitmq so it can be called 11 | func init() { 12 | agentstructs.AllPayloadData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 13 | RabbitmqRoutingKey: PT_RPC_RESYNC_ROUTING_KEY, 14 | RabbitmqProcessingFunction: processPTRPCReSync, 15 | }) 16 | } 17 | 18 | // All rabbitmq methods must take byte inputs and return an interface. 19 | // However, we can cast these to the input and return types defined in this file 20 | func processPTRPCReSync(msg []byte) interface{} { 21 | input := agentstructs.PTRPCReSyncMessage{} 22 | responseMsg := agentstructs.PTRPCReSyncMessageResponse{} 23 | if err := json.Unmarshal(msg, &input); err != nil { 24 | logging.LogError(err, "Failed to unmarshal JSON into struct") 25 | responseMsg.Success = false 26 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 27 | } else { 28 | // actually do config checks on configCheck 29 | return PTRPCReSync(input) 30 | } 31 | return responseMsg 32 | } 33 | 34 | func PTRPCReSync(input agentstructs.PTRPCReSyncMessage) agentstructs.PTRPCReSyncMessageResponse { 35 | response := agentstructs.PTRPCReSyncMessageResponse{ 36 | Success: true, 37 | Error: "", 38 | } 39 | SyncPayloadData(&input.Name, true) 40 | return response 41 | } 42 | -------------------------------------------------------------------------------- /rabbitmq/recv_pt_rpc_typedarray_parse_function.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 9 | ) 10 | 11 | func init() { 12 | agentstructs.AllPayloadData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 13 | RabbitmqRoutingKey: PT_RPC_COMMAND_TYPEDARRAY_PARSE, 14 | RabbitmqProcessingFunction: processPtRPCTypedArrayParseMessages, 15 | }) 16 | } 17 | 18 | func processPtRPCTypedArrayParseMessages(msg []byte) interface{} { 19 | incomingMessage := agentstructs.PTRPCTypedArrayParseFunctionMessage{} 20 | response := agentstructs.PTRPCTypedArrayParseMessageResponse{ 21 | Success: false, 22 | } 23 | if err := json.Unmarshal(msg, &incomingMessage); err != nil { 24 | logging.LogError(err, "Failed to unmarshal JSON into struct") 25 | response.Error = "Failed to unmarshal JSON message into structs" 26 | return response 27 | } else { 28 | for _, command := range agentstructs.AllPayloadData.Get(incomingMessage.CommandPayloadType).GetCommands() { 29 | if command.Name == incomingMessage.Command { 30 | for _, param := range command.CommandParameters { 31 | if incomingMessage.ParameterName == param.Name { 32 | if param.TypedArrayParseFunction != nil { 33 | response.TypedArray = param.TypedArrayParseFunction(incomingMessage) 34 | response.Success = true 35 | return response 36 | } else { 37 | response.TypedArray = [][]string{} 38 | response.Error = "Function was nil" 39 | return response 40 | } 41 | } 42 | } 43 | response.Error = "Failed to find right parameter for command" 44 | return response 45 | } 46 | } 47 | response.Error = fmt.Sprintf("Failed to find command %s", incomingMessage.Command) 48 | return response 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rabbitmq/recv_pt_task_opsec_post.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 9 | "github.com/MythicMeta/MythicContainer/logging" 10 | ) 11 | 12 | func init() { 13 | agentstructs.AllPayloadData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 14 | RabbitmqRoutingKey: PT_TASK_OPSEC_POST_CHECK, 15 | RabbitmqProcessingFunction: processPtTaskOPSECPostMessages, 16 | }) 17 | } 18 | 19 | func processPtTaskOPSECPostMessages(msg []byte) { 20 | incomingMessage := agentstructs.PTTaskMessageAllData{} 21 | response := agentstructs.PTTaskOPSECPostTaskMessageResponse{ 22 | Success: false, 23 | } 24 | if err := json.Unmarshal(msg, &incomingMessage); err != nil { 25 | logging.LogError(err, "Failed to unmarshal JSON into struct") 26 | response.Error = "Failed to unmarshal JSON message into structs" 27 | } else { 28 | response.TaskID = incomingMessage.Task.ID 29 | for _, command := range agentstructs.AllPayloadData.Get(incomingMessage.CommandPayloadType).GetCommands() { 30 | if command.Name == incomingMessage.Task.CommandName { 31 | if command.TaskFunctionOPSECPost != nil { 32 | if err := prepTaskArgs(command, &incomingMessage); err != nil { 33 | response.Error = err.Error() 34 | sendTaskOpsecPostResponse(response) 35 | return 36 | } 37 | response = command.TaskFunctionOPSECPost(&incomingMessage) 38 | } else { 39 | response.OpsecPostBlocked = false 40 | response.OpsecPostMessage = "Not Implemented" 41 | response.Success = true 42 | } 43 | sendTaskOpsecPostResponse(response) 44 | return 45 | } 46 | } 47 | response.Error = fmt.Sprintf("Failed to find command %s", incomingMessage.Task.CommandName) 48 | sendTaskOpsecPostResponse(response) 49 | return 50 | } 51 | } 52 | 53 | func sendTaskOpsecPostResponse(response agentstructs.PTTaskOPSECPostTaskMessageResponse) { 54 | for { 55 | err := RabbitMQConnection.SendStructMessage( 56 | MYTHIC_EXCHANGE, 57 | PT_TASK_OPSEC_POST_CHECK_RESPONSE, 58 | "", 59 | response, 60 | false, 61 | ) 62 | if err != nil { 63 | logging.LogError(err, "Failed to send payload response back to Mythic") 64 | continue 65 | } 66 | return 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /rabbitmq/recv_pt_task_opsec_pre.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 9 | "github.com/MythicMeta/MythicContainer/logging" 10 | ) 11 | 12 | func init() { 13 | agentstructs.AllPayloadData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 14 | RabbitmqRoutingKey: PT_TASK_OPSEC_PRE_CHECK, 15 | RabbitmqProcessingFunction: processPtTaskOPSECPreMessages, 16 | }) 17 | } 18 | 19 | func processPtTaskOPSECPreMessages(msg []byte) { 20 | incomingMessage := agentstructs.PTTaskMessageAllData{} 21 | response := agentstructs.PTTTaskOPSECPreTaskMessageResponse{ 22 | Success: false, 23 | } 24 | if err := json.Unmarshal(msg, &incomingMessage); err != nil { 25 | logging.LogError(err, "Failed to unmarshal JSON into struct") 26 | response.Error = "Failed to unmarshal JSON message into structs" 27 | } else { 28 | response.TaskID = incomingMessage.Task.ID 29 | for _, command := range agentstructs.AllPayloadData.Get(incomingMessage.CommandPayloadType).GetCommands() { 30 | if command.Name == incomingMessage.Task.CommandName { 31 | if command.TaskFunctionOPSECPre != nil { 32 | if err := prepTaskArgs(command, &incomingMessage); err != nil { 33 | response.Error = err.Error() 34 | sendTaskOpsecPreResponse(response) 35 | return 36 | } 37 | response = command.TaskFunctionOPSECPre(&incomingMessage) 38 | } else { 39 | response.OpsecPreBlocked = false 40 | response.Success = true 41 | response.OpsecPreMessage = "Not Implemented" 42 | } 43 | response.TaskID = incomingMessage.Task.ID 44 | sendTaskOpsecPreResponse(response) 45 | return 46 | } 47 | } 48 | response.Error = fmt.Sprintf("Failed to find command %s", incomingMessage.Task.CommandName) 49 | sendTaskOpsecPreResponse(response) 50 | return 51 | } 52 | } 53 | 54 | func sendTaskOpsecPreResponse(response agentstructs.PTTTaskOPSECPreTaskMessageResponse) { 55 | for { 56 | err := RabbitMQConnection.SendStructMessage( 57 | MYTHIC_EXCHANGE, 58 | PT_TASK_OPSEC_PRE_CHECK_RESPONSE, 59 | "", 60 | response, 61 | false, 62 | ) 63 | if err != nil { 64 | logging.LogError(err, "Failed to send payload response back to Mythic") 65 | continue 66 | } 67 | return 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /rabbitmq/recv_tr_custom_to_mythic_format.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/translationstructs" 6 | 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | ) 9 | 10 | // Register this RPC method with rabbitmq so it can be called 11 | func init() { 12 | /* 13 | translationstructs.AllTranslationData.Get("").AddRPCMethod(translationstructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: TR_RPC_CONVERT_TO_MYTHIC_C2_FORMAT, 15 | RabbitmqProcessingFunction: processTrRPCCustomToMythicFormat, 16 | }) 17 | 18 | */ 19 | } 20 | 21 | // All rabbitmq methods must take byte inputs and return an interface. 22 | // However, we can cast these to the input and return types defined in this file 23 | func processTrRPCCustomToMythicFormat(msg []byte) interface{} { 24 | input := translationstructs.TrCustomMessageToMythicC2FormatMessage{} 25 | responseMsg := translationstructs.TrCustomMessageToMythicC2FormatMessageResponse{} 26 | if err := json.Unmarshal(msg, &input); err != nil { 27 | logging.LogError(err, "Failed to unmarshal JSON into struct") 28 | responseMsg.Success = false 29 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 30 | } else { 31 | // actually do config checks on configCheck 32 | return TrRPCCustomToMythicFormat(input) 33 | } 34 | return responseMsg 35 | } 36 | 37 | func TrRPCCustomToMythicFormat(input translationstructs.TrCustomMessageToMythicC2FormatMessage) translationstructs.TrCustomMessageToMythicC2FormatMessageResponse { 38 | response := translationstructs.TrCustomMessageToMythicC2FormatMessageResponse{ 39 | Success: false, 40 | Error: "No Translation function defined", 41 | } 42 | if translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().TranslateCustomToMythicFormat != nil { 43 | response = translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().TranslateCustomToMythicFormat(input) 44 | } 45 | return response 46 | } 47 | -------------------------------------------------------------------------------- /rabbitmq/recv_tr_decrypt_bytes.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/translationstructs" 6 | 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | ) 9 | 10 | // Register this RPC method with rabbitmq so it can be called 11 | func init() { 12 | /* 13 | translationstructs.AllTranslationData.Get("").AddRPCMethod(translationstructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: TR_RPC_DECRYPT_BYTES, 15 | RabbitmqProcessingFunction: processTrRPCDecryptBytes, 16 | }) 17 | 18 | */ 19 | } 20 | 21 | // All rabbitmq methods must take byte inputs and return an interface. 22 | // However, we can cast these to the input and return types defined in this file 23 | func processTrRPCDecryptBytes(msg []byte) interface{} { 24 | input := translationstructs.TrDecryptBytesMessage{} 25 | responseMsg := translationstructs.TrDecryptBytesMessageResponse{} 26 | if err := json.Unmarshal(msg, &input); err != nil { 27 | logging.LogError(err, "Failed to unmarshal JSON into struct") 28 | responseMsg.Success = false 29 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 30 | } else { 31 | // actually do config checks on configCheck 32 | return TrRPCDecryptBytes(input) 33 | } 34 | return responseMsg 35 | } 36 | 37 | func TrRPCDecryptBytes(input translationstructs.TrDecryptBytesMessage) translationstructs.TrDecryptBytesMessageResponse { 38 | response := translationstructs.TrDecryptBytesMessageResponse{ 39 | Success: false, 40 | Error: "No Translation function defined", 41 | } 42 | if translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().DecryptBytes != nil { 43 | response = translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().DecryptBytes(input) 44 | } 45 | return response 46 | } 47 | -------------------------------------------------------------------------------- /rabbitmq/recv_tr_encrypt_bytes.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/translationstructs" 6 | 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | ) 9 | 10 | // Register this RPC method with rabbitmq so it can be called 11 | func init() { 12 | /* 13 | translationstructs.AllTranslationData.Get("").AddRPCMethod(translationstructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: TR_RPC_ENCRYPT_BYTES, 15 | RabbitmqProcessingFunction: processTrRPCEncryptBytes, 16 | }) 17 | 18 | */ 19 | } 20 | 21 | // All rabbitmq methods must take byte inputs and return an interface. 22 | // However, we can cast these to the input and return types defined in this file 23 | func processTrRPCEncryptBytes(msg []byte) interface{} { 24 | input := translationstructs.TrEncryptBytesMessage{} 25 | responseMsg := translationstructs.TrEncryptBytesMessageResponse{} 26 | if err := json.Unmarshal(msg, &input); err != nil { 27 | logging.LogError(err, "Failed to unmarshal JSON into struct") 28 | responseMsg.Success = false 29 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 30 | } else { 31 | // actually do config checks on configCheck 32 | return TrRPCEncryptBytes(input) 33 | } 34 | return responseMsg 35 | } 36 | 37 | func TrRPCEncryptBytes(input translationstructs.TrEncryptBytesMessage) translationstructs.TrEncryptBytesMessageResponse { 38 | response := translationstructs.TrEncryptBytesMessageResponse{ 39 | Success: false, 40 | Error: "No Translation function defined", 41 | } 42 | if translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().EncryptBytes != nil { 43 | response = translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().EncryptBytes(input) 44 | } 45 | return response 46 | } 47 | -------------------------------------------------------------------------------- /rabbitmq/recv_tr_generate_encryption_keys.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/translationstructs" 6 | 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | ) 9 | 10 | // Register this RPC method with rabbitmq so it can be called 11 | func init() { 12 | /* 13 | translationstructs.AllTranslationData.Get("").AddRPCMethod(translationstructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: TR_RPC_GENERATE_KEYS, 15 | RabbitmqProcessingFunction: processTrRPCGenerateEncryptionKeys, 16 | }) 17 | 18 | */ 19 | } 20 | 21 | // All rabbitmq methods must take byte inputs and return an interface. 22 | // However, we can cast these to the input and return types defined in this file 23 | func processTrRPCGenerateEncryptionKeys(msg []byte) interface{} { 24 | input := translationstructs.TrGenerateEncryptionKeysMessage{} 25 | responseMsg := translationstructs.TrGenerateEncryptionKeysMessageResponse{} 26 | if err := json.Unmarshal(msg, &input); err != nil { 27 | logging.LogError(err, "Failed to unmarshal JSON into struct") 28 | responseMsg.Success = false 29 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 30 | } else { 31 | // actually do config checks on configCheck 32 | return TrRPCGenerateEncryptionKeys(input) 33 | } 34 | return responseMsg 35 | } 36 | 37 | func TrRPCGenerateEncryptionKeys(input translationstructs.TrGenerateEncryptionKeysMessage) translationstructs.TrGenerateEncryptionKeysMessageResponse { 38 | response := translationstructs.TrGenerateEncryptionKeysMessageResponse{ 39 | Success: false, 40 | Error: "No Translation function defined", 41 | } 42 | //logging.LogDebug("asked to generate keys", "req", input) 43 | if translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().GenerateEncryptionKeys != nil { 44 | response = translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().GenerateEncryptionKeys(input) 45 | } 46 | return response 47 | } 48 | -------------------------------------------------------------------------------- /rabbitmq/recv_tr_mythic_to_custom_format.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/translationstructs" 6 | 7 | "github.com/MythicMeta/MythicContainer/logging" 8 | ) 9 | 10 | // Register this RPC method with rabbitmq so it can be called 11 | func init() { 12 | /* 13 | translationstructs.AllTranslationData.Get("").AddRPCMethod(translationstructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: TR_RPC_CONVERT_FROM_MYTHIC_C2_FORMAT, 15 | RabbitmqProcessingFunction: processTrRPCMythicToCustomFormat, 16 | }) 17 | 18 | */ 19 | } 20 | 21 | // All rabbitmq methods must take byte inputs and return an interface. 22 | // However, we can cast these to the input and return types defined in this file 23 | func processTrRPCMythicToCustomFormat(msg []byte) interface{} { 24 | input := translationstructs.TrMythicC2ToCustomMessageFormatMessage{} 25 | responseMsg := translationstructs.TrMythicC2ToCustomMessageFormatMessageResponse{} 26 | if err := json.Unmarshal(msg, &input); err != nil { 27 | logging.LogError(err, "Failed to unmarshal JSON into struct") 28 | responseMsg.Success = false 29 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 30 | } else { 31 | // actually do config checks on configCheck 32 | return TrRPCMythicToCustomFormat(input) 33 | } 34 | return responseMsg 35 | } 36 | 37 | func TrRPCMythicToCustomFormat(input translationstructs.TrMythicC2ToCustomMessageFormatMessage) translationstructs.TrMythicC2ToCustomMessageFormatMessageResponse { 38 | response := translationstructs.TrMythicC2ToCustomMessageFormatMessageResponse{ 39 | Success: false, 40 | Error: "No Translation function defined", 41 | } 42 | if translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().TranslateMythicToCustomFormat != nil { 43 | response = translationstructs.AllTranslationData.Get(input.TranslationContainerName).GetPayloadDefinition().TranslateMythicToCustomFormat(input) 44 | } 45 | return response 46 | } 47 | -------------------------------------------------------------------------------- /rabbitmq/recv_tr_rpc_resync.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/translationstructs" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | 8 | "github.com/MythicMeta/MythicContainer/logging" 9 | ) 10 | 11 | // Register this RPC method with rabbitmq so it can be called 12 | func init() { 13 | translationstructs.AllTranslationData.Get("").AddRPCMethod(sharedStructs.RabbitmqRPCMethod{ 14 | RabbitmqRoutingKey: TR_RPC_RESYNC_ROUTING_KEY, 15 | RabbitmqProcessingFunction: processTrRPCReSync, 16 | }) 17 | } 18 | 19 | // All rabbitmq methods must take byte inputs and return an interface. 20 | // However, we can cast these to the input and return types defined in this file 21 | func processTrRPCReSync(msg []byte) interface{} { 22 | input := translationstructs.TRRPCReSyncMessage{} 23 | responseMsg := translationstructs.TRRPCReSyncMessageResponse{} 24 | if err := json.Unmarshal(msg, &input); err != nil { 25 | logging.LogError(err, "Failed to unmarshal JSON into struct") 26 | responseMsg.Success = false 27 | responseMsg.Error = "Failed to unmarshal JSON message into structs" 28 | } else { 29 | // actually do config checks on configCheck 30 | return TrRPCReSync(input) 31 | } 32 | return responseMsg 33 | } 34 | 35 | func TrRPCReSync(input translationstructs.TRRPCReSyncMessage) translationstructs.TRRPCReSyncMessageResponse { 36 | response := translationstructs.TRRPCReSyncMessageResponse{ 37 | Success: true, 38 | Error: "", 39 | } 40 | SyncTranslationData(&input.Name) 41 | return response 42 | } 43 | -------------------------------------------------------------------------------- /rabbitmq/send_c2_rpc_update_status.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | ) 7 | 8 | type MythicRPCC2UpdateStatusMessage struct { 9 | C2Profile string `json:"c2_profile"` // required 10 | InternalServerRunning bool `json:"server_running"` // required 11 | Error string `json:"error"` 12 | } 13 | type MythicRPCC2UpdateStatusMessageResponse struct { 14 | Success bool `json:"success"` 15 | Error string `json:"error"` 16 | } 17 | 18 | // SendMythicRPCCallbackCreate - Register a new callback within Mythic 19 | func SendMythicRPCC2UpdateStatus(input MythicRPCC2UpdateStatusMessage) (*MythicRPCC2UpdateStatusMessageResponse, error) { 20 | response := MythicRPCC2UpdateStatusMessageResponse{} 21 | for { 22 | responseBytes, err := RabbitMQConnection.SendRPCStructMessage( 23 | MYTHIC_EXCHANGE, 24 | MYTHIC_RPC_C2_UPDATE_STATUS, 25 | input, 26 | ) 27 | if err != nil { 28 | logging.LogError(err, "Failed to send RPC message") 29 | continue 30 | } 31 | err = json.Unmarshal(responseBytes, &response) 32 | if err != nil { 33 | logging.LogError(err, "Failed to parse response back to struct", "response", response) 34 | return nil, err 35 | } 36 | return &response, nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rabbitmq/send_c2_sync_data.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | c2structs "github.com/MythicMeta/MythicContainer/c2_structs" 6 | "github.com/MythicMeta/MythicContainer/logging" 7 | "time" 8 | ) 9 | 10 | func SyncAllC2Data(resyncName *string) { 11 | // now make our c2 info that we're going to sync 12 | for _, c2 := range c2structs.AllC2Data.GetAllNames() { 13 | if resyncName == nil || c2 == *resyncName { 14 | logging.LogInfo("Syncing C2 profile", "name", c2) 15 | syncMessage := c2structs.C2SyncMessage{} 16 | response := c2structs.C2SyncMessageResponse{} 17 | syncMessage.Profile = c2structs.AllC2Data.Get(c2).GetC2Definition() 18 | syncMessage.Parameters = c2structs.AllC2Data.Get(c2).GetParameters() 19 | c2structs.AllC2Data.Get(c2).AddContainerVersion(containerVersion) 20 | syncMessage.ContainerVersion = c2structs.AllC2Data.Get(c2).GetContainerVersion() 21 | for { 22 | syncMessageJson, err := json.Marshal(syncMessage) 23 | if err != nil { 24 | logging.LogError(err, "Failed to serialize c2 sync message to json") 25 | time.Sleep(RETRY_CONNECT_DELAY) 26 | continue 27 | } 28 | resp, err := RabbitMQConnection.SendRPCMessage(MYTHIC_EXCHANGE, C2_SYNC_ROUTING_KEY, syncMessageJson, true) 29 | if err != nil { 30 | logging.LogError(err, "Failed to send c2 profile to Mythic") 31 | time.Sleep(RETRY_CONNECT_DELAY) 32 | continue 33 | } 34 | err = json.Unmarshal(resp, &response) 35 | if err != nil { 36 | logging.LogError(err, "Failed to marshal sync response back to struct") 37 | time.Sleep(RETRY_CONNECT_DELAY) 38 | continue 39 | } 40 | if !response.Success { 41 | logging.LogError(nil, response.Error) 42 | time.Sleep(RETRY_CONNECT_DELAY) 43 | continue 44 | } 45 | logging.LogInfo("Successfully synced c2 profile!", "name", c2) 46 | break 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rabbitmq/send_pt_sync_data.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "time" 7 | 8 | agentstructs "github.com/MythicMeta/MythicContainer/agent_structs" 9 | "github.com/MythicMeta/MythicContainer/logging" 10 | ) 11 | 12 | func SyncPayloadData(syncPayloadName *string, forcedResync bool) { 13 | // now make our payloadtype info that we're going to sync 14 | for _, pt := range agentstructs.AllPayloadData.GetAllPayloadTypeNames() { 15 | if syncPayloadName == nil || *syncPayloadName == pt { 16 | logging.LogInfo("Syncing payload type", "name", pt) 17 | syncMessage := agentstructs.PayloadTypeSyncMessage{ 18 | ForcedResync: forcedResync, 19 | } 20 | response := agentstructs.PayloadTypeSyncMessageResponse{} 21 | //logging.LogInfo("about to sync over definition", "payload", agentstructs.AllPayloadData.GetPayloadDefinition(), "commands", agentstructs.AllPayloadData.GetCommands()) 22 | syncMessage.PayloadType = agentstructs.AllPayloadData.Get(pt).GetPayloadDefinition() 23 | syncMessage.CommandList = agentstructs.AllPayloadData.Get(pt).GetCommands() 24 | agentstructs.AllPayloadData.Get(pt).AddContainerVersion(containerVersion) 25 | syncMessage.ContainerVersion = agentstructs.AllPayloadData.Get(pt).GetContainerVersion() 26 | for { 27 | syncMessageJson, err := json.Marshal(syncMessage) 28 | if err != nil { 29 | logging.LogError(err, "Failed to serialize payload sync message to json, %s", err.Error()) 30 | time.Sleep(RETRY_CONNECT_DELAY) 31 | continue 32 | } 33 | resp, err := RabbitMQConnection.SendRPCMessage(MYTHIC_EXCHANGE, PT_SYNC_ROUTING_KEY, syncMessageJson, true) 34 | if err != nil { 35 | logging.LogError(err, "Failed to send payload type to Mythic") 36 | time.Sleep(RETRY_CONNECT_DELAY) 37 | continue 38 | } 39 | err = json.Unmarshal(resp, &response) 40 | if err != nil { 41 | logging.LogError(err, "Failed to marshal sync response back to struct") 42 | time.Sleep(RETRY_CONNECT_DELAY) 43 | continue 44 | } 45 | if !response.Success { 46 | logging.LogError(errors.New(response.Error), "waiting and trying again...") 47 | time.Sleep(RETRY_CONNECT_DELAY) 48 | continue 49 | } 50 | logging.LogInfo("Successfully synced payload type!", "name", pt) 51 | break 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /rabbitmq/send_tr_sync_data.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/translationstructs" 6 | "time" 7 | 8 | "github.com/MythicMeta/MythicContainer/logging" 9 | ) 10 | 11 | func SyncTranslationData(translationName *string) { 12 | // now make our payloadtype info that we're going to sync 13 | for _, pt := range translationstructs.AllTranslationData.GetAllPayloadTypeNames() { 14 | if translationName == nil || *translationName == pt { 15 | logging.LogInfo("Syncing translation container", "name", pt) 16 | syncMessage := translationstructs.TrSyncMessage{} 17 | response := translationstructs.TrSyncMessageResponse{} 18 | syncMessage.Name = translationstructs.AllTranslationData.Get(pt).GetPayloadName() 19 | syncMessage.Author = translationstructs.AllTranslationData.Get(pt).GetAuthor() 20 | syncMessage.Description = translationstructs.AllTranslationData.Get(pt).GetDescription() 21 | translationstructs.AllTranslationData.Get(pt).AddContainerVersion(containerVersion) 22 | syncMessage.ContainerVersion = translationstructs.AllTranslationData.Get(pt).GetContainerVersion() 23 | //logging.LogDebug("syncing over tr", "tr info", syncMessage) 24 | for { 25 | syncMessageJson, err := json.Marshal(syncMessage) 26 | if err != nil { 27 | logging.LogError(err, "Failed to serialize translation service sync message to json, %s", err.Error()) 28 | time.Sleep(RETRY_CONNECT_DELAY) 29 | continue 30 | } 31 | resp, err := RabbitMQConnection.SendRPCMessage(MYTHIC_EXCHANGE, TR_SYNC_ROUTING_KEY, syncMessageJson, true) 32 | if err != nil { 33 | logging.LogError(err, "Failed to send translation service to Mythic") 34 | time.Sleep(RETRY_CONNECT_DELAY) 35 | continue 36 | } 37 | err = json.Unmarshal(resp, &response) 38 | if err != nil { 39 | logging.LogError(err, "Failed to marshal sync response back to struct") 40 | time.Sleep(RETRY_CONNECT_DELAY) 41 | continue 42 | } 43 | if !response.Success { 44 | logging.LogError(nil, response.Error) 45 | time.Sleep(RETRY_CONNECT_DELAY) 46 | continue 47 | } 48 | logging.LogInfo("Successfully synced translation service!", "name", pt) 49 | break 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rabbitmq/structs.go: -------------------------------------------------------------------------------- 1 | package rabbitmq 2 | -------------------------------------------------------------------------------- /translationstructs/structs_custom_to_mythic_format.go: -------------------------------------------------------------------------------- 1 | package translationstructs 2 | 3 | // TRANSLATION_CONTAINER_CUSTOM_MESSAGE_TO_MYTHIC_C2_FORMAT STRUCTS 4 | 5 | type TrCustomMessageToMythicC2FormatMessage struct { 6 | TranslationContainerName string `json:"translation_container_name"` 7 | C2Name string `json:"c2_profile_name"` 8 | Message []byte `json:"message"` 9 | UUID string `json:"uuid"` 10 | MythicEncrypts bool `json:"mythic_encrypts"` 11 | CryptoKeys []CryptoKeys `json:"crypto_keys"` 12 | } 13 | 14 | type TrCustomMessageToMythicC2FormatMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | Message map[string]interface{} `json:"message"` 18 | } 19 | -------------------------------------------------------------------------------- /translationstructs/structs_decrypt_bytes.go: -------------------------------------------------------------------------------- 1 | package translationstructs 2 | 3 | // TRANSLATION_CONTAINER_DECRYPT_BYTES STRUCTS 4 | 5 | type TrDecryptBytesMessage struct { 6 | TranslationContainerName string `json:"translation_container_name"` 7 | EncryptionKey []byte `json:"enc_key"` 8 | CryptoType string `json:"crypto_type"` 9 | Message []byte `json:"message"` 10 | AgentCallbackUUID string `json:"callback_uuid"` 11 | } 12 | 13 | type TrDecryptBytesMessageResponse struct { 14 | Success bool `json:"success"` 15 | Error string `json:"error"` 16 | Message []byte `json:"message"` 17 | } 18 | -------------------------------------------------------------------------------- /translationstructs/structs_encrypt_bytes.go: -------------------------------------------------------------------------------- 1 | package translationstructs 2 | 3 | // TRANSLATION_CONTAINER_ENCRYPT_BYTES STRUCTS 4 | 5 | type TR_ENCRYPT_BYTES_STATUS = string 6 | 7 | type TrEncryptBytesMessage struct { 8 | TranslationContainerName string `json:"translation_container_name"` 9 | EncryptionKey []byte `json:"enc_key"` 10 | CryptoType string `json:"crypto_type"` 11 | Message []byte `json:"message"` 12 | IncludeUUID bool `json:"include_uuid"` 13 | Base64ReturnMessage bool `json:"base64_message"` 14 | } 15 | 16 | type TrEncryptBytesMessageResponse struct { 17 | Success bool `json:"success"` 18 | Error string `json:"error"` 19 | Message []byte `json:"message"` 20 | } 21 | -------------------------------------------------------------------------------- /translationstructs/structs_generate_encryption_keys.go: -------------------------------------------------------------------------------- 1 | package translationstructs 2 | 3 | // TRANSLATION_CONTAINER_GENERATE_ENCRYPTION_KEYS STRUCTS 4 | 5 | type TrGenerateEncryptionKeysMessage struct { 6 | TranslationContainerName string `json:"translation_container_name"` 7 | C2Name string `json:"c2_profile_name"` 8 | CryptoParamValue string `json:"value"` 9 | CryptoParamName string `json:"name"` 10 | } 11 | 12 | type TrGenerateEncryptionKeysMessageResponse struct { 13 | Success bool `json:"success"` 14 | Error string `json:"error"` 15 | EncryptionKey *[]byte `json:"enc_key"` 16 | DecryptionKey *[]byte `json:"dec_key"` 17 | } 18 | -------------------------------------------------------------------------------- /translationstructs/structs_generic.go: -------------------------------------------------------------------------------- 1 | package translationstructs 2 | 3 | type CryptoKeys struct { 4 | EncKey *[]byte `json:"enc_key,omitempty"` 5 | DecKey *[]byte `json:"dec_key,omitempty"` 6 | Value string `json:"value"` 7 | Location string `json:"location,omitempty"` 8 | } 9 | -------------------------------------------------------------------------------- /translationstructs/structs_mythic_to_custom_format.go: -------------------------------------------------------------------------------- 1 | package translationstructs 2 | 3 | // TRANSLATION_CONTAINER_MYTHIC_C2_TO_CUSTOM_MESSAGE_FORMAT STRUCTS 4 | 5 | type TrMythicC2ToCustomMessageFormatMessage struct { 6 | TranslationContainerName string `json:"translation_container_name"` 7 | C2Name string `json:"c2_profile_name"` 8 | Message map[string]interface{} `json:"message"` 9 | UUID string `json:"uuid"` 10 | MythicEncrypts bool `json:"mythic_encrypts"` 11 | CryptoKeys []CryptoKeys `json:"crypto_keys"` 12 | } 13 | 14 | type TrMythicC2ToCustomMessageFormatMessageResponse struct { 15 | Success bool `json:"success"` 16 | Error string `json:"error"` 17 | Message []byte `json:"message"` 18 | } 19 | -------------------------------------------------------------------------------- /translationstructs/structs_tr_resync.go: -------------------------------------------------------------------------------- 1 | package translationstructs 2 | 3 | type TRRPCReSyncMessage struct { 4 | Name string `json:"translation_name"` 5 | } 6 | 7 | type TRRPCReSyncMessageResponse struct { 8 | Success bool `json:"success"` 9 | Error string `json:"error"` 10 | } 11 | -------------------------------------------------------------------------------- /translationstructs/structs_tr_sync.go: -------------------------------------------------------------------------------- 1 | package translationstructs 2 | 3 | import "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 4 | 5 | type TranslationContainer struct { 6 | Name string `json:"name"` 7 | Description string `json:"description"` 8 | Author string `json:"author"` 9 | TranslateCustomToMythicFormat TranslateCustomToMythicFormatFunction `json:"-"` 10 | TranslateMythicToCustomFormat TranslateMythicToCustomFormatFunction `json:"-"` 11 | GenerateEncryptionKeys GenerateEncryptionKeysFunction `json:"-"` 12 | EncryptBytes EncryptBytesFunction `json:"-"` 13 | DecryptBytes DecryptBytesFunction `json:"-"` 14 | OnContainerStartFunction func(sharedStructs.ContainerOnStartMessage) sharedStructs.ContainerOnStartMessageResponse `json:"-"` 15 | } 16 | 17 | // TR_SYNC STRUCTS 18 | 19 | type TrSyncMessageResponse struct { 20 | Success bool `json:"success"` 21 | Error string `json:"error"` 22 | } 23 | 24 | type TrSyncMessage struct { 25 | Name string `json:"name"` 26 | Description string `json:"description"` 27 | Author string `json:"author"` 28 | ContainerVersion string `json:"container_version"` 29 | } 30 | 31 | type TranslateCustomToMythicFormatFunction = func(input TrCustomMessageToMythicC2FormatMessage) TrCustomMessageToMythicC2FormatMessageResponse 32 | type TranslateMythicToCustomFormatFunction = func(input TrMythicC2ToCustomMessageFormatMessage) TrMythicC2ToCustomMessageFormatMessageResponse 33 | type GenerateEncryptionKeysFunction = func(input TrGenerateEncryptionKeysMessage) TrGenerateEncryptionKeysMessageResponse 34 | type EncryptBytesFunction = func(input TrEncryptBytesMessage) TrEncryptBytesMessageResponse 35 | type DecryptBytesFunction = func(input TrDecryptBytesMessage) TrDecryptBytesMessageResponse 36 | -------------------------------------------------------------------------------- /utils/helpers/helpers.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | func StringSliceContains(source []string, str string) bool { 10 | for _, v := range source { 11 | if str == v { 12 | return true 13 | } 14 | } 15 | return false 16 | } 17 | 18 | func RemoveStringFromSliceNoOrder(source []string, str string) []string { 19 | for index, value := range source { 20 | if str == value { 21 | source[index] = source[len(source)-1] 22 | source[len(source)-1] = "" 23 | source = source[:len(source)-1] 24 | return source 25 | } 26 | } 27 | // we didn't find the element to remove 28 | return source 29 | } 30 | 31 | func GetCwdFromExe() string { 32 | exe, err := os.Executable() 33 | if err != nil { 34 | log.Fatalf("[-] Failed to get path to current executable: %v", err) 35 | } 36 | return filepath.Dir(exe) 37 | } 38 | 39 | func FileExists(path string) bool { 40 | info, err := os.Stat(path) 41 | if err != nil { 42 | if os.IsNotExist(err) { 43 | return false 44 | } 45 | } 46 | return !info.IsDir() 47 | } 48 | -------------------------------------------------------------------------------- /utils/sharedStructs/sharedStructs.go: -------------------------------------------------------------------------------- 1 | package sharedStructs 2 | 3 | type RabbitmqRPCMethod struct { 4 | RabbitmqRoutingKey string 5 | RabbitmqProcessingFunction func([]byte) interface{} 6 | } 7 | type RabbitmqDirectMethod struct { 8 | RabbitmqRoutingKey string 9 | RabbitmqProcessingFunction func([]byte) 10 | } 11 | 12 | type ContainerOnStartMessage struct { 13 | ContainerName string `json:"container_name"` 14 | OperationID int `json:"operation_id"` 15 | OperationName string `json:"operation_name"` 16 | ServerName string `json:"server_name"` 17 | APIToken string `json:"apitoken"` 18 | } 19 | 20 | type ContainerOnStartMessageResponse struct { 21 | ContainerName string `json:"container_name"` 22 | EventLogInfoMessage string `json:"stdout"` 23 | EventLogErrorMessage string `json:"stderr"` 24 | RestartInternalServer bool `json:"restart_internal_server"` 25 | } 26 | 27 | type ContainerRPCGetFileMessage struct { 28 | ContainerName string `json:"container_name"` 29 | Filename string `json:"filename"` 30 | } 31 | 32 | type ContainerRPCGetFileMessageResponse struct { 33 | Success bool `json:"success"` 34 | Error string `json:"error"` 35 | Message []byte `json:"message"` 36 | } 37 | 38 | type ContainerRPCListFileMessage struct { 39 | ContainerName string `json:"container_name"` 40 | } 41 | 42 | type ContainerRPCListFileMessageResponse struct { 43 | Success bool `json:"success"` 44 | Error string `json:"error"` 45 | Files []string `json:"files"` 46 | } 47 | 48 | type ContainerRPCRemoveFileMessage struct { 49 | ContainerName string `json:"container_name"` 50 | Filename string `json:"filename"` 51 | } 52 | 53 | type ContainerRPCRemoveFileMessageResponse struct { 54 | Success bool `json:"success"` 55 | Error string `json:"error"` 56 | } 57 | 58 | type ContainerRPCWriteFileMessage struct { 59 | ContainerName string `json:"container_name"` 60 | Filename string `json:"filename"` 61 | Contents []byte `json:"contents"` 62 | } 63 | 64 | type ContainerRPCWriteFileMessageResponse struct { 65 | Success bool `json:"success"` 66 | Error string `json:"error"` 67 | Message string `json:"message"` 68 | } 69 | -------------------------------------------------------------------------------- /webhookstructs/alert_webhook.go: -------------------------------------------------------------------------------- 1 | package webhookstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | ) 8 | 9 | type NewAlertWebhookMessage struct { 10 | webhookMessageBase 11 | Data NewAlertWebhookData `json:"data"` 12 | } 13 | type NewAlertWebhookData struct { 14 | OperatorID int `json:"operator_id"` 15 | Message string `json:"message"` 16 | Source string `json:"source"` 17 | Count int `json:"count"` 18 | Timestamp string `json:"timestamp"` 19 | } 20 | 21 | // Register this method with rabbitmq so it can be called 22 | func init() { 23 | AllWebhookData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 24 | RabbitmqRoutingKey: WEBHOOK_TYPE_NEW_ALERT, 25 | RabbitmqProcessingFunction: processNewAlertWebhook, 26 | }) 27 | } 28 | func processNewAlertWebhook(input []byte) { 29 | inputStruct := NewAlertWebhookMessage{} 30 | if err := json.Unmarshal(input, &inputStruct); err != nil { 31 | logging.LogError(err, "Failed to process new callback webhook message") 32 | } else { 33 | // success, so do RPC calls to Mythic to get more context or send off webhook now 34 | for _, webhook := range AllWebhookData.GetAllNames() { 35 | if AllWebhookData.Get(webhook).GetWebhookDefinition().NewAlertFunction != nil { 36 | AllWebhookData.Get(webhook).GetWebhookDefinition().NewAlertFunction(inputStruct) 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /webhookstructs/custom_webhook.go: -------------------------------------------------------------------------------- 1 | package webhookstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | ) 8 | 9 | type NewCustomWebhookMessage struct { 10 | webhookMessageBase 11 | Data map[string]string `json:"data"` 12 | } 13 | 14 | // Register this method with rabbitmq so it can be called 15 | func init() { 16 | AllWebhookData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 17 | RabbitmqRoutingKey: WEBHOOK_TYPE_NEW_CUSTOM, 18 | RabbitmqProcessingFunction: processNewCustomWebhook, 19 | }) 20 | } 21 | func processNewCustomWebhook(input []byte) { 22 | inputStruct := NewCustomWebhookMessage{} 23 | if err := json.Unmarshal(input, &inputStruct); err != nil { 24 | logging.LogError(err, "Failed to process new callback webhook message") 25 | } else { 26 | // success, so do RPC calls to Mythic to get more context or send off webhook now 27 | for _, webhook := range AllWebhookData.GetAllNames() { 28 | if AllWebhookData.Get(webhook).GetWebhookDefinition().NewCustomFunction != nil { 29 | AllWebhookData.Get(webhook).GetWebhookDefinition().NewCustomFunction(inputStruct) 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /webhookstructs/new_callback_webhook.go: -------------------------------------------------------------------------------- 1 | package webhookstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | ) 8 | 9 | type NewCallbackWebookMessage struct { 10 | webhookMessageBase 11 | Data NewCallbackWebhookData `json:"data"` 12 | } 13 | 14 | type NewCallbackWebhookData struct { 15 | User string `json:"user" mapstructure:"user"` 16 | Host string `json:"host" mapstructure:"host"` 17 | IPs string `json:"ips" mapstructure:"ips"` 18 | Domain string `json:"domain" mapstructure:"domain"` 19 | ExternalIP string `json:"external_ip" mapstructure:"external_ip"` 20 | ProcessName string `json:"process_name" mapstructure:"process_name"` 21 | PID int `json:"pid" mapstructure:"pid"` 22 | Os string `json:"os" mapstructure:"os"` 23 | Architecture string `json:"architecture" mapstructure:"architecture"` 24 | AgentType string `json:"agent_type" mapstructure:"agent_type"` 25 | Description string `json:"description" mapstructure:"description"` 26 | ExtraInfo string `json:"extra_info" mapstructure:"extra_info"` 27 | SleepInfo string `json:"sleep_info" mapstructure:"sleep_info"` 28 | DisplayID int `json:"display_id" mapstructure:"display_id"` 29 | ID int `json:"id" mapstructure:"id"` 30 | IntegrityLevel int `json:"integrity_level" mapstructure:"integrity_level"` 31 | } 32 | 33 | // Register this method with rabbitmq so it can be called 34 | func init() { 35 | AllWebhookData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 36 | RabbitmqRoutingKey: WEBHOOK_TYPE_NEW_CALLBACK, 37 | RabbitmqProcessingFunction: processNewCallbackWebhook, 38 | }) 39 | } 40 | func processNewCallbackWebhook(input []byte) { 41 | inputStruct := NewCallbackWebookMessage{} 42 | if err := json.Unmarshal(input, &inputStruct); err != nil { 43 | logging.LogError(err, "Failed to process new callback webhook message") 44 | } else { 45 | // success, so do RPC calls to Mythic to get more context or send off webhook now 46 | for _, webhook := range AllWebhookData.GetAllNames() { 47 | if AllWebhookData.Get(webhook).GetWebhookDefinition().NewCallbackFunction != nil { 48 | AllWebhookData.Get(webhook).GetWebhookDefinition().NewCallbackFunction(inputStruct) 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /webhookstructs/new_feedback_webhook.go: -------------------------------------------------------------------------------- 1 | package webhookstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | ) 8 | 9 | type NewFeedbackWebookMessage struct { 10 | webhookMessageBase 11 | Data NewFeedbackWebhookData `json:"data"` 12 | } 13 | 14 | type NewFeedbackWebhookData struct { 15 | TaskID *int `json:"task_id,omitempty"` 16 | TaskDisplayID *int `json:"display_id,omitempty"` 17 | Message string `json:"message"` 18 | FeedbackType string `json:"feedback_type"` 19 | } 20 | 21 | // Register this method with rabbitmq so it can be called 22 | func init() { 23 | AllWebhookData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 24 | RabbitmqRoutingKey: WEBHOOK_TYPE_NEW_FEEDBACK, 25 | RabbitmqProcessingFunction: processNewFeedbackWebhook, 26 | }) 27 | } 28 | 29 | func processNewFeedbackWebhook(input []byte) { 30 | inputStruct := NewFeedbackWebookMessage{} 31 | if err := json.Unmarshal(input, &inputStruct); err != nil { 32 | logging.LogError(err, "Failed to process new feedback webhook message") 33 | } else { 34 | for _, webhook := range AllWebhookData.GetAllNames() { 35 | if AllWebhookData.Get(webhook).GetWebhookDefinition().NewFeedbackFunction != nil { 36 | AllWebhookData.Get(webhook).GetWebhookDefinition().NewFeedbackFunction(inputStruct) 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /webhookstructs/startup_webhook.go: -------------------------------------------------------------------------------- 1 | package webhookstructs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/MythicMeta/MythicContainer/logging" 6 | "github.com/MythicMeta/MythicContainer/utils/sharedStructs" 7 | ) 8 | 9 | type NewStartupWebhookMessage struct { 10 | webhookMessageBase 11 | Data NewStartupWebhookData `json:"data"` 12 | } 13 | type NewStartupWebhookData struct { 14 | StartupMessage string `json:"startup_message"` 15 | } 16 | 17 | // Register this method with rabbitmq so it can be called 18 | func init() { 19 | AllWebhookData.Get("").AddDirectMethod(sharedStructs.RabbitmqDirectMethod{ 20 | RabbitmqRoutingKey: WEBHOOK_TYPE_NEW_STARTUP, 21 | RabbitmqProcessingFunction: processNewStartupWebhook, 22 | }) 23 | } 24 | func processNewStartupWebhook(input []byte) { 25 | inputStruct := NewStartupWebhookMessage{} 26 | if err := json.Unmarshal(input, &inputStruct); err != nil { 27 | logging.LogError(err, "Failed to process new callback webhook message") 28 | } else { 29 | // success, so do RPC calls to Mythic to get more context or send off webhook now 30 | for _, webhook := range AllWebhookData.GetAllNames() { 31 | if AllWebhookData.Get(webhook).GetWebhookDefinition().NewStartupFunction != nil { 32 | AllWebhookData.Get(webhook).GetWebhookDefinition().NewStartupFunction(inputStruct) 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /webhookstructs/structs.go: -------------------------------------------------------------------------------- 1 | package webhookstructs 2 | 3 | type webhookMessageBase struct { 4 | OperationID int `json:"operation_id"` 5 | OperationName string `json:"operation_name"` 6 | OperationWebhook string `json:"operation_webhook"` 7 | OperationChannel string `json:"operation_channel"` 8 | OperatorUsername string `json:"operator_username"` 9 | ServerName string `json:"server_name"` 10 | Action WEBHOOK_TYPE `json:"action"` 11 | } 12 | 13 | type SlackWebhookMessage struct { 14 | Channel string `json:"channel"` 15 | Username string `json:"username"` 16 | IconEmoji string `json:"icon_emoji"` 17 | Attachments []SlackWebhookMessageAttachment `json:"attachments"` 18 | } 19 | 20 | type SlackWebhookMessageAttachment struct { 21 | Title string `json:"fallback"` 22 | Color string `json:"color,omitempty"` 23 | Blocks *[]SlackWebhookMessageAttachmentBlock `json:"blocks,omitempty"` 24 | } 25 | 26 | type SlackWebhookMessageAttachmentBlock struct { 27 | Type string `json:"type"` 28 | Text *SlackWebhookMessageAttachmentBlockText `json:"text,omitempty"` 29 | Fields *[]SlackWebhookMessageAttachmentBlockText `json:"fields,omitempty"` 30 | } 31 | 32 | type SlackWebhookMessageAttachmentBlockText struct { 33 | Type string `json:"type,omitempty"` 34 | Text string `json:"text,omitempty"` 35 | } 36 | 37 | func GetNewDefaultWebhookMessage() SlackWebhookMessage { 38 | headerBlockText := SlackWebhookMessageAttachmentBlockText{ 39 | Type: "mrkdwn", 40 | Text: "You have a new message from Mythic!", 41 | } 42 | 43 | blocks := []SlackWebhookMessageAttachmentBlock{ 44 | { 45 | Type: "section", 46 | Text: &headerBlockText, 47 | }, 48 | { 49 | Type: "divider", 50 | }, 51 | } 52 | newMsg := SlackWebhookMessage{ 53 | Username: "Mythic", 54 | IconEmoji: ":mythic:", 55 | Channel: "#mythic-notifications", 56 | Attachments: []SlackWebhookMessageAttachment{ 57 | { 58 | Title: "New Mythic Message!", 59 | Color: "#b366ff", 60 | Blocks: &blocks, 61 | }, 62 | }, 63 | } 64 | return newMsg 65 | } 66 | --------------------------------------------------------------------------------