Skip to content

Commit

Permalink
UI bug fix and increased web logging
Browse files Browse the repository at this point in the history
  • Loading branch information
its-a-feature committed Sep 13, 2024
1 parent 11bfff6 commit 9852d5d
Show file tree
Hide file tree
Showing 19 changed files with 250 additions and 31 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Updated some of the logging for bad messages to be clearer

## [3.3.1-rc8] - 2024-09-13

### Changed

- Added more verbose error messages on connections to include user agent and full URL + Query paths
- Requires latest `http` and `websocket` profiles to forward the necessary headers
- Added more context for GraphQL queries used by APITokens/Scripting to the event log
- Fixed a bug with exporting saved c2 profile instances that would then break imports

## [3.3.1-rc6] - 2024-09-04

### Changed
Expand Down
6 changes: 6 additions & 0 deletions MythicReactUI/CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.43] - 2024-09-13

## Changed

- Fixed an issue with export saved c2 profile instances improperly representing dictionaries

## [0.2.42] - 2024-09-10

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,15 @@ export function C2ProfileSavedInstancesDialog(props) {
instance_name: instanceName
};
configuration.c2_instance = currentParameters.reduce( (prev, cur) => {
return {...prev, [cur.name]:cur.value};
switch (cur.parameter_type) {
case "Dictionary":
const condensed = cur.value.reduce( (p, c) => {
return {...p, [c.name]: c.value}
}, {});
return {...prev, [cur.name]: condensed};
default:
return {...prev, [cur.name]:cur.value};
}
}, {});
const dataBlob = new Blob([JSON.stringify(configuration, null, 2)], {type: 'text/plain'});
const ele = document.getElementById("download_instance");
Expand Down
2 changes: 1 addition & 1 deletion MythicReactUI/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {snackActions} from './components/utilities/Snackbar';
import jwt_decode from 'jwt-decode';
import {meState} from './cache';

export const mythicUIVersion = "0.2.42";
export const mythicUIVersion = "0.2.43";

let fetchingNewToken = false;

