• XSS.stack #1 – первый литературный журнал от юзеров форума

Cl0p Ransomware Targets Linux Systems with Flawed Encryption | Decryptor Available

guesswhozb4ck

RAID-массив
Пользователь
Регистрация
25.11.2021
Сообщения
66
Реакции
31

ELF Technical Analysis​

The ELF Cl0p variant is developed in a similar logic to the Windows variant, though it contains small differences mostly attributed to OS differences such as API calls. It appears to be in its initial development phases as some functionalities present in the Windows versions do not currently exist in this new Linux version.

A reason for this could be that the threat actor has not needed to dedicate time and resources to improve obfuscation or evasiveness due to the fact that it is currently undetected by all 64 security engines on VirusTotal . SentinelOne Singularity detects Cl0p ransomware on both Linux and Windows devices.

SentinelOne Singularity detects Cl0p Linux ransomware



Initially, the ransomware creates a new process by calling fork and exits the parent-process. The child-process sets its file mode creation mask to any permission (read, write, execute) by calling umask(0) . It then calls setsid , creates a session and sets the process group ID. It tries to access root by changing the working directory to “/” ( chdir(“/”) ). Once the permissions are set, the ransomware proceeds encrypting other directories.

Targeted Folders & Files​

While the Windows versions contain a hashing algorithm in order to avoid encrypting specific folders and files, such functionality was not observed in the Linux variant. The ELF variant targets specific folders, subfolders and all files/types.

The discovered ELF sample targets files contained in the following directories for encryption, though we do not exclude the possibility of future versions including more directories.

FolderDescription
/optContains subdirectories for optional software packages
/u01Oracle Directory, mount point used for the Oracle software only.
/u02Oracle Directory, used for the database files.
/u03Oracle Directory, used for the database files.
/u04Oracle Directory, used for the database files.
/homeContains the home directory of each user.
/rootContains the home directory of the root user.

Encryption Flaw​

Windows versions of Cl0p ransomware use a Mersenne Twister PRNG (MT19937) to generate a 0x75 bytes size RC4 key for each file. This key is then validated (checks if the first five bytes are NULL) and used for file encryption. Then, by using the RSA public key, it encrypts the generated RC4 key and stores it to $filename.$clop_extension. Victims who pay the ransom demand receive a decryptor which decrypts the generated Cl0p file using the RSA private key, retrieves the generated RC4 key, and then decrypts the encrypted file.

This core functionality is missing in the Linux variant. Instead, we discovered a flawed ransomware-encryption logic which makes it possible to retrieve the original files without paying for a decryptor.

The Linux variant contains a hardcoded RC4 “master-key” which, during the execution of the main function, is copied into the global variable szKeyKey.

Sample’s RC4 “master-key”:

Jfkdskfku2ir32y7432uroduw8y7318i9018urewfdsZ2Oaifwuieh~~cudsffdsd

During the file encryption phase, the ransomware – similar to the Windows version – generates a 0x75 bytes size RC4 key, with the use of a lookup table and a PRNG byte. This generated RC4 key is used to encrypt the mappedAddress and write it back to the file.

Then by using the RC4 “master-key” the ransomware encrypts the generated RC4 key and stores it to $filename.$clop_extension. By using a symmetric algorithm (second RC4) to “encrypt” the file’s RC4 key, we were able to take advantage of this flaw and decrypt Cl0p-ELF encrypted files.

Cl0p-ELF encryption flaw
Cl0p-ELF encryption flaw
Cl0p-ELF Decryption Logic:

  1. Retrieve RC4 “master-key”.
  2. Read all $filename.$clop_extension.
  3. Decrypt with RC4 using the RC4 “master-key”, the generated RC4 key.
  4. Decrypt $filename with RC4 using the generated RC4 key.
  5. Write decrypted to $filename.

clop_decryptor.gif


Cl0p File-Key Creation Flaw​

The 0x75 bytes size PRNG RC4 key is encrypted with RC4 using the RC4 “master-key”. The encrypted RC4 output is 0x75 bytes size, though writes 0x100 bytes into the created Cl0p key $filename.$clop_extension. This results in writing memory data to the file and more specifically stack variables.

