mirror of
https://github.com/its-a-feature/Mythic
synced 2026-06-08 14:55:38 +00:00
v3.0.1-rc28
updated the way container status is checked to hopefully reduce rabbitmq errors
This commit is contained in:
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [3.0.1-rc28] - 2023-06-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated check for container status to use rabbitmq REST api to port 15672 instead of passively declaring queues
|
||||
- Updated rabbitmq image to rabbitmq:3-management-alpine to support the above bullet
|
||||
|
||||
## [3.0.1-rc26] - 2023-06-26
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.1.15-rc25] - 2023-06-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated payload building page to not cache query for payload types
|
||||
- Updated active callbacks table to have a button for adjusting IP instead of right clicking
|
||||
- Updated c2 profile page's stdout viewer to not cache queries
|
||||
|
||||
## [0.1.15-rc24] - 2023-06-21
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -36,8 +36,8 @@ import InfoIcon from '@mui/icons-material/Info';
|
||||
import { MythicStyledTooltip } from '../../MythicComponents/MythicStyledTooltip';
|
||||
import {TaskFromUIButton} from './TaskFromUIButton';
|
||||
import {CallbacksTabsTaskMultipleDialog} from './CallbacksTabsTaskMultipleDialog';
|
||||
import {CallbacksTabsHideMultipleDialog} from './CallbacksTabsHideMultipleDialog';
|
||||
import { MythicSelectFromRawListDialog } from '../../MythicComponents/MythicSelectFromListDialog';
|
||||
import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
|
||||
|
||||
// callback_stream(batch_size: 1, cursor: {initial_value: {last_checkin: "1970-01-01"}}, where: {id: {_eq: $callback_id}}){
|
||||
// still have some issues with the stream unfortunately
|
||||
@@ -377,7 +377,14 @@ export const CallbacksTableIPCell = ({cellData, rowData, callback_id, updateIPs}
|
||||
}, [cellData]);
|
||||
return (
|
||||
<>
|
||||
<div onContextMenu={onClick}>{displayIP}</div>
|
||||
<div style={{display: "flex", alignItems: "center"}}>
|
||||
{options.length > 1 &&
|
||||
<MythicStyledTooltip title={"Adjust Displayed"}>
|
||||
<UnfoldMoreIcon onClick={onClick} style={{paddingTop: "5px", cursor: "pointer"}} />
|
||||
</MythicStyledTooltip>
|
||||
}
|
||||
{displayIP}
|
||||
</div>
|
||||
{openPickIP &&
|
||||
<MythicDialog fullWidth={true} open={openPickIP} onClose={() => {setOpenPickIP(false);}}
|
||||
innerDialog={
|
||||
|
||||
@@ -87,7 +87,9 @@ export function Step2SelectPayloadType(props){
|
||||
const [fileExtension, setFileExtension] = React.useState('');
|
||||
const [supportsDynamicLoading, setSupportsDynamicLoading] = React.useState(false);
|
||||
const [payloadTypeParameters, setSelectedPayloadTypeParameters] = React.useState([]);
|
||||
const { loading, error, data } = useQuery(GET_Payload_Types, {variables:{os: props.buildOptions },
|
||||
const { loading, error, data } = useQuery(GET_Payload_Types,
|
||||
{variables:{os: props.buildOptions },
|
||||
fetchPolicy: "no-cache",
|
||||
onCompleted: data => {
|
||||
if(data.payloadtype.length > 0){
|
||||
if(props.prevData !== undefined && props.prevData.os === props.buildOptions){
|
||||
|
||||
@@ -36,7 +36,9 @@ export function Step2SelectPayloadType(props){
|
||||
const [selectedPayloadTypeID, setSelectedPayloadTypeID] = React.useState(0);
|
||||
const [fileExtension, setFileExtension] = React.useState('');
|
||||
const [payloadTypeParameters, setSelectedPayloadTypeParameters] = React.useState([]);
|
||||
const { loading, error, data } = useQuery(GET_Payload_Types, {variables:{os: props.buildOptions},
|
||||
const { loading, error, data } = useQuery(GET_Payload_Types,
|
||||
{variables:{os: props.buildOptions},
|
||||
fetchPolicy: "no-cache",
|
||||
onCompleted: data => {
|
||||
if(data.payloadtype.length > 0){
|
||||
if(props.prevData !== undefined && props.prevData.os === props.buildOptions){
|
||||
|
||||
+21
-12
@@ -5,12 +5,12 @@ import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import {useQuery, gql} from '@apollo/client';
|
||||
import LinearProgress from '@mui/material/LinearProgress';
|
||||
import AceEditor from 'react-ace';
|
||||
import 'ace-builds/src-noconflict/mode-json';
|
||||
import 'ace-builds/src-noconflict/theme-monokai';
|
||||
import 'ace-builds/src-noconflict/theme-xcode';
|
||||
import {useTheme} from '@mui/material/styles';
|
||||
import {snackActions} from "../../utilities/Snackbar";
|
||||
|
||||
const getProfileOutputQuery = gql`
|
||||
query getProfileOutput($id: Int!) {
|
||||
@@ -24,20 +24,29 @@ query getProfileOutput($id: Int!) {
|
||||
|
||||
export function C2ProfileOutputDialog(props) {
|
||||
const theme = useTheme();
|
||||
const { loading, error, data } = useQuery(getProfileOutputQuery, {
|
||||
const [outputData, setOutputData] = React.useState("Waiting 3s for data...");
|
||||
useQuery(getProfileOutputQuery, {
|
||||
variables: {id: props.profile_id},
|
||||
onCompleted: data => {
|
||||
//console.log("completed", data.getProfileOutput.output)
|
||||
console.log("completed")
|
||||
if(data.getProfileOutput.status === "success"){
|
||||
if(data.getProfileOutput.output.length === 0){
|
||||
setOutputData("No data from server");
|
||||
} else {
|
||||
setOutputData(data.getProfileOutput.output);
|
||||
}
|
||||
|
||||
} else {
|
||||
snackActions.error(data.getProfileOutput.error);
|
||||
}
|
||||
|
||||
},
|
||||
fetchPolicy: "network-only"
|
||||
onError: data => {
|
||||
snackActions.error(data.message);
|
||||
console.log(data);
|
||||
},
|
||||
fetchPolicy: "no-cache"
|
||||
});
|
||||
if (loading) {
|
||||
return <LinearProgress />;
|
||||
}
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return <div>Error! {error.message}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -53,7 +62,7 @@ export function C2ProfileOutputDialog(props) {
|
||||
showGutter={true}
|
||||
height={"100px"}
|
||||
highlightActiveLine={true}
|
||||
value={data.getProfileOutput.output}
|
||||
value={outputData}
|
||||
width={"100%"}
|
||||
minLines={2}
|
||||
maxLines={50}
|
||||
|
||||
@@ -16,8 +16,8 @@ import MessageTypes from 'subscriptions-transport-ws/dist/message-types';
|
||||
import jwt_decode from 'jwt-decode';
|
||||
import {meState} from './cache';
|
||||
|
||||
export const mythicVersion = "3.0.1-rc25";
|
||||
export const mythicUIVersion = "0.1.15-rc24";
|
||||
export const mythicVersion = "3.0.1-rc28";
|
||||
export const mythicUIVersion = "0.1.15-rc25";
|
||||
|
||||
let fetchingNewToken = false;
|
||||
|
||||
|
||||
+4
-2
@@ -5,8 +5,10 @@
|
||||
The following the table details the supported versions of Mythic.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 2.3.7 | :white_check_mark: |
|
||||
|---------| ------------------ |
|
||||
| 3.0.0 | :white_check_mark: |
|
||||
| 2.3.13 | :x: |
|
||||
| 2.3.9 | :x: |
|
||||
| < 2.3.0 | :x: |
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package rabbitmq
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/its-a-feature/Mythic/grpc"
|
||||
"github.com/its-a-feature/Mythic/utils"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/its-a-feature/Mythic/database"
|
||||
@@ -61,27 +66,91 @@ func initializeContainers() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tr = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
MaxIdleConns: 10,
|
||||
MaxConnsPerHost: 10,
|
||||
//IdleConnTimeout: 1 * time.Nanosecond,
|
||||
}
|
||||
var httpClient = &http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
Transport: tr,
|
||||
}
|
||||
|
||||
type rabbitmqAPIQuery struct {
|
||||
FilteredCount int `json:"filtered_count" mapstructure:"filtered_count"`
|
||||
ItemCount int `json:"item_count" mapstructure:"item_count"`
|
||||
Items []map[string]interface{} `json:"items" mapstructure:"items"`
|
||||
Page int `json:"page" mapstructure:"page"`
|
||||
PageCount int `json:"page_count" mapstructure:"page_count"`
|
||||
PageSize int `json:"page_size" mapstructure:"page_size"`
|
||||
TotalCount int `json:"total_count" mapstructure:"total_count"`
|
||||
}
|
||||
|
||||
func checkContainerStatus() {
|
||||
// get all queues from rabbitmq
|
||||
// http://rabbitmq_user:rabbitmq_password@rabbitmq_host:15672/rabbitmq/api/queues/mythic_vhost
|
||||
rabbitmqReqURL := fmt.Sprintf("http://%s:%s@%s:15672/api/queues/mythic_vhost?use_regex=true&page=1&page_size=500&name=%s",
|
||||
utils.MythicConfig.RabbitmqUser, utils.MythicConfig.RabbitmqPassword, utils.MythicConfig.RabbitmqHost,
|
||||
fmt.Sprintf("(.%%2A_%s|.%%2A_%s)", PT_BUILD_ROUTING_KEY, C2_RPC_START_SERVER_ROUTING_KEY))
|
||||
go checkContainerStatusAddPT()
|
||||
go checkContainerStatusAddC2()
|
||||
go checkContainerStatusAddTR()
|
||||
go initializeContainers()
|
||||
for {
|
||||
time.Sleep(CHECK_CONTAINER_STATUS_DELAY)
|
||||
rabbitmqReq, err := http.NewRequest("GET", rabbitmqReqURL, nil)
|
||||
if err != nil {
|
||||
logging.LogError(err, "Failed to generate http request to fetch queues from rabbitmq")
|
||||
continue
|
||||
}
|
||||
rabbitmqResponse, err := httpClient.Do(rabbitmqReq)
|
||||
if err != nil {
|
||||
logging.LogError(err, "Failed to fetch queues from rabbitmq")
|
||||
continue
|
||||
}
|
||||
if rabbitmqResponse.StatusCode != 200 {
|
||||
logging.LogError(nil, "Failed to get a good status code from rabbitmq",
|
||||
"status_code", rabbitmqResponse.StatusCode, "status", rabbitmqResponse.Status)
|
||||
continue
|
||||
}
|
||||
rabbitmqBody, err := io.ReadAll(rabbitmqResponse.Body)
|
||||
if err != nil {
|
||||
logging.LogError(err, "Failed to read body of message from rabbitmq")
|
||||
rabbitmqResponse.Body.Close()
|
||||
continue
|
||||
}
|
||||
rabbitmqResponse.Body.Close()
|
||||
|
||||
rabbitmqQueues := rabbitmqAPIQuery{}
|
||||
err = json.Unmarshal(rabbitmqBody, &rabbitmqQueues)
|
||||
if err != nil {
|
||||
logging.LogError(err, "Failed to convert rabbitmq response into list of dictionaries")
|
||||
continue
|
||||
}
|
||||
//logging.LogInfo("got message from rabbitmq", "queue body", rabbitmqQueues)
|
||||
existingQueues := make([]string, len(rabbitmqQueues.Items))
|
||||
for index, queue := range rabbitmqQueues.Items {
|
||||
if queueName, ok := queue["name"]; !ok {
|
||||
logging.LogError(nil, "no 'name' field in queue information from rabbitmq")
|
||||
} else {
|
||||
existingQueues[index] = queueName.(string)
|
||||
//logging.LogInfo("found queue", "queue", queueName)
|
||||
}
|
||||
}
|
||||
|
||||
// loop through payload types
|
||||
for container := range payloadTypesToCheck {
|
||||
//logging.LogDebug("checking container", "container", container)
|
||||
// check that a container is online
|
||||
running, err := RabbitMQConnection.CheckPayloadTypeContainerExists(payloadTypesToCheck[container].Name)
|
||||
//logging.LogInfo("checking container running", "container", container, "running", running, "current_running", payloadTypesToCheck[container].ContainerRunning)
|
||||
if err != nil {
|
||||
logging.LogError(err, "Failed to check for payloadtype container existence")
|
||||
} else if running != payloadTypesToCheck[container].ContainerRunning {
|
||||
running := utils.SliceContains(existingQueues, GetPtBuildRoutingKey(payloadTypesToCheck[container].Name))
|
||||
if running != payloadTypesToCheck[container].ContainerRunning {
|
||||
if entry, ok := payloadTypesToCheck[container]; ok {
|
||||
entry.ContainerRunning = running
|
||||
if _, err = database.DB.NamedExec(`UPDATE payloadtype SET
|
||||
container_running=:container_running, deleted=false
|
||||
WHERE id=:id`, entry,
|
||||
if _, err = database.DB.NamedExec(`UPDATE payloadtype SET
|
||||
container_running=:container_running, deleted=false
|
||||
WHERE id=:id`, entry,
|
||||
); err != nil {
|
||||
logging.LogError(err, "Failed to set container running status", "container_running", payloadTypesToCheck[container].ContainerRunning, "container", container)
|
||||
} else {
|
||||
@@ -97,19 +166,15 @@ func checkContainerStatus() {
|
||||
} else {
|
||||
logging.LogError(nil, "Failed to get payload type from map for updating running status")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// loop through c2 profiles
|
||||
for container := range c2profilesToCheck {
|
||||
// check that a container is online
|
||||
//logging.LogDebug("checking container", "container", container)
|
||||
running, err := RabbitMQConnection.CheckC2ProfileContainerExists(container)
|
||||
running := utils.SliceContains(existingQueues, GetC2RPCStartServerRoutingKey(c2profilesToCheck[container].Name))
|
||||
//logging.LogInfo("checking container running", "container", container, "running", running, "current_running", c2profilesToCheck[container].ContainerRunning)
|
||||
if err != nil {
|
||||
logging.LogError(err, "Failed to check for c2 container existence")
|
||||
} else if running != c2profilesToCheck[container].ContainerRunning {
|
||||
if running != c2profilesToCheck[container].ContainerRunning {
|
||||
if entry, ok := c2profilesToCheck[container]; ok {
|
||||
entry.ContainerRunning = running
|
||||
if _, err = database.DB.NamedExec(`UPDATE c2profile SET
|
||||
@@ -129,7 +194,6 @@ func checkContainerStatus() {
|
||||
} else {
|
||||
logging.LogError(nil, "Failed to get c2 profile from map for updating running status")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// loop through translation containers
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/new/static/css/main.4722e92b.css",
|
||||
"main.js": "/new/static/js/main.cec2d3ce.js",
|
||||
"main.js": "/new/static/js/main.472aed0e.js",
|
||||
"static/media/mythic.svg": "/new/static/media/mythic.7189479fdfbd51ae729872ce2cb98784.svg",
|
||||
"static/media/mythic_red_small.svg": "/new/static/media/mythic_red_small.793b41cc7135cdede246661ec232976b.svg",
|
||||
"index.html": "/new/index.html",
|
||||
"main.4722e92b.css.map": "/new/static/css/main.4722e92b.css.map",
|
||||
"main.cec2d3ce.js.map": "/new/static/js/main.cec2d3ce.js.map"
|
||||
"main.472aed0e.js.map": "/new/static/js/main.472aed0e.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.4722e92b.css",
|
||||
"static/js/main.cec2d3ce.js"
|
||||
"static/js/main.472aed0e.js"
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/new/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><link rel="apple-touch-icon" href="/new/logo192.png"/><link rel="manifest" href="/new/manifest.json"/><title>Mythic</title><script defer="defer" src="/new/static/js/main.cec2d3ce.js"></script><link href="/new/static/css/main.4722e92b.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/new/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><link rel="apple-touch-icon" href="/new/logo192.png"/><link rel="manifest" href="/new/manifest.json"/><title>Mythic</title><script defer="defer" src="/new/static/js/main.472aed0e.js"></script><link href="/new/static/css/main.4722e92b.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1,3 @@
|
||||
FROM rabbitmq:3-alpine
|
||||
#FROM rabbitmq:3-alpine
|
||||
FROM rabbitmq:3-management-alpine
|
||||
ADD rabbitmq.conf /etc/rabbitmq/rabbitmq.conf
|
||||
Reference in New Issue
Block a user