From eadb076f0b88a3109418d3837b066f236b2b9ac2 Mon Sep 17 00:00:00 2001 From: its-a-feature Date: Tue, 30 Jan 2024 15:43:39 -0800 Subject: [PATCH] updating mythic-cli for handling non-tty install --- Mythic_CLI/src/cmd/addDockerCompose.go | 2 +- Mythic_CLI/src/cmd/config/vars.go | 2 +- Mythic_CLI/src/cmd/databaseBackup.go | 23 ++++++ Mythic_CLI/src/cmd/internal/installservice.go | 6 +- Mythic_CLI/src/cmd/internal/reset.go | 8 +++ .../src/cmd/internal/serviceExecution.go | 6 +- .../src/cmd/internal/serviceMetadata.go | 11 +-- .../src/cmd/manager/dockerComposeManager.go | 72 ++++++++++++++++++- .../src/cmd/manager/managerInterface.go | 4 ++ jupyter-docker/.docker/Dockerfile | 1 + 10 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 Mythic_CLI/src/cmd/databaseBackup.go diff --git a/Mythic_CLI/src/cmd/addDockerCompose.go b/Mythic_CLI/src/cmd/addDockerCompose.go index 72c8615d4..73b226c33 100644 --- a/Mythic_CLI/src/cmd/addDockerCompose.go +++ b/Mythic_CLI/src/cmd/addDockerCompose.go @@ -26,7 +26,7 @@ func addDockerCompose(cmd *cobra.Command, args []string) { internal.AddMythicService(args[0]) return } - err := internal.Add3rdPartyService(args[0], make(map[string]interface{})) + err := internal.Add3rdPartyService(args[0], make(map[string]interface{}), true) if err != nil { log.Printf("[-] Failed to add service") } diff --git a/Mythic_CLI/src/cmd/config/vars.go b/Mythic_CLI/src/cmd/config/vars.go index c0b9aa447..f8ca07b45 100644 --- a/Mythic_CLI/src/cmd/config/vars.go +++ b/Mythic_CLI/src/cmd/config/vars.go @@ -4,5 +4,5 @@ package config var ( // Version Mythic CLI version - Version = "v0.2.8" + Version = "v0.2.9" ) diff --git a/Mythic_CLI/src/cmd/databaseBackup.go b/Mythic_CLI/src/cmd/databaseBackup.go new file mode 100644 index 000000000..f9b29bde1 --- /dev/null +++ b/Mythic_CLI/src/cmd/databaseBackup.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "github.com/MythicMeta/Mythic_CLI/cmd/internal" + "github.com/spf13/cobra" +) + +// configCmd represents the config command +var databaseBackupCmd = &cobra.Command{ + Use: "backup {path}", + Short: "backup the database", + Long: `Run this command to stop mythic and backup the current database (Save a copy to the specified location).`, + Run: databaseBackup, + Args: cobra.ExactArgs(1), +} + +func init() { + //databaseCmd.AddCommand(databaseBackupCmd) +} + +func databaseBackup(cmd *cobra.Command, args []string) { + internal.DatabaseBackup(args[0]) +} diff --git a/Mythic_CLI/src/cmd/internal/installservice.go b/Mythic_CLI/src/cmd/internal/installservice.go index 394a1d856..f68b4695c 100644 --- a/Mythic_CLI/src/cmd/internal/installservice.go +++ b/Mythic_CLI/src/cmd/internal/installservice.go @@ -82,14 +82,14 @@ func InstallFolder(installPath string, overWrite bool) error { } log.Printf("[*] Adding service into docker-compose\n") if installConfig.IsSet("docker-compose") { - err := Add3rdPartyService(f.Name(), installConfig.GetStringMap("docker-compose")) + err := Add3rdPartyService(f.Name(), installConfig.GetStringMap("docker-compose"), true) if err != nil { log.Printf("[-] Failed to add service to docker-compose: %v\n", err) } else if err := ServiceBuild([]string{f.Name()}); err != nil { log.Printf("[-] Failed to start service: %v\n", err) } } else { - if err := Add3rdPartyService(f.Name(), make(map[string]interface{})); err != nil { + if err := Add3rdPartyService(f.Name(), make(map[string]interface{}), true); err != nil { log.Printf("[-] Failed to add service to docker-compose: %v\n", err) } else if err := ServiceBuild([]string{f.Name()}); err != nil { log.Printf("[-] Failed to start service: %v\n", err) @@ -144,7 +144,7 @@ func InstallFolder(installPath string, overWrite bool) error { } // now add payload type to yaml installConfig log.Printf("[*] Adding c2, %s, into docker-compose\n", f.Name()) - if err = Add3rdPartyService(f.Name(), make(map[string]interface{})); err != nil { + if err = Add3rdPartyService(f.Name(), make(map[string]interface{}), true); err != nil { log.Printf("[-] Failed to add %s to docker-compose: %v\n", f.Name(), err) } else if err := ServiceBuild([]string{f.Name()}); err != nil { log.Printf("[-] Failed to start service: %v\n", err) diff --git a/Mythic_CLI/src/cmd/internal/reset.go b/Mythic_CLI/src/cmd/internal/reset.go index 2b86a515e..0753f1894 100644 --- a/Mythic_CLI/src/cmd/internal/reset.go +++ b/Mythic_CLI/src/cmd/internal/reset.go @@ -17,5 +17,13 @@ func DatabaseReset() { log.Printf("[*] Removing database files\n") } } +} +func DatabaseBackup(backupPath string) { + confirm := config.AskConfirm("Are you sure you want to backup the database? ") + if confirm { + log.Printf("[*] Stopping Mythic\n") + manager.GetManager().StopServices([]string{}, config.GetMythicEnv().GetBool("REBUILD_ON_START")) + manager.GetManager().BackupDatabase(backupPath, config.GetMythicEnv().GetBool("postgres_bind_use_volume")) + } } diff --git a/Mythic_CLI/src/cmd/internal/serviceExecution.go b/Mythic_CLI/src/cmd/internal/serviceExecution.go index 9729b4101..1275d47e7 100644 --- a/Mythic_CLI/src/cmd/internal/serviceExecution.go +++ b/Mythic_CLI/src/cmd/internal/serviceExecution.go @@ -54,7 +54,7 @@ func ServiceStart(containers []string) error { add := config.AskConfirm(fmt.Sprintf("\n%s isn't in docker-compose, but is on disk. Would you like to add it? ", val)) if add { finalContainers = append(finalContainers, val) - Add3rdPartyService(val, map[string]interface{}{}) + Add3rdPartyService(val, map[string]interface{}{}, config.GetMythicEnv().GetBool("REBUILD_ON_START")) } } else { add := config.AskConfirm(fmt.Sprintf("\n%s isn't in docker-compose and is not on disk. Would you like to install it from https://github.com/? ", val)) @@ -72,7 +72,7 @@ func ServiceStart(containers []string) error { if utils.StringInSlice(service, config.MythicPossibleServices) { AddMythicService(service) } else { - Add3rdPartyService(service, map[string]interface{}{}) + Add3rdPartyService(service, map[string]interface{}{}, config.GetMythicEnv().GetBool("REBUILD_ON_START")) } } manager.GetManager().TestPorts(finalContainers) @@ -102,7 +102,7 @@ func ServiceBuild(containers []string) error { // update the necessary docker compose entries for mythic services AddMythicService(container) } else if utils.StringInSlice(container, composeServices) { - Add3rdPartyService(container, map[string]interface{}{}) + Add3rdPartyService(container, map[string]interface{}{}, true) } } err = manager.GetManager().BuildServices(containers) diff --git a/Mythic_CLI/src/cmd/internal/serviceMetadata.go b/Mythic_CLI/src/cmd/internal/serviceMetadata.go index 93e92c069..aa23a5a4b 100644 --- a/Mythic_CLI/src/cmd/internal/serviceMetadata.go +++ b/Mythic_CLI/src/cmd/internal/serviceMetadata.go @@ -538,7 +538,7 @@ func AddMythicService(service string) { manager.GetManager().SetVolumes(volumes) _ = manager.GetManager().SetServiceConfiguration(service, pStruct) } -func Add3rdPartyService(service string, additionalConfigs map[string]interface{}) error { +func Add3rdPartyService(service string, additionalConfigs map[string]interface{}, removeVolume bool) error { existingConfig, _ := manager.GetManager().GetServiceConfiguration(service) if _, ok := existingConfig["environment"]; !ok { existingConfig["environment"] = []string{} @@ -580,9 +580,12 @@ func Add3rdPartyService(service string, additionalConfigs map[string]interface{} pStruct["volumes"] = []string{ volumeName + ":/Mythic/", } - // blow away the old volume just in case to make sure we don't carry over old data - log.Printf("[*] Removing old volume if it exists") - manager.GetManager().RemoveVolume(volumeName) + if removeVolume { + // blow away the old volume just in case to make sure we don't carry over old data + log.Printf("[*] Removing old volume, %s, if it exists", volumeName) + manager.GetManager().RemoveVolume(volumeName) + } + // add our new volume to the list of volumes if needed volumes, _ := manager.GetManager().GetVolumes() volumes[volumeName] = map[string]string{ diff --git a/Mythic_CLI/src/cmd/manager/dockerComposeManager.go b/Mythic_CLI/src/cmd/manager/dockerComposeManager.go index ad1f7dac3..1104d97b1 100644 --- a/Mythic_CLI/src/cmd/manager/dockerComposeManager.go +++ b/Mythic_CLI/src/cmd/manager/dockerComposeManager.go @@ -851,6 +851,40 @@ func (d *DockerComposeManager) ResetDatabase(useVolume bool) { } } } +func (d *DockerComposeManager) BackupDatabase(backupPath string, useVolume bool) { + /* + if !useVolume { + workingPath := utils.GetCwdFromExe() + err := utils.CopyDir(filepath.Join(workingPath, "postgres-docker", "database"), backupPath) + if err != nil { + log.Fatalf("[-] Failed to copy database files\n%v\n", err) + } else { + log.Printf("[+] Successfully copied datbase files\n") + } + } else { + d.CopyFromVolume("mythic_postgres_volume", "/var/lib/postgresql/data", backupPath) + log.Printf("[+] Successfully copied database files") + } + + */ +} +func (d *DockerComposeManager) RestoreDatabase(backupPath string, useVolume bool) { + /* + if !useVolume { + workingPath := utils.GetCwdFromExe() + err := utils.CopyDir(backupPath, filepath.Join(workingPath, "postgres-docker", "database")) + if err != nil { + log.Fatalf("[-] Failed to copy database files\n%v\n", err) + } else { + log.Printf("[+] Successfully copied datbase files\n") + } + } else { + d.CopyIntoVolume("mythic_postgres_volume", "/var/lib/postgresql/data", backupPath) + log.Printf("[+] Successfully copied database files") + } + + */ +} func (d *DockerComposeManager) PrintVolumeInformation() { ctx := context.Background() cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) @@ -942,7 +976,7 @@ func (d *DockerComposeManager) RemoveVolume(volumeName string) error { if err != nil { log.Printf(fmt.Sprintf("[!] Failed to remove container that's using the volume: %v\n", err)) } else { - log.Printf("[+] Removed container %s, which was using that container", containerName) + log.Printf("[+] Removed container %s, which was using that volume", containerName) } } } @@ -1121,9 +1155,41 @@ func (d *DockerComposeManager) runDockerCompose(args []string) error { command.Env = d.getMythicEnvList() f, err := pty.Start(command) if err != nil { - log.Fatalf("[-] Failed to run docker command: %v\n", err) + stdout, err := command.StdoutPipe() + if err != nil { + log.Fatalf("[-] Failed to get stdout pipe for running docker-compose\n") + } + stderr, err := command.StderrPipe() + if err != nil { + log.Fatalf("[-] Failed to get stderr pipe for running docker-compose\n") + } + + stdoutScanner := bufio.NewScanner(stdout) + stderrScanner := bufio.NewScanner(stderr) + go func() { + for stdoutScanner.Scan() { + fmt.Printf("%s\n", stdoutScanner.Text()) + } + }() + go func() { + for stderrScanner.Scan() { + fmt.Printf("%s\n", stderrScanner.Text()) + } + }() + err = command.Start() + if err != nil { + log.Fatalf("[-] Error trying to start docker-compose: %v\n", err) + } + err = command.Wait() + if err != nil { + fmt.Printf("[-] Error from docker-compose: %v\n", err) + fmt.Printf("[*] Docker compose command: %v\n", args) + return err + } + } else { + io.Copy(os.Stdout, f) } - io.Copy(os.Stdout, f) + return nil } func (d *DockerComposeManager) setDockerComposeDefaultsAndWrite(curConfig map[string]interface{}) error { diff --git a/Mythic_CLI/src/cmd/manager/managerInterface.go b/Mythic_CLI/src/cmd/manager/managerInterface.go index 7eb60d8e0..c505d8671 100644 --- a/Mythic_CLI/src/cmd/manager/managerInterface.go +++ b/Mythic_CLI/src/cmd/manager/managerInterface.go @@ -67,6 +67,10 @@ type CLIManager interface { PrintAllServices() // ResetDatabase deletes the current database or volume ResetDatabase(useVolume bool) + // BackupDatabase saves a copy of the database to the specified path + BackupDatabase(backupPath string, useVolume bool) + // RestoreDatabase restores a saved copy of the datababse to the specified path + RestoreDatabase(backupPath string, useVolume bool) // PrintVolumeInformation prints out all the volumes in use by Mythic PrintVolumeInformation() // RemoveVolume removes the named volume diff --git a/jupyter-docker/.docker/Dockerfile b/jupyter-docker/.docker/Dockerfile index fab7a3892..271ac657c 100644 --- a/jupyter-docker/.docker/Dockerfile +++ b/jupyter-docker/.docker/Dockerfile @@ -12,6 +12,7 @@ WORKDIR /projects #CMD start.sh jupyter lab --ServerApp.open_browser=false --IdentityProvider.token='' --ServerApp.base_url="/jupyter" --ServerApp.default_url="/jupyter" ENV JUPYTERHUB_SERVICE_PREFIX "/jupyter/" +ENV JUPYTER_TOKEN "mythic" COPY ["jupyter/", "."]