This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification."
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE64-1434
Target Operating System: 64 bit Linux (x86_64 GNU/Linux)
GitHub Link: https://github.com/rtaylor777/nasm/blob/master/Encrypt1434.zip
https://pypi.python.org/pypi/pycrypto
The encryption used is AES and the mode used is AES.MODE_CBC. The password is hashed using SHA256.
Download the Encrypt1434.zip file:
wget https://github.com/rtaylor777/nasm/raw/master/Encrypt1434.zip
Unzip the file:
Generate some shellcode and update the Encrypt1434.py script with it by running Config against an object file (or manually editing Encrypt1434.py its your choice).
Execute the Encrypt1434.py script along with your desired password as a command line argument:
Besides outputting the encrypted shellcode to the display the Encrypt1434.py script updated the Decrypt1434.py script with this encrypted payload. All that is left is to is to run Decrypt1434.py with the correct password as an argument:
Running the Decrypt1434.py script not only decrypted the payload but it loaded it into memory and executed it.
If you fail to provide the correct password to the Decrypt1434.py script it will probably have a segmentation fault error. There is no guarantee however that harmful code will not be extracted and run, though it is highly unlikely that anything useful will be produced without the correct password.
The first part of the script uses objdump to pull the bytecode out of an object file and formats it into a line that can be used to replace the existing "shellcode=" line in the Encrypt1434.py script. Then sed is used to do an in place edit and replace the line if the Encrypt1434.py script is found in the current directory.
I created a function that will parse through a string of bytecode and look for nulls. If any are found the function returns the number 1, otherwise it returns 0. This function is used to ensure that the IV (initialization vector), the extended shellcode, and the encrypted shellcode have no nulls.
Since I mentioned the extended shellcode above I guess it would be prudent to discuss that next. The encryption function expects that the shellcode (the message) will be evenly divisible by 16. In order to accommodate that, the shellcode has enough random bytes appended to it to meet that criteria. The code tests to ensure that a null byte is not appended to the shellcode.
An initialization vector (IV) is used in encryption to ensure that the same password (key) together with the same message does not produce the same ciphertext. The IV should be a random string of bytes and is usually prepended onto the encrypted message so that it is available for the decryption process. The same IV would be required during decryption as was used for encryption.
Deriving a cryptographic key from a password is usually accomplished by hashing the password, often together with salt, if we were storing the password hash somewhere such as a database.
We are not storing the password somewhere, however, we are simply using it to encrypt our shellcode. So the time to crack the encryption depends on the time to generate the key from a "test password" plus the time to attempt to decrypt the shellcode. Without rewriting the code of the Decrypt1434.py, the only way to know if you successfully decrypted the shellcode is if it successfully loads into memory and executes.
I added the value of "i" as a string into the loop to simulate the effect of a salt. As long as a preexisting database of hashed passwords does not exist the hashing time required is still part of the equation. It is unlikely that anyone produced a database of hashes from this function.
You can see some discussion about key derivation functions here:
The encrypt function is pretty basic. If you visited the python crypto site I linked to earlier it is almost verbatim: https://pypi.python.org/pypi/pycrypto
The main difference is the handling of the IV by prepending it to the ciphertext.
If you are not familiar with this fileinput library you will find this a bit odd. The standard out has been mapped to the file so the "print line" is actually writing to the file not the display. See: https://docs.python.org/2/library/fileinput.html
The comma after the "print line" is required because the new line character read from the file is still part of the line, so we don't need print outputting another new line. I could have probably just used my custom function prnt in this case.
The rest of the file should be pretty obvious so I will leave off discussing it.
from ctypes import CDLL, c_char_p, c_void_p, memmove, cast, CFUNCTYPE
libc = CDLL('libc.so.6')
https://docs.python.org/3/library/ctypes.html
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE64-1434
Target Operating System: 64 bit Linux (x86_64 GNU/Linux)
Assignment 7:
Create a custom crypter like the one shown in the "crypters" video. You can use any encryption algorithm. You can use any programming language. But demo the encryption and decryption end to end.GitHub Link: https://github.com/rtaylor777/nasm/blob/master/Encrypt1434.zip
Intro
For this assignment I decided to use the Python Cryptography Toolkit (pycrypto):https://pypi.python.org/pypi/pycrypto
The encryption used is AES and the mode used is AES.MODE_CBC. The password is hashed using SHA256.
Quickstart
Create a directory to extract the files into:Download the Encrypt1434.zip file:
wget https://github.com/rtaylor777/nasm/raw/master/Encrypt1434.zip
Unzip the file:
Generate some shellcode and update the Encrypt1434.py script with it by running Config against an object file (or manually editing Encrypt1434.py its your choice).
Execute the Encrypt1434.py script along with your desired password as a command line argument:
Besides outputting the encrypted shellcode to the display the Encrypt1434.py script updated the Decrypt1434.py script with this encrypted payload. All that is left is to is to run Decrypt1434.py with the correct password as an argument:
Running the Decrypt1434.py script not only decrypted the payload but it loaded it into memory and executed it.
If you fail to provide the correct password to the Decrypt1434.py script it will probably have a segmentation fault error. There is no guarantee however that harmful code will not be extracted and run, though it is highly unlikely that anything useful will be produced without the correct password.
Config
The first part of the script uses objdump to pull the bytecode out of an object file and formats it into a line that can be used to replace the existing "shellcode=" line in the Encrypt1434.py script. Then sed is used to do an in place edit and replace the line if the Encrypt1434.py script is found in the current directory.
Encrypt1434.py
If you know python the script should be fairly easy to understand. I will discuss sections of the code that I feel may need some clarification.I created a function that will parse through a string of bytecode and look for nulls. If any are found the function returns the number 1, otherwise it returns 0. This function is used to ensure that the IV (initialization vector), the extended shellcode, and the encrypted shellcode have no nulls.
Since I mentioned the extended shellcode above I guess it would be prudent to discuss that next. The encryption function expects that the shellcode (the message) will be evenly divisible by 16. In order to accommodate that, the shellcode has enough random bytes appended to it to meet that criteria. The code tests to ensure that a null byte is not appended to the shellcode.
An initialization vector (IV) is used in encryption to ensure that the same password (key) together with the same message does not produce the same ciphertext. The IV should be a random string of bytes and is usually prepended onto the encrypted message so that it is available for the decryption process. The same IV would be required during decryption as was used for encryption.
Deriving a cryptographic key from a password is usually accomplished by hashing the password, often together with salt, if we were storing the password hash somewhere such as a database.
We are not storing the password somewhere, however, we are simply using it to encrypt our shellcode. So the time to crack the encryption depends on the time to generate the key from a "test password" plus the time to attempt to decrypt the shellcode. Without rewriting the code of the Decrypt1434.py, the only way to know if you successfully decrypted the shellcode is if it successfully loads into memory and executes.
I added the value of "i" as a string into the loop to simulate the effect of a salt. As long as a preexisting database of hashed passwords does not exist the hashing time required is still part of the equation. It is unlikely that anyone produced a database of hashes from this function.
You can see some discussion about key derivation functions here:
The encrypt function is pretty basic. If you visited the python crypto site I linked to earlier it is almost verbatim: https://pypi.python.org/pypi/pycrypto
The main difference is the handling of the IV by prepending it to the ciphertext.
If you are not familiar with this fileinput library you will find this a bit odd. The standard out has been mapped to the file so the "print line" is actually writing to the file not the display. See: https://docs.python.org/2/library/fileinput.html
The comma after the "print line" is required because the new line character read from the file is still part of the line, so we don't need print outputting another new line. I could have probably just used my custom function prnt in this case.
The rest of the file should be pretty obvious so I will leave off discussing it.
Decrypt1434.py
The only thing that may be new for you once you have understood the code that I explained for the Encrypt1434.py is the execute() function. Here we are using some CTYPEsfrom ctypes import CDLL, c_char_p, c_void_p, memmove, cast, CFUNCTYPE
libc = CDLL('libc.so.6')
https://docs.python.org/3/library/ctypes.html
- We are defining "code" to be a c type pointer to a character string which points to the bytes in our "my_deciphered" string.
- We put the size of our shellcode into the "size" variable.
- Then we allocate some memory for our shellcode.
- We move our shellcode into that memory.
- We set the memory protection to read 1, write 2 and execute 4 (PROT_READ, PROT_WRITE, PROT_EXEC) which by bitwise combination results in 7.
- We cast the address pointed to to be a c type function that requires no input.
- Then we run() this function.
Summary
The Encrypt1434.zip project is composed of 3 scripts. The Config script is used to generate shellcode text and update the Encrypt1434.py script with it. The Encrypt1434.py script accepts a password on the command line and encrypts the shellcode. The Encrypt1434.py script not only outputs the encrypted shellcode to the screen but updates the Decrypt1434.py script with it as it's payload. The Decrypt1434.py script accepts the password on the command line and decrypts the payload and loads it into memory and executes it.
If you wish to learn more about assembly language, I highly recommend
the "SecurityTube Linux Assembly Expert course and certification."
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Comments
Post a Comment