揭开CryptoShield 勒索软件的真实面目

前言


近日,Proofpoint 公司的病毒分析工程师发现一批利用Rig 漏洞利用包传播CryptoShield勒索软件。这波攻击大多利用flash漏洞进行,对于flash漏洞,本人就不再班门弄斧。我们今天就重点分析这一波攻击中所使用的CryptoShield勒索软件。该勒索软件使用了RSA和AES加密算法,使用RSA生成的公钥做为AES算法的密钥,使用AES加密用户文件。在用户机器无法与CC服务器通信的情况下,勒索软件会使用自身硬编码的密钥进行文件的加密,这就为单机受害用户提供了恢复文件的可能,文末提供于单机受害用户的文件恢复方法。

CryptoShield加密后提示文件显示的内容如下:
# RESTORING FILES #.HTML与# RESTORING FILES #.TXT内容

t1.png

我们得到的可执行文件大小不足100K,    可执行文件中的资源文件保存了加密过勒索程序。可执行文件起到了loader的作用。

Loader分析

Loader运行后,会从自身读取类型为“BKJSYHFIOAJSHBGYHFJHASIODFJHAHIJOSKLFAS”的资源数据,然后通过R**算法解密读取到的资源数据得到勒索程序,随后在内存动态加载勒索软件并跳到勒索程序的入口点处执行,对受害用户的磁盘进行扫描加密。

1.    加载资源过程:

t2.png

资源内容:

t3.png

读取资源后,判断资源中的第一个byte是不是字符’Z’,如果不是,就进行解密资源操作。
解密算法为R**,解密密钥为“P*2&%@jJFHSUFH3”,

t4.png

解密过后的内容为PE文件,可以将文件保存出来留做后面分析。
随后,程序在内存中加载解密出的PE文件并到解密出的PE的OEP处执行

t5.png

勒索程序

上面解密出来的PE文件才是真正的勒索程序。我们将从勒索程序的用户标识ID生成算法,加密过程,RSA密钥产生过程三方面来对勒索软件进行分析。

用户标识ID的生成

用户标识ID由两部分组成,第一部分来自于受害用户的用户名信息,对用户名使用ROL7算法。第二部分来自于第一个磁盘分区的卷标序列号:

t6.png

t7.png

t8.png

加密过程分析

程序并没有使用多线程技术,因此对文件的遍历过程耗费的时间较长。勒索程序会根据文件大小(0-50M,50-100M,100M-256M)遍历三次系统文件,首先加密0-50M的文件内容,其次加密50-100M的文件内容,最后加密100M-256M的文件内容。在每次遍历文件系统时,程序首先遍历盘符“A”到盘符“Z”,如果盘符类型为DRIVE_FIXED 、DRIVE_REMOVABLE 、DRIVE_REMOTE 或RIVE_RAMDISK时,遍历该盘符中所有下面扩展名的文件,同时,如果在特定的文件目录下的文件也会跳过不进行加密。

三次遍历系统文件的函数,第一个参数表示此次遍历中最大文件大小maxFileSize,第二个参数表示此次遍历中最小文件大小minFileSize,第三个参数表示用于生成AES密钥的RSAKey。

t33.png

加密的文件后缀名列表:

t9.png

排除下面目录中的文件:

t10.png

遍历下面类型的磁盘,遍历符合加密条件的文件。

t11.png

t12.png

对遍历到的文件,调用加密函数进行加密,有四个参数:RSA密钥,指向文件内容的内存buf,文件大小,保存密文所需要的字节数。对文件使用参数一中的RSA密钥做为AES_256的密钥,调用AES_256对称算法对文件进行加密。

t13.png

RSA密钥的产生

当程序无法与CC服务器通信时,程序会使用保存在文件中的硬编码的RSA密钥。而当程序可以连接到CC服务器时,程序会生成新的RSA密钥对文件进行加密。

1.    程序会判断CC地址的通信情况,如果程序不能与CC地址正常通信,则使用文件中硬编码的RSA密钥。
文件中R**过的硬编码的RSA密钥如下图选中部分:

t14.png