Expand Down
5 changes: 3 additions & 2 deletions Mythic_CLI/src/cmd/manager/dockerComposeManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ func (d *DockerComposeManager) StopServices(services []string, deleteImages bool
}
}
if !found {
log.Printf("[-] Failed to find container: %s\n", service)
log.Printf("[*] Container not running: %s\n", service)
}
}
return nil
Expand Down Expand Up @@ -685,7 +685,8 @@ func (d *DockerComposeManager) Status(verbose bool) {
log.Fatalf("[-] Failed to get client in Status check: %v", err)
}
containers, err := cli.ContainerList(context.Background(), container.ListOptions{
All: true,
All: true,
Size: true,
})
if err != nil {
log.Fatalf("[-] Failed to get container list: %v\n", err)
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.3.1-rc7
3.3.1-rc8
2 changes: 1 addition & 1 deletion jupyter-docker/.docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ARG PIP_INDEX
ARG PIP_INDEX_URL
ARG PIP_TRUSTED_HOST

RUN pip3 install mythic==0.2.0
RUN pip3 install mythic==0.2.4

WORKDIR /projects

Expand Down
2 changes: 1 addition & 1 deletion jupyter-docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ARG PIP_INDEX
ARG PIP_INDEX_URL
ARG PIP_TRUSTED_HOST

RUN pip3 install mythic==0.2.0
RUN pip3 install mythic==0.2.4

WORKDIR /projects

Expand Down
115 changes: 115 additions & 0 deletions jupyter-docker/jupyter/MythicExamples/AgentMessages.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "78922966-f039-4bde-baed-893afbc6492a",
"metadata": {},
"outputs": [],
"source": [
"from mythic import mythic"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6fdb246e-7fd0-4660-9ad0-01431ea1e435",
"metadata": {},
"outputs": [],
"source": [
"mythic_instance = await mythic.login(\n",
" username=\"mythic_admin\",\n",
" password=\"mythic_password\",\n",
" server_ip=\"mythic_nginx\",\n",
" server_port=7443,\n",
" timeout=-1\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bb78634e-0127-48bf-b366-d033768841c3",
"metadata": {},
"outputs": [],
"source": [
"## Send a JSON agent message as though it came from a certain callback and parse the response ###\n",
"# This currently only works with 36 character UUID Strings and no translation containers\n",
"# Must specify a C2 Profile and the Agent Callback ID so Mythic can look up the right crypto\n",
"resp = await mythic.send_callback_agent_message_dict(mythic=mythic_instance,\n",
" c2_profile=\"http\",\n",
" agent_callback_id=\"69ed4277-4832-4d94-8536-d4137b97d7a0\",\n",
" message={\n",
" \"action\": \"update_info\",\n",
" \"user\": \"bob\"\n",
" })\n",
"print(resp)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fef01140-4201-406e-bc69-e1b756035705",
"metadata": {},
"outputs": [],
"source": [
"## Take a JSON message that a callback would send, encrypt it, and optionally include the UUID + base64 encode ##\n",
"encryptedMsg = await mythic.local_encrypt_agent_message(mythic=mythic_instance,\n",
" agent_callback_id=\"69ed4277-4832-4d94-8536-d4137b97d7a0\",\n",
" include_uuid=True,\n",
" base64_result=True,\n",
" message={\n",
" \"action\": \"update_info\",\n",
" \"user\": \"heracles\"\n",
" }\n",
" )\n",
"print(encryptedMsg)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a3dc3c6f-296b-4bd8-9839-bab1acf7e8e3",
"metadata": {},
"outputs": [],
"source": [
"## Take an existing, base64 message that an agent would send and forward it to Mythic, optionally processing the response ##\n",
"resp = await mythic.send_callback_agent_message_base64(mythic=mythic_instance,\n",
" c2_profile=\"http\",\n",
" message=encryptedMsg,\n",
" agent_callback_id=\"69ed4277-4832-4d94-8536-d4137b97d7a0\",\n",
" decrypt_response=True)\n",
"print(resp)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b31bcf1c-7cc4-48ee-a539-b9a86373dcaa",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
27 changes: 27 additions & 0 deletions jupyter-docker/jupyter/MythicExamples/CustomQueries.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,33 @@
"id": "654b1348-cf5f-4b2c-9d01-bed63d613a6b",
"metadata": {},
"outputs": [],
"source": [
"# ################ Custom query with variables ################\n",
"operation = await mythic.execute_custom_query(\n",
" mythic=mythic_instance,\n",
" query=\"\"\"\n",
" query specificOperation($operation_name: String!){\n",
" operation(where: {name: {_eq: $operation_name}}) {\n",
" id\n",
" name\n",
" operators {\n",
" id\n",
" username\n",
" }\n",
" }\n",
" }\n",
"\"\"\",\n",
" variables={\"operation_name\": \"Operation Chimera\"}\n",
")\n",
"print(operation)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "076c3a79-b433-4d51-a9e7-0ad89537a8d9",
"metadata": {},
"outputs": [],
"source": []
}
],
Expand Down
2 changes: 1 addition & 1 deletion mythic-docker/src/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.3.1-rc7
3.3.1-rc8
39 changes: 33 additions & 6 deletions mythic-docker/src/authentication/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,25 @@ func TokenValid(c *gin.Context) error {
} else {
c.Request.Header.Add("MythicSource", "apitoken")
}
c.Set("apitoken_logging_struct", databaseApiToken)
c.Set("user_id", databaseApiToken.OperatorID)
c.Set("username", databaseApiToken.Operator.Username)
c.Set("apitoken", databaseApiToken.Name)
c.Set("account", databaseApiToken.Operator.AccountType)
go func(token databaseStructs.Apitokens) {
go rabbitmq.SendAllOperationsMessage(fmt.Sprintf("APIToken, %s (%s), for user %s (%s) just used",
token.Name, token.TokenType, token.Operator.Username, token.Operator.AccountType),
int(token.Operator.CurrentOperationID.Int64), token.TokenValue,
database.MESSAGE_LEVEL_DEBUG)
}(databaseApiToken)
/*
if hasura, ok := c.Get("hasura"); ok {
logging.LogInfo("got hasura info", "hasura", hasura)
} else {
logging.LogInfo("no hasura info yet")
}
go func(token databaseStructs.Apitokens) {
go rabbitmq.SendAllOperationsMessage(fmt.Sprintf("APIToken, %s, for user %s (%s) just used",
token.Name, token.Operator.Username, token.Operator.AccountType),
int(token.Operator.CurrentOperationID.Int64), token.TokenValue,
database.MESSAGE_LEVEL_DEBUG)
}(databaseApiToken)
*/
return nil
}
claims := mythicjwt.CustomClaims{}
Expand Down Expand Up @@ -162,6 +171,14 @@ func ExtractToken(c *gin.Context) (string, error) {
if c.Request.Method == "POST" {
if _, ok := c.Get("hasura"); !ok {
// don't try to double process, only do this once
/*
var buf bytes.Buffer
tee := io.TeeReader(c.Request.Body, &buf)
body, _ := ioutil.ReadAll(tee)
c.Request.Body = ioutil.NopCloser(&buf)
logging.LogInfo("raw hasura info", "raw body", string(body))
*/
var input HasuraRequest
if err := c.ShouldBindJSON(&input); err != nil {
logging.LogError(err, "Failed to find hasura request")
Expand All @@ -171,6 +188,7 @@ func ExtractToken(c *gin.Context) (string, error) {
c.Request.Header.Add(key, value)
}
c.Set("hasura", input)
//logging.LogInfo("hasura info", "hasura", input)
}
}
token = c.Request.Header.Get("Authorization")
Expand All @@ -196,6 +214,14 @@ func ExtractAPIToken(c *gin.Context) (string, error) {
if c.Request.Method == "POST" {
if _, ok := c.Get("hasura"); !ok {
// don't try to double process, only do this once
/*
var buf bytes.Buffer
tee := io.TeeReader(c.Request.Body, &buf)
body, _ := ioutil.ReadAll(tee)
c.Request.Body = ioutil.NopCloser(&buf)
logging.LogInfo("raw hasura info", "raw body", string(body))
*/
var input HasuraRequest
if err := c.ShouldBindJSON(&input); err != nil {
logging.LogError(err, "Failed to find hasura request")
Expand All @@ -205,6 +231,7 @@ func ExtractAPIToken(c *gin.Context) (string, error) {
c.Request.Header.Add(key, value)
}
c.Set("hasura", input)
//logging.LogInfo("hasura info", "hasura", input)
}
}
token = c.Request.Header.Get("apitoken")
Expand Down
Loading

0 comments on commit 9852d5d

Please sign in to comment.