Compare commits

...
12 Commits
Author SHA1 Message Date
Cody Thomas 96b24b48a7 Merge pull request #594 from je4yfc/integration
Generalized Support for external services across compose generation and port checks
2026-10-11 10:24:27 -05:00
Cody Thomas bdc722f6ce Merge pull request #589 from mjmaley/fix/cli-pasted-whitespace
Handle pasted whitespace in task arguments
2026-10-08 10:39:11 -05:00
Joseph Erdosy f9e71d0859 feat(cli): generalize external service handling in compose configuration and port checks
Signed-off-by: Joseph Erdosy <[email protected]>
2026-09-10 10:46:37 -04:00
Joseph Erdosy 742d878928 fix(cli): support external Nginx and create config dir for block lists
Signed-off-by: Joseph Erdosy <[email protected]>
2026-09-10 10:46:34 -04:00
Joseph Erdosy 01ea8bc896 feat(database): add external PostgreSQL support and configurable SSL mode (#587, #590)
Signed-off-by: Joseph Erdosy <[email protected]>
2026-09-10 10:46:31 -04:00
pwn 94418bcd52 fix(cli): fail fast on docker-compose failures instead of misleading health loop
The pty path in runDockerCompose returned the (nil) error variable on
nonzero exit, and start() discarded ServiceStart's error. Both together
let 'mythic-cli start' proceed into the UI probe loop after a failed
compose up, ending in os.Exit(1) with unrelated diagnostics (run-1.log).

- dockerComposeManager.runDockerCompose: return a descriptive error on
  nonzero exit in the pty path
- start: log.Fatalf on ServiceStart error so compose failures surface
  immediately

Signed-off-by: Joseph Erdosy <[email protected]>
2026-09-10 10:46:28 -04:00
Cody Thomas 3ae9c5fe18 Merge pull request #593 from je4yfc/cli-error-handling-fixes
fix(cli): fail fast on docker-compose failures in mythic-cli start
2026-09-07 10:57:19 -05:00
pwn 5e85a20d14 fix(cli): fail fast on docker-compose failures instead of misleading health loop
The pty path in runDockerCompose returned the (nil) error variable on
nonzero exit, and start() discarded ServiceStart's error. Both together
let 'mythic-cli start' proceed into the UI probe loop after a failed
compose up, ending in os.Exit(1) with unrelated diagnostics (run-1.log).

- dockerComposeManager.runDockerCompose: return a descriptive error on
  nonzero exit in the pty path
- start: log.Fatalf on ServiceStart error so compose failures surface
  immediately
2026-09-06 14:29:33 -04:00
mjmaley 5f46db6ede Handle pasted whitespace in task arguments 2026-09-02 16:56:36 -04:00
its-a-feature e37e057a89 process browser fix 2026-07-16 13:02:35 -07:00
github-actions 33a46d7db7 Bump Mythic Dockerfile tag to match release 'v3.4.0.61' 2026-07-01 16:06:33 +00:00
its-a-feature 540aec0f00 fixing filtering bug in process browser 2026-07-01 08:45:06 -07:00
22 changed files with 212 additions and 183 deletions

No files matched your search

+6
View File
@@ -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.3.113] - 2026-07-01
### Changed
- Fixed a bug in the process browser that would set a filter to undefined instead of ""
## [0.3.112] - 2026-05-17
- Updated the single task view to show interactive tasking surrounding results
@@ -197,11 +197,13 @@ export const CallbacksTabsFileBrowserTable = (props) => {
return tempData;
}, [allData, sortData]);
const onSubmitFilterOptions = (value) => {
setFilterOptions({...filterOptions, [selectedColumn.key]: value });
try{
updateSetting({setting_name: `file_browser_filter_options`, value: {...filterOptions,[selectedColumn.key]: value }});
let newValue = value ? value : "";
setFilterOptions({...filterOptions, [selectedColumn.key]: newValue });
updateSetting({setting_name: `file_browser_filter_options`, value: {...filterOptions,[selectedColumn.key]: newValue }});
}catch(error){
console.log("failed to save filter options");
console.log("failed to save filter options", error);
}
}
const filterRow = (row) => {
@@ -393,11 +393,12 @@ export const CallbacksTabsProcessBrowserTable = ({treeAdjMatrix, treeRootData, m
return tempData;
}, [allData, sortData]);
const onSubmitFilterOptions = (value) => {
setFilterOptions({...filterOptions, [selectedColumn.current.key]: value });
let newValue = value ? value : "";
try{
updateSetting({setting_name: `process_browser_filter_options`, value: {...filterOptions,[selectedColumn.current.key]: value }});
setFilterOptions({...filterOptions, [selectedColumn.current.key]: newValue });
updateSetting({setting_name: `process_browser_filter_options`, value: {...filterOptions,[selectedColumn.current.key]: newValue }});
}catch(error){
console.log("failed to save filter options");
console.log("failed to save filter options", error, filterOptions, selectedColumn.current.key, newValue);
}
if(viewSingleTreeData){
return
@@ -495,7 +496,7 @@ export const CallbacksTabsProcessBrowserTable = ({treeAdjMatrix, treeRootData, m
}
setSingleTreeData(singleTreeAdjMatrix);
onSubmitFilterOptions({});
onSubmitFilterOptions(undefined);
}
const toggleViewSingleTreeData = () => {
setViewSingleTreeData(!viewSingleTreeData);
@@ -767,7 +768,7 @@ export const CallbacksTabsProcessBrowserTable = ({treeAdjMatrix, treeRootData, m
<MythicModifyStringDialog
title='Filter Column'
onSubmit={onSubmitFilterOptions}
value={filterOptions[selectedColumn.current]}
value={String(filterOptions[selectedColumn.current.key])}
onClose={() => {
setOpenContextMenu(false);
}}
@@ -827,7 +827,7 @@ export function CallbacksTabsTaskingInputPreMemo(props){
buffer += value;
return;
}
else if(value === " "){
else if([" ", "\t", "\r", "\n"].includes(value)){
if(backslash){
backslash = false;
//buffer += " ";
+1 -1
View File
@@ -15,7 +15,7 @@ import {jwtDecode} from 'jwt-decode';
import {meState} from './cache';
import {getSkewedNow} from "./components/utilities/Time";
export const mythicUIVersion = "0.3.112";
export const mythicUIVersion = "0.3.114";
let fetchingNewToken = false;
+1 -1
View File
@@ -1,6 +1,6 @@
BINARY_NAME=mythic-cli
LOCAL_PATH=$(shell pwd)
BUILDER_IMAGE=ghcr.io/its-a-feature/mythic_cli:v3.4.0.60
BUILDER_IMAGE=ghcr.io/its-a-feature/mythic_cli:v3.4.0.61
.PHONY: default
default: build_linux ;
+1 -1
View File
@@ -2,5 +2,5 @@ package config
// MythicDockerLatest is the most recent tagged version pushed to GitHub packages
const MythicDockerLatest = "v3.4.0.60"
const MythicDockerLatest = "v3.4.0.61"
+3
View File
@@ -271,6 +271,9 @@ If it's anything else, mythic-cli will not spin up this container as it assumes
mythicEnv.SetDefault("postgres_password", utils.GenerateRandomPassword(30))
mythicEnvInfo["postgres_password"] = `This is the randomly generated password that mythic_server and mythic_graphql use to connect to the mythic_postgres container`
mythicEnv.SetDefault("postgres_sslmode", "disable")
mythicEnvInfo["postgres_sslmode"] = `This specifies the SSL mode used when connecting to the PostgreSQL database (e.g. disable, require, verify-ca, verify-full)`
mythicEnv.SetDefault("postgres_cpus", defaultNumberOfCPUs)
mythicEnvInfo["postgres_cpus"] = `Set this to limit the maximum number of CPUs this service is able to consume`
@@ -87,8 +87,14 @@ func ServiceStart(containers []string, keepVolume bool) error {
log.Printf("[-] Failed to remove images\n%v\n", err)
return err
}
updateNginxBlockLists()
generateCerts()
// nginx-specific housekeeping only applies when mythic_nginx runs locally
if isServiceInternal("mythic_nginx") {
updateNginxBlockLists()
if err := generateCerts(); err != nil {
log.Printf("[-] Failed to generate certs: %v\n", err)
return err
}
}
TestMythicRabbitmqConnection()
TestMythicConnection()
Status(false)
+135 -153
View File
@@ -67,16 +67,7 @@ func AddMythicService(service string, removeVolume bool) {
} else {
delete(pStruct, "ports")
pStruct["network_mode"] = "host"
pStruct["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
}
pStruct["extra_hosts"] = getExtraHosts()
if mythicEnv.GetBool("postgres_bind_localhost_only") {
pStruct["command"] = "postgres -c \"max_connections=100\" -p ${POSTGRES_PORT} -c config_file=/etc/postgresql.conf -c \"listen_addresses=localhost\""
} else {
@@ -146,16 +137,7 @@ func AddMythicService(service string, removeVolume bool) {
} else {
delete(pStruct, "ports")
pStruct["network_mode"] = "host"
pStruct["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
}
pStruct["extra_hosts"] = getExtraHosts()
if mythicEnv.GetBool("documentation_bind_localhost_only") {
pStruct["environment"] = []string{
"DOCUMENTATION_PORT=${DOCUMENTATION_PORT}",
@@ -185,13 +167,21 @@ func AddMythicService(service string, removeVolume bool) {
}
}
case "mythic_graphql":
pStruct["depends_on"] = map[string]map[string]string{
"mythic_postgres": {
dependsOn := map[string]map[string]string{}
if isServiceInternal("mythic_server") {
dependsOn["mythic_server"] = map[string]string{
"condition": "service_healthy",
},
"mythic_server": {
}
}
if isServiceInternal("mythic_postgres") {
dependsOn["mythic_postgres"] = map[string]string{
"condition": "service_healthy",
},
}
}
if len(dependsOn) > 0 {
pStruct["depends_on"] = dependsOn
} else {
delete(pStruct, "depends_on")
}
if mythicEnv.GetBool("hasura_use_build_context") {
pStruct["build"] = map[string]interface{}{
@@ -208,8 +198,8 @@ func AddMythicService(service string, removeVolume bool) {
pStruct["mem_limit"] = mythicEnv.GetString("hasura_mem_limit")
}
environment := []string{
"HASURA_GRAPHQL_DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}",
"HASURA_GRAPHQL_METADATA_DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}",
"HASURA_GRAPHQL_DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=${POSTGRES_SSLMODE:-disable}",
"HASURA_GRAPHQL_METADATA_DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=${POSTGRES_SSLMODE:-disable}",
"HASURA_GRAPHQL_ENABLE_CONSOLE=true",
"HASURA_GRAPHQL_DEV_MODE=false",
"HASURA_GRAPHQL_ADMIN_SECRET=${HASURA_SECRET}",
@@ -239,16 +229,7 @@ func AddMythicService(service string, removeVolume bool) {
} else {
delete(pStruct, "ports")
pStruct["network_mode"] = "host"
pStruct["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
}
pStruct["extra_hosts"] = getExtraHosts()
if mythicEnv.GetBool("hasura_bind_localhost_only") {
environment = append(environment, "HASURA_GRAPHQL_SERVER_HOST=127.0.0.1")
} else {
@@ -264,22 +245,36 @@ func AddMythicService(service string, removeVolume bool) {
delete(pStruct, "volumes")
}
case "mythic_nginx":
pStruct["depends_on"] = map[string]map[string]string{
"mythic_server": {
dependsOn := map[string]map[string]string{}
if isServiceInternal("mythic_server") {
dependsOn["mythic_server"] = map[string]string{
"condition": "service_healthy",
},
"mythic_react": {
}
}
if isServiceInternal("mythic_react") {
dependsOn["mythic_react"] = map[string]string{
"condition": "service_started",
},
"mythic_jupyter": {
}
}
if isServiceInternal("mythic_jupyter") {
dependsOn["mythic_jupyter"] = map[string]string{
"condition": "service_healthy",
},
"mythic_documentation": {
}
}
if isServiceInternal("mythic_documentation") {
dependsOn["mythic_documentation"] = map[string]string{
"condition": "service_started",
},
"mythic_graphql": {
}
}
if isServiceInternal("mythic_graphql") {
dependsOn["mythic_graphql"] = map[string]string{
"condition": "service_healthy",
},
}
}
if len(dependsOn) > 0 {
pStruct["depends_on"] = dependsOn
} else {
delete(pStruct, "depends_on")
}
if mythicEnv.GetBool("nginx_use_build_context") {
pStruct["build"] = map[string]interface{}{
@@ -348,16 +343,7 @@ func AddMythicService(service string, removeVolume bool) {
} else {
delete(pStruct, "ports")
pStruct["network_mode"] = "host"
pStruct["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
}
pStruct["extra_hosts"] = getExtraHosts()
if mythicEnv.GetBool("nginx_bind_localhost_only") {
finalNginxEnv = append(finalNginxEnv, "NGINX_BIND_IPV4=127.0.0.1", "NGINX_BIND_IPV6=[::1]")
} else {
@@ -434,16 +420,7 @@ func AddMythicService(service string, removeVolume bool) {
} else {
delete(pStruct, "ports")
pStruct["network_mode"] = "host"
pStruct["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
}
pStruct["extra_hosts"] = getExtraHosts()
if mythicEnv.GetBool("rabbitmq_bind_localhost_only") {
environment = append(environment, "RABBITMQ_NODE_IP_ADDRESS=127.0.0.1", "RABBITMQ_NODE_PORT=${RABBITMQ_PORT}")
} else {
@@ -469,16 +446,26 @@ func AddMythicService(service string, removeVolume bool) {
}
}
case "mythic_react":
pStruct["depends_on"] = map[string]map[string]string{
"mythic_server": {
dependsOn := map[string]map[string]string{}
if isServiceInternal("mythic_server") {
dependsOn["mythic_server"] = map[string]string{
"condition": "service_healthy",
},
"mythic_graphql": {
}
}
if isServiceInternal("mythic_graphql") {
dependsOn["mythic_graphql"] = map[string]string{
"condition": "service_healthy",
},
"mythic_postgres": {
}
}
if isServiceInternal("mythic_postgres") {
dependsOn["mythic_postgres"] = map[string]string{
"condition": "service_healthy",
},
}
}
if len(dependsOn) > 0 {
pStruct["depends_on"] = dependsOn
} else {
delete(pStruct, "depends_on")
}
if mythicEnv.GetBool("mythic_react_debug") {
pStruct["build"] = map[string]interface{}{
@@ -550,16 +537,7 @@ func AddMythicService(service string, removeVolume bool) {
} else {
delete(pStruct, "ports")
pStruct["network_mode"] = "host"
pStruct["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
}
pStruct["extra_hosts"] = getExtraHosts()
if mythicEnv.GetBool("mythic_react_bind_localhost_only") {
pStruct["environment"] = []string{
"MYTHIC_REACT_PORT=${MYTHIC_REACT_PORT}",
@@ -574,16 +552,26 @@ func AddMythicService(service string, removeVolume bool) {
}
case "mythic_jupyter":
pStruct["depends_on"] = map[string]map[string]string{
"mythic_server": {
dependsOn := map[string]map[string]string{}
if isServiceInternal("mythic_server") {
dependsOn["mythic_server"] = map[string]string{
"condition": "service_healthy",
},
"mythic_postgres": {
}
}
if isServiceInternal("mythic_graphql") {
dependsOn["mythic_graphql"] = map[string]string{
"condition": "service_healthy",
},
"mythic_graphql": {
}
}
if isServiceInternal("mythic_postgres") {
dependsOn["mythic_postgres"] = map[string]string{
"condition": "service_healthy",
},
}
}
if len(dependsOn) > 0 {
pStruct["depends_on"] = dependsOn
} else {
delete(pStruct, "depends_on")
}
if mythicEnv.GetBool("jupyter_use_build_context") {
pStruct["build"] = map[string]interface{}{
@@ -620,16 +608,7 @@ func AddMythicService(service string, removeVolume bool) {
} else {
delete(pStruct, "ports")
pStruct["network_mode"] = "host"
pStruct["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
}
pStruct["extra_hosts"] = getExtraHosts()
environment := []string{
"JUPYTER_TOKEN=${JUPYTER_TOKEN}",
"CHOWN_EXTRA=/projects",
@@ -665,13 +644,21 @@ func AddMythicService(service string, removeVolume bool) {
}
}
case "mythic_server":
pStruct["depends_on"] = map[string]map[string]string{
"mythic_postgres": {
dependsOn := map[string]map[string]string{}
if isServiceInternal("mythic_rabbitmq") {
dependsOn["mythic_rabbitmq"] = map[string]string{
"condition": "service_healthy",
},
"mythic_rabbitmq": {
}
}
if isServiceInternal("mythic_postgres") {
dependsOn["mythic_postgres"] = map[string]string{
"condition": "service_healthy",
},
}
}
if len(dependsOn) > 0 {
pStruct["depends_on"] = dependsOn
} else {
delete(pStruct, "depends_on")
}
if mythicEnv.GetBool("mythic_server_use_build_context") {
pStruct["build"] = map[string]interface{}{
@@ -710,6 +697,7 @@ func AddMythicService(service string, removeVolume bool) {
"POSTGRES_HOST=${POSTGRES_HOST}",
"POSTGRES_PORT=${POSTGRES_PORT}",
"POSTGRES_PASSWORD=${POSTGRES_PASSWORD}",
"POSTGRES_SSLMODE=${POSTGRES_SSLMODE}",
"RABBITMQ_HOST=${RABBITMQ_HOST}",
"RABBITMQ_PORT=${RABBITMQ_PORT}",
"RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}",
@@ -740,16 +728,7 @@ func AddMythicService(service string, removeVolume bool) {
} else {
delete(pStruct, "ports")
pStruct["network_mode"] = "host"
pStruct["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
}
pStruct["extra_hosts"] = getExtraHosts()
}
if _, ok := pStruct["environment"]; ok {
@@ -774,10 +753,12 @@ func AddMythicService(service string, removeVolume bool) {
}
}
case "mythic_sync":
pStruct["depends_on"] = map[string]map[string]string{
"mythic_nginx": {
"condition": "service_healthy",
},
if isServiceInternal("mythic_nginx") {
pStruct["depends_on"] = map[string]map[string]string{
"mythic_nginx": {"condition": "service_healthy"},
}
} else {
delete(pStruct, "depends_on")
}
absPath, err := filepath.Abs(filepath.Join(manager.GetManager().GetPathTo3rdPartyServicesOnDisk(), service))
if err != nil {
@@ -822,16 +803,7 @@ func AddMythicService(service string, removeVolume bool) {
delete(pStruct, "extra_hosts")
} else {
pStruct["network_mode"] = "host"
pStruct["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
}
pStruct["extra_hosts"] = getExtraHosts()
}
}
@@ -863,29 +835,25 @@ func Add3rdPartyService(service string, additionalConfigs map[string]interface{}
"args": config.GetBuildArguments(),
}
existingConfig["network_mode"] = "host"
existingConfig["extra_hosts"] = []string{
"mythic_server:127.0.0.1",
"mythic_rabbitmq:127.0.0.1",
"mythic_nginx:127.0.0.1",
"mythic_react:127.0.0.1",
"mythic_documentation:127.0.0.1",
"mythic_graphql:127.0.0.1",
"mythic_jupyter:127.0.0.1",
"mythic_postgres:127.0.0.1",
existingConfig["extra_hosts"] = getExtraHosts()
dependsOn := map[string]map[string]string{}
if isServiceInternal("mythic_server") {
dependsOn["mythic_server"] = map[string]string{"condition": "service_healthy"}
}
existingConfig["depends_on"] = map[string]map[string]string{
"mythic_server": {
"condition": "service_healthy",
},
"mythic_rabbitmq": {
"condition": "service_healthy",
},
"mythic_nginx": {
"condition": "service_healthy",
},
"mythic_graphql": {
"condition": "service_healthy",
},
if isServiceInternal("mythic_rabbitmq") {
dependsOn["mythic_rabbitmq"] = map[string]string{"condition": "service_healthy"}
}
if isServiceInternal("mythic_graphql") {
dependsOn["mythic_graphql"] = map[string]string{"condition": "service_healthy"}
}
if isServiceInternal("mythic_nginx") {
dependsOn["mythic_nginx"] = map[string]string{"condition": "service_healthy"}
}
if len(dependsOn) > 0 {
existingConfig["depends_on"] = dependsOn
} else {
delete(existingConfig, "depends_on")
}
agentConfigs := config.GetConfigStrings([]string{fmt.Sprintf("%s_.*", service)})
agentUseBuildContextKey := fmt.Sprintf("%s_use_build_context", service)
@@ -1003,3 +971,17 @@ func applyImageMirror(imageURL, mirror string) string {
}
return mirror + "/" + imageURL
}
func isServiceInternal(service string) bool {
return manager.GetManager().IsServiceInternal(service)
}
func getExtraHosts() []string {
extraHosts := []string{}
for _, service := range config.MythicPossibleServices {
if isServiceInternal(service) {
extraHosts = append(extraHosts, fmt.Sprintf("%s:127.0.0.1", service))
}
}
return extraHosts
}
+3
View File
@@ -112,6 +112,9 @@ func updateNginxBlockLists() {
outputString += "deny all;"
if !config.GetMythicEnv().GetBool("nginx_use_volume") {
ipFilePath := filepath.Join(utils.GetCwdFromExe(), "nginx-docker", "config", "blockips.conf")
if err := os.MkdirAll(filepath.Dir(ipFilePath), 0755); err != nil {
log.Fatalf("[-] Failed to create nginx-docker/config directory for block list file: %v\n", err)
}
if err := os.WriteFile(ipFilePath, []byte(outputString), 0600); err != nil {
log.Fatalf("[-] Failed to write out block list file: %v\n", err)
}
@@ -92,6 +92,18 @@ func (d *DockerComposeManager) IsServiceRunning(service string) bool {
return false
}
// IsServiceInternal checks if a service is configured to run locally in docker vs externally
func (d *DockerComposeManager) IsServiceInternal(service string) bool {
if !utils.StringInSlice(service, config.MythicPossibleServices) {
return true
}
intendedServices, err := config.GetIntendedMythicServiceNames()
if err != nil {
return true
}
return utils.StringInSlice(service, intendedServices)
}
// DoesImageExist use Docker API to check existing images for the specified name
func (d *DockerComposeManager) DoesImageExist(service string) bool {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
@@ -624,9 +636,9 @@ func (d *DockerComposeManager) TestPorts(services []string) {
var removeServices []string
mythicEnv := config.GetMythicEnv()
for key, val := range portChecks {
// only check ports for services we're about to start
// only check ports for services we're about to start that are running locally
if utils.StringInSlice(val[1], services) {
if mythicEnv.GetString(key) == val[1] || mythicEnv.GetString(key) == "127.0.0.1" {
if d.IsServiceInternal(val[1]) {
addServices = append(addServices, val[1])
p, err := net.Listen("tcp", ":"+strconv.Itoa(mythicEnv.GetInt(val[0])))
if err != nil {
@@ -1413,7 +1425,7 @@ func (d *DockerComposeManager) runDockerCompose(args []string) error {
return err
}
if processState.ExitCode() != 0 {
return err
return fmt.Errorf("docker-compose %v exited with code %d", args, processState.ExitCode())
}
}
return nil
@@ -12,6 +12,8 @@ type CLIManager interface {
GetManagerName() string
// IsServiceRunning checks if a service by the specified name is currently running or not
IsServiceRunning(service string) bool
// IsServiceInternal checks if a service is configured to run locally in docker vs externally
IsServiceInternal(service string) bool
// CheckRequiredManagerVersion checks if the version of the management software installed is a valid version or not
CheckRequiredManagerVersion() bool
// GenerateRequiredConfig creates any necessary base configuration files needed by the manager, like a docker-compose.yml file
+3 -1
View File
@@ -1,6 +1,8 @@
package cmd
import (
"log"
"github.com/MythicMeta/Mythic_CLI/cmd/config"
"github.com/MythicMeta/Mythic_CLI/cmd/internal"
"github.com/spf13/cobra"
@@ -31,6 +33,6 @@ func start(cmd *cobra.Command, args []string) {
keepVolume = !config.GetMythicEnv().GetBool("REBUILD_ON_START")
}
if err := internal.ServiceStart(args, localKeepVolume); err != nil {
log.Fatalf("[-] Failed to start Mythic: %v\n", err)
}
}
+8 -2
View File
@@ -36,6 +36,11 @@ func Initialize() {
logging.LogInfo("Disconnecting from database and reconnecting to load new schema")
DB.Close()
DB = getNewDbConnection()
if utils.MythicConfig.PostgresDebug {
if _, err := DB.Exec("CREATE EXTENSION IF NOT EXISTS pg_stat_statements SCHEMA public;"); err != nil {
logging.LogWarning("Failed to create pg_stat_statements extension (requires superuser)", "error", err.Error())
}
}
// we need to initialize the admin user and operation
salt := uuid.NewString()
newUser := databaseStructs.Operator{
@@ -161,12 +166,13 @@ func checkDBConnection() {
func getNewDbConnection() *sqlx.DB {
for {
logging.LogInfo("Attempting to connect to database...", "host", utils.MythicConfig.PostgresHost, "port", utils.MythicConfig.PostgresPort)
conn, err := sqlx.Connect("postgres", fmt.Sprintf("user='%s' password='%s' host='%s' port='%d' dbname='%s' sslmode=disable connect_timeout=10",
conn, err := sqlx.Connect("postgres", fmt.Sprintf("user='%s' password='%s' host='%s' port='%d' dbname='%s' sslmode=%s connect_timeout=10",
utils.MythicConfig.PostgresUser,
utils.MythicConfig.PostgresPassword,
utils.MythicConfig.PostgresHost,
utils.MythicConfig.PostgresPort,
utils.MythicConfig.PostgresDB),
utils.MythicConfig.PostgresDB,
utils.MythicConfig.PostgresSSLMode),
)
if err != nil {
logging.LogError(err, "Failed to connect to database", "host", utils.MythicConfig.PostgresHost, "port", utils.MythicConfig.PostgresPort)
-2
View File
@@ -4847,8 +4847,6 @@ ALTER TABLE ONLY public.wrappedpayloadtypes
ALTER TABLE ONLY public.wrappedpayloadtypes
ADD CONSTRAINT wrappedpayloadtypes_wrapper_id_fkey FOREIGN KEY (wrapper_id) REFERENCES public.payloadtype(id) ON DELETE CASCADE;
CREATE EXTENSION pg_stat_statements SCHEMA public;
--
-- PostgreSQL database dump complete
--
+6
View File
@@ -47,6 +47,8 @@ type Config struct {
PostgresDB string
PostgresUser string
PostgresPassword string
PostgresSSLMode string
PostgresDebug bool
// jwt configuration
JWTSecret []byte
@@ -78,6 +80,8 @@ func Initialize() {
mythicEnv.SetDefault("postgres_db", "mythic_db")
mythicEnv.SetDefault("postgres_user", "mythic_user")
mythicEnv.SetDefault("postgres_password", "")
mythicEnv.SetDefault("postgres_sslmode", "disable")
mythicEnv.SetDefault("postgres_debug", false)
// rabbitmq configuration
mythicEnv.SetDefault("rabbitmq_host", "mythic_rabbitmq")
mythicEnv.SetDefault("rabbitmq_port", 5672)
@@ -180,6 +184,8 @@ func setConfigFromEnv(mythicEnv *viper.Viper) {
MythicConfig.PostgresDB = mythicEnv.GetString("postgres_db")
MythicConfig.PostgresUser = mythicEnv.GetString("postgres_user")
MythicConfig.PostgresPassword = mythicEnv.GetString("postgres_password")
MythicConfig.PostgresSSLMode = mythicEnv.GetString("postgres_sslmode")
MythicConfig.PostgresDebug = mythicEnv.GetBool("postgres_debug")
// rabbitmq configuration
MythicConfig.RabbitmqHost = mythicEnv.GetString("rabbitmq_host")
MythicConfig.RabbitmqPort = mythicEnv.GetUint("rabbitmq_port")
@@ -1,17 +1,17 @@
{
"files": {
"main.css": "/new/static/css/main.262ce320.css",
"main.js": "/new/static/js/main.92ca76ae.js",
"main.js": "/new/static/js/main.6df06080.js",
"sql-wasm.wasm": "/new/sql-wasm-7f26ab750fcdafabbe18c6525a66a0bd.wasm",
"static/media/mythic-red.png": "/new/static/media/mythic-red.203468a4e5240d239aa0.png",
"static/media/graphql.png": "/new/static/media/graphql.8f15978b39b0870a9f0e.png",
"static/media/Mythic_Logo.svg": "/new/static/media/Mythic_Logo.6842c911bebe36d6f83fc7ced4a2cd99.svg",
"index.html": "/new/index.html",
"main.262ce320.css.map": "/new/static/css/main.262ce320.css.map",
"main.92ca76ae.js.map": "/new/static/js/main.92ca76ae.js.map"
"main.6df06080.js.map": "/new/static/js/main.6df06080.js.map"
},
"entrypoints": [
"static/css/main.262ce320.css",
"static/js/main.92ca76ae.js"
"static/js/main.6df06080.js"
]
}
+1 -1
View File
@@ -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.92ca76ae.js"></script><link href="/new/static/css/main.262ce320.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.6df06080.js"></script><link href="/new/static/css/main.262ce320.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
@@ -1,3 +1,3 @@
/*! For license information please see main.92ca76ae.js.LICENSE.txt */
(()=>{var e={6603(e,t,n){e=n.nmd(e),function(){var e=function(){return this}();e||"undefined"==typeof window||(e=window);var t=function(e,n,r){"string"===typeof e?(2==arguments.length&&(r=n),t.modules[e]||(t.payloads[e]=r,t.modules[e]=null)):t.original?t.original.apply(this,arguments):(console.error("dropping module because define wasn't a string."),console.trace())};t.modules={},t.payloads={};var n=function(e,t,n){if("string"===typeof t){var i=o(e,t);if(void 0!=i)return n&&n(),i}else if("[object Array]"===Object.prototype.toString.call(t)){for(var a=[],s=0,l=t.length;s<l;++s){var c=o(e,t[s]);if(void 0==c&&r.original)return;a.push(c)}return n&&n.apply(null,a)||!0}},r=function(e,t){var i=n("",e,t);return void 0==i&&r.original?r.original.apply(this,arguments):i},i=function(e,t){if(-1!==t.indexOf("!")){var n=t.split("!");return i(e,n[0])+"!"+i(e,n[1])}if("."==t.charAt(0))for(t=e.split("/").slice(0,-1).join("/")+"/"+t;-1!==t.indexOf(".")&&r!=t;){var r=t;t=t.replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}return t},o=function(e,r){r=i(e,r);var o=t.modules[r];if(!o){if("function"===typeof(o=t.payloads[r])){var a={},s={id:r,uri:"",exports:a,packaged:!0};a=o((function(e,t){return n(r,e,t)}),a,s)||s.exports,t.modules[r]=a,delete t.payloads[r]}o=t.modules[r]=a||o}return o};!function(n){var i=e;n&&(e[n]||(e[n]={}),i=e[n]),i.define&&i.define.packaged||(t.original=i.define,i.define=t,i.define.packaged=!0),i.require&&i.require.packaged||(r.original=i.require,i.require=r,i.require.packaged=!0)}("ace")}(),ace.define("ace/lib/es6-shim",["require","exports","module"],(function(e,t,n){function r(e,t,n){Object.defineProperty(e,t,{value:n,enumerable:!1,writable:!0,configurable:!0})}String.prototype.startsWith||r(String.prototype,"startsWith",(function(e,t){return t=t||0,this.lastIndexOf(e,t)===t})),String.prototype.endsWith||r(String.prototype,"endsWith",(function(e,t){var n=this;(void 0===t||t>n.length)&&(t=n.length),t-=e.length;var r=n.indexOf(e,t);return-1!==r&&r===t})),String.prototype.repeat||r(String.prototype,"repeat",(function(e){for(var t="",n=this;e>0;)1&e&&(t+=n),(e>>=1)&&(n+=n);return t})),String.prototype.includes||r(String.prototype,"includes",(function(e,t){return-1!=this.indexOf(e,t)})),Object.assign||(Object.assign=function(e){if(void 0===e||null===e)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(e),n=1;n<arguments.length;n++){var r=arguments[n];void 0!==r&&null!==r&&Object.keys(r).forEach((function(e){t[e]=r[e]}))}return t}),Object.values||(Object.values=function(e){return Object.keys(e).map((function(t){return e[t]}))}),Array.prototype.find||r(Array.prototype,"find",(function(e){for(var t=this.length,n=arguments[1],r=0;r<t;r++){var i=this[r];if(e.call(n,i,r,this))return i}})),Array.prototype.findIndex||r(Array.prototype,"findIndex",(function(e){for(var t=this.length,n=arguments[1],r=0;r<t;r++){var i=this[r];if(e.call(n,i,r,this))return r}})),Array.prototype.includes||r(Array.prototype,"includes",(function(e,t){return-1!=this.indexOf(e,t)})),Array.prototype.fill||r(Array.prototype,"fill",(function(e){for(var t=this,n=t.length>>>0,r=arguments[1]|0,i=r<0?Math.max(n+r,0):Math.min(r,n),o=arguments[2],a=void 0===o?n:o|0,s=a<0?Math.max(n+a,0):Math.min(a,n);i<s;)t[i]=e,i++;return t})),Array.of||r(Array,"of",(function(){return Array.prototype.slice.call(arguments)}))})),ace.define("ace/lib/fixoldbrowsers",["require","exports","module","ace/lib/es6-shim"],(function(e,t,n){"use strict";e("./es6-shim")})),ace.define("ace/lib/deep_copy",["require","exports","module"],(function(e,t,n){t.deepCopy=function e(t){if("object"!==typeof t||!t)return t;var n;if(Array.isArray(t)){n=[];for(var r=0;r<t.length;r++)n[r]=e(t[r]);return n}if("[object Object]"!==Object.prototype.toString.call(t))return t;for(var r in n={},t)n[r]=e(t[r]);return n}})),ace.define("ace/lib/lang",["require","exports","module","ace/lib/deep_copy"],(function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){for(var n="";t>0;)1&t&&(n+=e),(t>>=1)&&(e+=e);return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){for(var t=[],n=0,r=e.length;n<r;n++)e[n]&&"object"==typeof e[n]?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=e("./deep_copy").deepCopy,t.arrayToMap=function(e){for(var t={},n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return(""+e).replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return eLine truncated
//# sourceMappingURL=main.92ca76ae.js.map
/*! For license information please see main.6df06080.js.LICENSE.txt */
(()=>{var e={6603(e,t,n){e=n.nmd(e),function(){var e=function(){return this}();e||"undefined"==typeof window||(e=window);var t=function(e,n,r){"string"===typeof e?(2==arguments.length&&(r=n),t.modules[e]||(t.payloads[e]=r,t.modules[e]=null)):t.original?t.original.apply(this,arguments):(console.error("dropping module because define wasn't a string."),console.trace())};t.modules={},t.payloads={};var n=function(e,t,n){if("string"===typeof t){var i=o(e,t);if(void 0!=i)return n&&n(),i}else if("[object Array]"===Object.prototype.toString.call(t)){for(var a=[],s=0,l=t.length;s<l;++s){var c=o(e,t[s]);if(void 0==c&&r.original)return;a.push(c)}return n&&n.apply(null,a)||!0}},r=function(e,t){var i=n("",e,t);return void 0==i&&r.original?r.original.apply(this,arguments):i},i=function(e,t){if(-1!==t.indexOf("!")){var n=t.split("!");return i(e,n[0])+"!"+i(e,n[1])}if("."==t.charAt(0))for(t=e.split("/").slice(0,-1).join("/")+"/"+t;-1!==t.indexOf(".")&&r!=t;){var r=t;t=t.replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}return t},o=function(e,r){r=i(e,r);var o=t.modules[r];if(!o){if("function"===typeof(o=t.payloads[r])){var a={},s={id:r,uri:"",exports:a,packaged:!0};a=o((function(e,t){return n(r,e,t)}),a,s)||s.exports,t.modules[r]=a,delete t.payloads[r]}o=t.modules[r]=a||o}return o};!function(n){var i=e;n&&(e[n]||(e[n]={}),i=e[n]),i.define&&i.define.packaged||(t.original=i.define,i.define=t,i.define.packaged=!0),i.require&&i.require.packaged||(r.original=i.require,i.require=r,i.require.packaged=!0)}("ace")}(),ace.define("ace/lib/es6-shim",["require","exports","module"],(function(e,t,n){function r(e,t,n){Object.defineProperty(e,t,{value:n,enumerable:!1,writable:!0,configurable:!0})}String.prototype.startsWith||r(String.prototype,"startsWith",(function(e,t){return t=t||0,this.lastIndexOf(e,t)===t})),String.prototype.endsWith||r(String.prototype,"endsWith",(function(e,t){var n=this;(void 0===t||t>n.length)&&(t=n.length),t-=e.length;var r=n.indexOf(e,t);return-1!==r&&r===t})),String.prototype.repeat||r(String.prototype,"repeat",(function(e){for(var t="",n=this;e>0;)1&e&&(t+=n),(e>>=1)&&(n+=n);return t})),String.prototype.includes||r(String.prototype,"includes",(function(e,t){return-1!=this.indexOf(e,t)})),Object.assign||(Object.assign=function(e){if(void 0===e||null===e)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(e),n=1;n<arguments.length;n++){var r=arguments[n];void 0!==r&&null!==r&&Object.keys(r).forEach((function(e){t[e]=r[e]}))}return t}),Object.values||(Object.values=function(e){return Object.keys(e).map((function(t){return e[t]}))}),Array.prototype.find||r(Array.prototype,"find",(function(e){for(var t=this.length,n=arguments[1],r=0;r<t;r++){var i=this[r];if(e.call(n,i,r,this))return i}})),Array.prototype.findIndex||r(Array.prototype,"findIndex",(function(e){for(var t=this.length,n=arguments[1],r=0;r<t;r++){var i=this[r];if(e.call(n,i,r,this))return r}})),Array.prototype.includes||r(Array.prototype,"includes",(function(e,t){return-1!=this.indexOf(e,t)})),Array.prototype.fill||r(Array.prototype,"fill",(function(e){for(var t=this,n=t.length>>>0,r=arguments[1]|0,i=r<0?Math.max(n+r,0):Math.min(r,n),o=arguments[2],a=void 0===o?n:o|0,s=a<0?Math.max(n+a,0):Math.min(a,n);i<s;)t[i]=e,i++;return t})),Array.of||r(Array,"of",(function(){return Array.prototype.slice.call(arguments)}))})),ace.define("ace/lib/fixoldbrowsers",["require","exports","module","ace/lib/es6-shim"],(function(e,t,n){"use strict";e("./es6-shim")})),ace.define("ace/lib/deep_copy",["require","exports","module"],(function(e,t,n){t.deepCopy=function e(t){if("object"!==typeof t||!t)return t;var n;if(Array.isArray(t)){n=[];for(var r=0;r<t.length;r++)n[r]=e(t[r]);return n}if("[object Object]"!==Object.prototype.toString.call(t))return t;for(var r in n={},t)n[r]=e(t[r]);return n}})),ace.define("ace/lib/lang",["require","exports","module","ace/lib/deep_copy"],(function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){for(var n="";t>0;)1&t&&(n+=e),(t>>=1)&&(e+=e);return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){for(var t=[],n=0,r=e.length;n<r;n++)e[n]&&"object"==typeof e[n]?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=e("./deep_copy").deepCopy,t.arrayToMap=function(e){for(var t={},n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return(""+e).replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return eLine truncated
//# sourceMappingURL=main.6df06080.js.map
@@ -1 +1 @@
{"version":3,"file":"static/js/main.92ca76ae.js","mappings":"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 truncated
{"version":3,"file":"static/js/main.6df06080.js","mappings":"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 truncated