通过R**算法(密钥为:OJ&*(&218u9yheIUTYEW^&Q),解密出RSA密钥:

t15.png

2.    在程序能够与CC地址通信的情况下,程序会生成加密用的RSAkey,同时将生成的RSA的公钥使用R**加密后保存到文件“ExcelFavorite.acl”文件中。

t16.png

然后使用将本地的ExcelFavorite.acl文件,上传到CC服务器中。

t17.png

t18.png

基于上面的分析,在程序能正常连接CC服务器的情况下,程序在本地生成RSA密钥对,并将其中的公钥经过R**加密后上传到CC服务器中删除保存在ExcelFavorite.acl文件中的公钥信息,随后使用该RSA公钥做为AES-256的加密密钥,调用AES-256算法对文件进行加密。

另外,为了实现持久化攻击,勒索软件还会将自己加入启动项,程序会在注册表的下面两个位置创建开机启动项:

t19.png

同时,为了防止受害用户恢复系统,勒索程序会将系统备份删除

t20.png

为了防止用户通过数据恢复类软件恢复保存在本地的ExcelFavorite.acl文件,勒索程序会在将ExcelFavorite.acl文件上传到CC控制服务器后,两次生成ExcelFavorite.acl文件进行覆盖后,最后再通过DeleteFile删除acl文件。

t21.png

数据恢复

通过上面的分析,文件最终的加密算法为AES-256,但勒索软件将加密用的密钥文件已经进行了多次重写后删除。在没有密钥的情况下,无法恢复用户的数据文件。但在CC服务器失效或者用户无法联网的情况下,勒索软件会通过内置的密钥对文件进行加密,在这种情况下,我们可以通过在勒索软件中提取出密钥,再通过该密钥解密用户文件。对此,我们实现了一个简单解密文件的程序,程序源代码在文章附件中。

t22.png

EncryptDecrypt程序输出三个参数,分别为:
Keyfile:我们在勒索程序中提取出来的解密密钥
encrypted_file:待解密的文件路径
plain_file:解密后的文件保存路径
软件运行命令及解密前后的文件对比如下图:

t23.png


总结


近几年来,勒索软件的数量和类型正呈现出爆发式增长,这一方面是由于更多的勒索软件的源代码加入了开源的阵列,从而使勒索软件更新换代更加容易。另一方面也由于对于被勒索软件加密过的文件很难被恢复,受害人常常为了取回文件而支付赎金,这又激起勒索软件作者的开发愿望。也可以看到,反勒索软件阵营也变得越来越强大,很多的厂商开始开发反勒索产品,开始互相沟通,交流反勒索经验,共享勒索的威胁情报。但基于勒索软件的加密方式,我们仍建议要把预防放在优先位置,及时备份文件,不轻易点开陌生人邮件,及时更新安全防护软件。

参考:


https://www.bleepingcomputer.com/news/security/cryptomix-variant-named-cryptoshield-1-0-ransomware-distributed-by-exploit-kits/

https://isc.sans.edu/forums/diary/CryptoShield+Ransomware+from+Rig+EK/22047/?adbsc=social69980656&adbid=829751979773620225&adbpl=tw&adbpr=4487645412


附EncryptDecrypt代码:


硬编码的RSA公钥文件的十六进制表示

06 02 00 00 00 A4 00 00 52 53 41 31 00 08 00 00
01 00 01 00 F3 18 13 A2 19 C1 39 C0 77 F2 97 6C
7E 09 32 52 AF 64 05 3E 49 90 07 C6 4C 18 22 0E
03 C5 9B 44 73 BA 35 EA C1 1B 38 1B 4F 09 D2 A0
16 60 41 FB A1 38 C1 ** 89 CC DE B3 92 7C 91 9F
19 6C AC 5C 94 89 9E 70 E2 AB FF 3D B8 DA 41 8A
3B 38 10 F7 B7 4B E7 94 1F D4 38 B2 5D 41 0A 77
8D F0 95 B7 0D E1 8D 5D B2 AF 28 91 78 61 DE 1F
DE CF EF F7 AA 00 EC DB 10 99 A5 52 7E 84 2B 25
B9 57 0C B7 AB 61 80 19 9A 1C BD CE 3E 30 15 A3
3D ** 68 9A 2A 00 3D 72 0E 25 DD 2B 90 8C 7C 79
85 3F 7B F6 96 C7 94 CF B3 AE 00 E3 58 DC 3C 47
84 55 3D F1 F3 04 EC 5A 05 B0 89 54 60 5D 8C 8F
1C BC 4D 5D C6 99 9B 33 09 6F A0 41 43 0C FC 26
53 70 03 F1 AE F7 83 EF 4B 7E 2F 99 C7 28 43 B0
74 7A B6 0F 83 4C 28 15 ** 95 C8 96 BB FF AE 02
03 48 8A 67 0B E6 4E AD 70 A1 17 95 D4 4C FE F0
F8 40 31 A9

EncryptDecrypt代码

#include "stdafx.h"

#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <conio.h>
#define  BUFFER_SIZE 512
#define BLOCK_SIZE 512

int MyDecrypt(_TCHAR* strPrivateKeyFile, _TCHAR* strEncryptedFile, _TCHAR* strPlainFile);
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    int iResult = 0;
    if (argc == 4)
    {
        // Decrypt
        iResult = MyDecrypt(argv[1], argv[2], argv[3]);
    }
    else
    {
        // Show usage
        _tprintf(_T("Usage:\n"));
        _tprintf(_T("- Decrypt : EncryptDecrypt keyfile encrypted_file plain_file\n"));
        iResult = 1;
    }
    _tprintf(_T("\n << Press any key to continue >> \n"));
    _getch();
    return iResult;
}

