in reversing/nomoreseacrypts/src/main.cpp [24:163]
int main()
{
/*
Exit if username is not the same as target user.
CTFuser will need to patch this check to execute the rest of the sample.
*/
#ifndef DEBUG_MODE
if (get_current_username() != TARGET_USER)
{
return 0;
}
#endif
/*
Attempt to find TARGET_FILE. Quit if not found.
CTFuser will learn which file contains the encrypted flag.
*/
string file_to_encrypt = get_home_directory();
if (!ends_with(file_to_encrypt, "/"))
{
file_to_encrypt += "/";
}
file_to_encrypt += TARGET_FILE;
ifstream sr_file(file_to_encrypt, ios::in | ios::binary);
if (!sr_file.is_open())
{
#ifdef DEBUG_MODE
cout << "Could not open " << TARGET_FILE << endl;
#endif
return 0;
}
/*
Get size of target file. Continue only if:
TARGET_FIRST_LINE.length() < filesize < TARGET_MAX_FILESIZE
This helps CTFuser get an idea about the size of the original unencrypted file.
*/
sr_file.seekg(0, ios::end);
streampos sr_filesize = sr_file.tellg();
if (sr_filesize >= TARGET_MAX_FILESIZE || sr_filesize <= TARGET_FIRST_LINE.length())
{
#ifdef DEBUG_MODE
cout << "File size is too small or too big for " << TARGET_FILE << endl;
#endif
return 0;
}
/*
Continue only if TARGET_FILE begins with TARGET_FIRST_LINE
Presence of TARGET_FIRST_LINE at the beginning of the file informs the CTFuser
that they've arrived at the correct key while bruteforcing decryption keys.
*/
sr_file.seekg(0, ios::beg);
char *buf_first_line = new char[TARGET_FIRST_LINE.length()];
sr_file.read(&buf_first_line[0], TARGET_FIRST_LINE.length());
if (strcmp(TARGET_FIRST_LINE.c_str(), buf_first_line) != 0)
{
delete buf_first_line;
sr_file.close();
return 0;
}
delete buf_first_line;
/*
Read the entire file into memory.
Generate "random" encryption key with current time as seed to srand().
This is where the bulk of the difficulty lies for this challenge.
CTFuser needs to realize that encryption can be broken due to insecure key generation.
*/
sr_file.seekg(0, ios::beg);
unsigned char *buf_file_contents = new unsigned char[sr_filesize];
sr_file.read((char*)&buf_file_contents[0], sr_filesize);
sr_file.close();
// Insecure key generation
int current_unixtime = time(NULL);
srand(current_unixtime);
string crypt_key = random_string(32);
uint8_t sbox[256];
struct AES_ctx ctx;
/*
Encrypt file using "random" key using AES256 in CTR mode.
CTFuser needs to realize that CTR mode is being used.
*/
initialize_aes_sbox(sbox);
AES_init_ctx_iv(&ctx, (unsigned char*) crypt_key.c_str(), iv, sbox);
AES_CTR_xcrypt_buffer(&ctx, buf_file_contents, sr_filesize, sbox);
// Sleep for a few seconds to simulate more work
sleep(SECONDS_TO_SLEEP);
#ifdef DEBUG_MODE
cout << "srand seed: " << current_unixtime << endl;
cout << "Encryption Key: " << crypt_key << endl;
hexdump("Encrypted Data:", buf_file_contents, sr_filesize);
#endif
/*
Dump encrypted file into ENCRYPTED_FILENAME within PWD.
Delete the original file.
This bit isn't necessary except to show that the sample
is a targeted ransomware.
*/
char cwd[PATH_MAX];
if (!getcwd(cwd, sizeof(cwd)))
{
#ifdef DEBUG_MODE
cout << "Could not get CWD" << endl;
#endif
delete buf_file_contents;
return 0;
}
string enc_filepath(cwd);
enc_filepath += "/" + ENCRYPTED_FILENAME;
ofstream sr_enc_file(enc_filepath, ios::out | ios::binary);
if (!sr_enc_file.is_open())
{
delete buf_file_contents;
return 0;
}
sr_enc_file.write((const char*)buf_file_contents, sr_filesize);
sr_enc_file.close();
// Delete original unencrypted file
remove(file_to_encrypt.c_str());
#ifdef DEBUG_MODE
// Confirm decryption works for encrypted file
// Counter needs to be set back to 0x01 for decryption.
uint8_t sbox2[256];
struct AES_ctx ctx2;
initialize_aes_sbox(sbox2);
AES_init_ctx_iv(&ctx2, (unsigned char*) crypt_key.c_str(), iv, sbox2);
AES_CTR_xcrypt_buffer(&ctx2, buf_file_contents, sr_filesize, sbox2);
hexdump("Decrypted Data:", buf_file_contents, sr_filesize);
cout << buf_file_contents << endl;
#endif
/*
Display fake error message to CTFuser.
*/
delete buf_file_contents;
cout << "Segmentation fault (core dumped)" << endl;
return 0;
}