Cl0p-ELF file-key creation flaw.
Cl0p-ELF file-key creation flaw.
This flaw provides some information regarding the file before encryption. This includes:

  • File fstat64 result
    • total size, in bytes, file size (st_size)
    • time of last status change, exact time of file encryption (st_ctime)
    • and more forensics information regarding the file before the encryption.
  • Size of buffer for file encryption (with check of >= 0x5f5e100 )
  • RC4 “master-key” size
  • RC4 PRNG key size
struct clopelfkeyfile {
byte encr_rc4key[117]; // encrypted RC4 PRNG key, size 0x75 bytes
stat fdstat; // stat(fd, &fdstat), size 0x58 bytes
long fdid; // file node unique id, size 0x8 bytes
int fd; // file descriptor, size 0x4 bytes
int fdmappedaddr; // file mapped address, size 0x4 bytes
off_t fdsize; // file size, size 0x8 bytes
int rc4_msize; // RC4 "master-key" size, size 0x4 bytes
long rc4_fsize; // RC4 PRNG key size, size 0x8 bytes
int fdnameaddr; // filename string address, size 0x4 bytes
intframeaddr; // frame pointer address, size 0x4 bytes
int retadd; // function return address, size 0x4 bytes
byte fdpathaddr[3]; // part of filepath strings address, size 0x3 bytes
}

Developed Functions & Names​

In ELF binaries the .symtab, Symbol Table Section , holds information needed to locate and relocate a program's symbolic definitions and references, allowing us to retrieve function and global variable names.

function nameDescription
do_heartbeat(void)Main function which starts the encryption of various folders.
find(char*,char const*)Multiple calls of this function are done by do_heartbeat; this function takes as parameter 1) the starting folder to encrypt (example, “/opt”) 2) regex of files to encrypt (example, “*.*”) and performs a recursive search from the starting folder until encrypts the “matching regex files.
CreateRadMe(char *)This function takes as parameter the folder to create the ransom note.
EncrFile(char*)Encrypts given filepath.
existsFile(char*)Checks if File exists, or if the process has the permissions to open.
_rc4Full(void const*,ushort,void *,ulong)Wrapper function to _rc4Init and _rc4, which is used to encrypt a buffer with a given key.
Createkey(char *,uchar *)Creates and writes into "%s.C_I_0P" the encrypted buffer.
Global VariableDescription
szKeyKeyGlobal variable of 0x64 bytes size, initialized during main function, containing RC4 “master-key” which encrypts the “randomly” generated 0x75 bytes size RC4 key.

Differences to Windows Variant​

Rather than simply port the Windows version of Cl0p directly, the authors have chosen to build bespoke Linux payloads. We understand this to be the primary reason for the lack of feature parity between the new Linux version and the far more established Windows variant.

SentinelLabs expects future versions of the Linux variant to start eliminating those differences and for each updated functionality to be applied in both variants simultaneously.

Some of the differences worth highlighting are detailed below:

DifferencesDescription
Files/Folders exclusionsThe Windows variant contains a hashing algorithm which excludes specific folders and files from encryption. This functionality was not observed in the Linux variant.
extension exclusionsThe Windows variant contains a hardcoded list of extensions to exclude from encryption. This functionality was not observed in the Linux variant.
Different methods of Reading/Writing depending on file size.The Windows variant, depending on the size of the file, will choose different methods of reading a file and writing the encrypted buffer. Small files are ignored, medium-sized files will make use of ReadFile / WriteFile , large files will use CreateFileMappingW / MapViewOfFile / UnmapViewOfFile . The Linux variant encrypts all the files using mmap64 / munmap . Both only variants encrypt the first 0x5f5e100 bytes of large files.
ransom note decryptionThe Windows variant stores the encrypted ransom note as a resource and decrypts it with a simple XOR algorithm. The Linux variant stores the note as plain text in “.rodata”.
drive enumerationThe Windows variant initially enumerates through drives in order to “find” the starting point to recursively encrypt the folders. The Linux variant contains hardcoded “starting” folders.
RC4 Default KeyOnce the Windows variant generates a 0x75 size PRNG RC4 Key, it will check if the first 5 bytes are NULL; if so, it uses the default key for encryption. The Linux version does not perform this validation and does not contain a default RC4 key in case the first 5 bytes of the PRNG RC4 are NULL.
Command Line ParametersThe Windows variant can be executed in three ways: 1) without parameters encrypting all local and network drives, 2) with “runrun” parameter encrypting only network drives, 3) with a file as parameter which contains the folders to be encrypted (observed temp .ocx/temp.dat). The Linux variant does not accept command line parameters and recursively encrypts the specified hardcoded folders.
RC4 Key EncryptionThe Windows variant encrypts the generated RC4 key responsible for the file encryption using the asymmetric algorithm RSA and a public key. In the Linux variant, the generated RC4 key is encrypted with a RC4 “master-key” (flawed logic).