int MyDecrypt(_TCHAR* strKeyFile, _TCHAR* strEncryptedFile, _TCHAR* strPlainFile)
{
    // Variables
    HCRYPTPROV hCryptProv = NULL;
    HCRYPTKEY hKey = NULL;
    HCRYPTHASH phHash = NULL;
    DWORD dwPrivateKeyLen = 0;
    DWORD dwDataLen = 0;
    BYTE* pbPrivateKey = NULL;
    BYTE* pbData = NULL;
    HANDLE hPrivateKeyFile = NULL;
    HANDLE hEncryptedFile = NULL;
    HANDLE hPlainFile = NULL;
    DWORD lpNumberOfBytesWritten = 0;
    __try
    {
        // Acquire access to key container
        if (!CryptAcquireContext(&hCryptProv, 0, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
        {
            // Error
            _tprintf(_T("CryptAcquireContext error 0x % x\n"), GetLastError());
            // Try to create a new key container
            if (!CryptAcquireContext(&hCryptProv, _T("AlejaCMa.EncryptDecrypt"), NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
            {
                // Error
                _tprintf(_T("CryptAcquireContext error 0x % x\n"), GetLastError());
                return 1;
            }
        }
        // Open private key file
        HANDLE hRsaFile;
        if ((hRsaFile = CreateFile(
            strKeyFile,
            GENERIC_READ,
            FILE_SHARE_READ,
            NULL,
            OPEN_EXISTING,
            FILE_FLAG_SEQUENTIAL_SCAN,
            NULL
            )) == INVALID_HANDLE_VALUE)
        {
            // Error
            _tprintf(_T("CreateFile error 0x % x\n"), GetLastError());
            return 1;
        }
        // Get file size
        DWORD dwRsaContentSize = 0;
        if ((dwRsaContentSize = GetFileSize(hRsaFile, NULL)) == INVALID_FILE_SIZE)
        {
            // Error
            _tprintf(_T("GetFileSize error 0x % x\n"), GetLastError());
            return 1;
        }
        // Create a buffer for the private key
        BYTE* pbRsaContent = NULL;
        if (!(pbRsaContent = (BYTE *)malloc(dwRsaContentSize)))
        {
            // Error
            _tprintf(_T("malloc error 0x % x\n"), GetLastError());
            return 1;
        }
        // Read private key
        if (!ReadFile(hRsaFile, pbRsaContent, dwRsaContentSize, &dwRsaContentSize, NULL))
        {
            // Error
            _tprintf(_T("ReadFile error 0x % x\n"), GetLastError());
            return 1;
        }

        // Open encrypted file
        if ((hEncryptedFile = CreateFile(
            strEncryptedFile,
            GENERIC_READ,
            FILE_SHARE_READ,
            NULL,
            OPEN_EXISTING,
            FILE_FLAG_SEQUENTIAL_SCAN,
            NULL
            )) == INVALID_HANDLE_VALUE)
        {
            // Error
            _tprintf(_T("CreateFile error 0x % x\n"), GetLastError());
            return 1;
        }
        // Get file size
        if ((dwDataLen = GetFileSize(hEncryptedFile, NULL)) == INVALID_FILE_SIZE)
        {
            // Error
            _tprintf(_T("GetFileSize error 0x % x\n"), GetLastError());
            return 1;
        }
        // Create a buffer for the encrypted data
        if (!(pbData = (BYTE *)malloc(dwDataLen)))
        {
            // Error
            _tprintf(_T("malloc error 0x % x\n"), GetLastError());
            return 1;
        }
        // Read encrypted data
        if (!ReadFile(hEncryptedFile, pbData, dwDataLen, &dwDataLen, NULL))
        {
            // Error
            _tprintf(_T("ReadFile error 0x % x\n"), GetLastError());
            return 1;
        }

        if (CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &phHash))
        {
            if (CryptHashData(phHash, pbRsaContent, 0x114u, 0) && CryptDeriveKey(hCryptProv, 0x6610u, phHash, CRYPT_EXPORTABLE, &hKey))
            {
                if (CryptDecrypt(hKey, 0, 1, 0, pbData, &dwDataLen))
                {
                    // Create a file to save the plain text
                    if ((hPlainFile = CreateFile(
                        strPlainFile,
                        GENERIC_WRITE,
                        0,
                        NULL,
                        CREATE_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL
                        )) == INVALID_HANDLE_VALUE)
                    {
                        // Error
                        _tprintf(_T("CreateFile error 0x % x\n"), GetLastError());
                        return 1;
                    }
                    // Write the plain text the file
                    if (!WriteFile(
                        hPlainFile,
                        (LPCVOID)pbData,
                        dwDataLen,
                        &lpNumberOfBytesWritten,
                        NULL
                        ))
                    {
                        // Error
                        _tprintf(_T("WriteFile error 0x % x\n"), GetLastError());
                        return 1;
                    }

                }
                CryptDestroyKey(hKey);
            }
            CryptDestroyHash(phHash);
        }
        CryptReleaseContext(hCryptProv, 0);

        return 0;
    }
    __finally
    {
        // Clean up
        if (!pbPrivateKey) {
            free(pbPrivateKey);
        }
        if (!pbData) {
            free(pbData);
        }
        if (hPrivateKeyFile) {
            CloseHandle(hPrivateKeyFile);
        }
        if (hEncryptedFile) {
            CloseHandle(hEncryptedFile);
        }
        if (hPlainFile) {
            CloseHandle(hPlainFile);
        }
        if (hKey) {
            CryptDestroyKey(hKey);
        }
        if (hCryptProv) {
            CryptReleaseContext(hCryptProv, 0);
        }
    }
}

本文作者:先知技术社区

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/63618.html

Tags:
评论  (4)
快来写下你的想法吧!
  • Skey11 2018-12-01 15:20:37

    [img=uploads/comments/2018/12/01/20181201071918_608.png][img=uploads/comments/2018/12/01/20181201071921_125.png][img=uploads/comments/2018/12/01/20181201071921_846.png]

    • Skey11 2018-12-01 15:21:35

      @Skey11 不是你的语言吗?使用http://translate.google.com

      你的文件怎么了?

      您所有的文件都是通过使用CryptoShield 2.0的RSA-2048强加密进行加密的。危险的。

      有关使用RSA-2048加密密钥的更多信息,请参见:https://en.wikipedia.org/wiki/RSA_(cryptosystem)

      这是怎么发生的?

      特别为您的PC生成了个人RSA – 2048密钥,包括公钥和私钥。

      你所有的文件都用公钥加密,公钥已经通过互联网转移到你的电脑上。

      只有在我们的秘密服务器上的私钥和解密程序的帮助下,才能解密您的文件。

      我该怎么办?

      所以,有两种方法可供你选择:等待奇迹出现,让你的价格翻倍,或者现在就开始发电子邮件寻求更具体的指示,

      和恢复您的数据容易的方式。

      如果你有真正有价值的数据,你最好不要浪费你的时间,因为除了付款,没有其他方法可以得到你的文件。

      接收您的私人软件:

      通过电子邮件与我们联系,将您的(个人***明)***号码通过电子邮件发送给我们,并等待进一步的指示。

      我们的专家会在24小时内与您联系。

      您所有的文件都是加密和锁定的,您不能删除它们、移动它们或对它们做任何事情。赶紧取回存取文件。

      请不要浪费你的时间!你只有72小时!之后,主服务器将双倍您的价格!

      所以现在你有机会以较低的价格购买你的个人私有软件了!

      联系电子邮件:

      r_sp@india.com,支持;

      r_sp@computer4u.com -支持预留优先;

      res_reserve@india.com -支持保留秒;

      ***(个人***):C6F26321DE4826C5

    • Skey11 2018-12-01 15:25:16

      @Skey11 [img=uploads/comments/2018/12/01/20181201072514_992.png]

    • SecPulse 企业认证 2018-12-02 11:52:47

      @Skey11 现在应该有解密工具了吧

先知技术社区

文章数:27 积分: 3

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号