├── .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 | --------------------------------------------------------------------------------