ransom notes​

The Linux variant of Clop ransomware drops a ransom note on victim machines with a .txt format.

ELF sample ransom note, README_C_I_0P.TXT.
ELF sample ransom note, "README_C_I_0P.TXT".
This differs somewhat from the Windows .rtf ransom note, although both use the email addresses unlock@support-mult[.]com and unlock@rsv-box[.]com as ways for victims to contact the attackers.

Window samples ransom note, !_READ_ME.RTF.
Window samples ransom note, “!_READ_ME.RTF”.

Source: https://www.sentinelone.com/labs/cl...s-with-flawed-encryption-decryptor-available/

Decryptor (source: https://gist.github.com/Tera0017S1/c62a928a911442e1509d127fdcd93b71):

Python:
"""
Author: @Tera0017/@SentinelOne
Description: Clop-Linux ransomware variant files decryption.
Link: https://s1.ai/Clop-ELF
Execution help: $ python3 clop_linux_file_decr.py --help
"""
import argparse
import glob
import os.path
import struct
from arc4 import ARC4


def parse_arguments() -> argparse.Namespace:
    """
    Parses commandline parameters if any.
    @return: returns parse_args() result -> argparse.Namespace
    """
    description = """Python3 script which decrypts files encrypted by flawed Cl0p ELF variant.
    More info regarding Cl0p ELF variant and how decryptor was created at https://s1.ai/Clop-ELF
    """
    print('=' * 40)
    print('SentinelOne Cl0p ELF variant Decryptor.\nAuthor: @Tera0017/@SentinelOne\nLink: https://s1.ai/Clop-ELF')
    print('=' * 40)
    parser = argparse.ArgumentParser(
                        prog='clop_linux_file_decr.py',
                        description=description,
                        epilog='author:@Tera0017/@SentinelOne')

    parser.add_argument('--elfile', default=None, help='ELF Cl0p Binary, is used to retrieve "RC4 master key" else default is used for decryption.')
    parser.add_argument('--keys', default=None, help='File containing result of "$ find / -name *.$cl0p_extension -print 2>/dev/null > cl0p_keys.txt". Run with sudo if needed .')
    parser.add_argument('--rc4key', default=None, help='RC4 master key for decryption of clop key files. If --elf is provided script will dynamically retrieve it.')
    return parser.parse_args()


def message(msg: str) -> None:
    """
    @param msg: message to print
    @return: None
    """
    print(f'*{msg}')


class ClopELFDecryptor:
    def __init__(self, filepath=None, clop_find_file=None, rc4_master_key=None):
        """
        @param filepath: str, filepath of cl0p elf variant ransomware found in encrypted machine.
        @param clop_find_file: str, filepath containing result of "$ find / -name *.$cl0p_extension -print 2>/dev/null > clop_keys.txt"
        @param rc4_master_key: str, rc4 master key is not extracted well from cl0p elf binary.
        """
        # if elf sample does not exist tries with observed key.
        self.elfdata = open(filepath, 'rb').read() if filepath is not None else None
        # result of "$ find / -name *.$cl0p_extension -print 2>/dev/null > clop_keys.txt" containing clop keys
        self.clop_keys_file = clop_find_file
        self.rc4_master_key = rc4_master_key
        # clop filekeys extension.
        self.clop_ext = ".C_I_0P"
        # RC4 generated key size.
        self.rc4_gen_key_size = 0x75

    def get_rc4_master_key(self) -> bytes:
        """
        Retrieves RC4 master key from ELF binary. If elf is not found returns default observed key.
        @return: bytes, RC4 master key.
        """
        if self.rc4_master_key is not None:
            message('User provided RC4 master key')
            return self.rc4_master_key
        elif self.elfdata is None:
            message('Retrieved previous observed RC4 key.')
            # observed RC4 master key
            return b'Jfkdskfku2ir32y7432uroduw8y7318i9018urewfdsZ2Oaifwueh~~cudsffdsd'
        # dirty way to retrieve master key.
        f = b'/root'
        idx = self.elfdata.find(f) + len(f) + 1
        return self.elfdata[idx: idx + 100].lstrip(b'\x00').split(b'\x00')[0]

    def get_clop_keys(self) -> list:
        """
        Based on the filekeys clop extension retrieves all the encrypted files from the machine.
        * If you need to speed up process add specific folders where encryption took place.
        * Or pass result of "$ find / -name *.$cl0p_extension -print 2>/dev/null > clop_keys.txt"
        as argument to "--keys".
        @return: list, encrypted filepaths
        """
        if self.clop_keys_file is not None:
            # get clop keys "$ find / -name *.$cl0p_extension -print 2>/dev/null > clop_keys.txt"
            with open(self.clop_keys_file, 'r') as hfile:
                lines = hfile.readlines()
            return [l.strip() for l in lines if l.strip()]

        # enumerate all folders and find clop extension files.
        message(f'Searching for encrypted file extension {self.clop_ext}.')
        message('This operation will take several minutes...')
        message('To speed up process prefer to use "--keys", parameter.')
        return glob.glob(f'/**/*{self.clop_ext}', recursive=True)

    def decrypt(self) -> None:
        """
        Main function decrypts Clop-ELF encrypted files.
        @return: None
        """
        message('Starting decryption process.')
        # 1. Retrieve RC4 "master-key".
        rc4_master_key = self.get_rc4_master_key()
        message(f'RC4 Master Key: "{rc4_master_key}"')
        # 2. Read all $filename.$clop_extension.
        file_keys = self.get_clop_keys()
        message(f'Encrypted Files: {len(file_keys)}')
        for file_key in file_keys:
            message(f'File: {file_key}')
            with open(file_key, 'rb') as hfile:
                file_key_data = hfile.read()
            # 3. Decrypt with RC4 using the RC4 "master-key", the generated RC4 key.
            cipher = ARC4(rc4_master_key)
            file_rc4_key = cipher.decrypt(file_key_data)[:self.rc4_gen_key_size]
            # getting encrypted file size (if file is written again after encryption then
            # encrypted_file_size != file_size
            size_off = 0x75 + 0x58 + 0x8 + 0x4 + 0x4
            try:
                encr_file_size = struct.unpack('Q', file_key_data[size_off: size_off + 0x8])[0]
            except struct.error:
                message(f'[ERROR] Clop key file seems corrupted: {file_key}')
                continue
            encr_file = file_key.replace(self.clop_ext, '')
            # decrypted files have extension '.decrypted_by_S1', once validated can delete and replace encrypted.
            decr_file = file_key.replace(self.clop_ext, '.decrypted_by_S1')
            if os.path.isfile(encr_file):
                with open(encr_file, 'rb') as hfile:
                    encr_file_data = hfile.read()
            else:
                message(f'[ERROR] Unable to find encrypted file: {encr_file}')
                continue
            # 4. Decrypt $filename with RC4 using the generated RC4 key.
            cipher = ARC4(file_rc4_key)
            decrypted_file_data = cipher.decrypt(encr_file_data[:encr_file_size]) + encr_file_data[encr_file_size:]
            # 5. Write decrypted to $filename.
            with open(decr_file, 'wb') as hfile:
                hfile.write(decrypted_file_data)
            message(f'Decrypted: {decr_file}')


if __name__ == '__main__':
    # parsing command line arguments for the decryptor. Use --help for more information
    parsed = parse_arguments()
    ClopELFDecryptor(parsed.elfile, parsed.keys, parsed.rc4key).decrypt()
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх