基本信息
报告名称:Rapid勒索病毒变种分析
作者:Bianca
报告更新日期:2020.12.8
样本发现日期:未知
样本类型:PE32 executable (GUI) Intel 80386, for MS Windows
样本文件大小/被感染文件变化长度:472K
样本文件MD5 校验值:40c5113e35dd653ca1fc1524d51da408
样本文件SHA1 校验值:c43028b0a2287d7e64199500d48ce7c5f864dc54
壳信息:
可能受到威胁的系统:32位Windows操作系统
相关漏洞:
已知检测名称:
简介
Rapid的勒索病毒使用了 RSA加AES对文件进行加密,它不仅会感染计算机上已有的文件,还会对新创建的文件进行加密。
被感染系统及网络症状
本节的主要目的是帮助潜在读者快速识别被感染后的症状。
文件系统变化
- 它不仅会感染计算机上的已有文件,还会对新创建的文件进行加密。被加密的文件,其文件名被添加“.rapid”扩展名,同时文件大小增加了0x4D0字节;
- 在进行加密的文件夹中创建名为“How Recovery Files.txt”的勒索提示文件;
- 重启电脑弹出recovery.txt文件,和How Recovery Files.txt文件名相同。
注册表变化
[将要/可能]被[创建/修改/删除]的[注册表键/键值]
网络症状
被监听的端口,向指定目标及端口的网络活动及类型,等等
详细分析/功能介绍
1、解密shellcode到内存后执行
- 静态分析
- 编写python程序解密(from 吾爱破解)
- struct.pack参数:https://www.coder4.com/archives/3838
# 解密脚本
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import struct #处理二进制的包
from ctypes import *
'''
c_uint32:unsigned int
int.from_bytes(x, byteorder='little'):把bytes类型的变量x,转化为十进制整数,x的高位字节为后四位
由于加法或程序有可能大于0x100000000, 所以需要与0xffffffff.
struct.pack('I', value):将value打包成unsigned int格式
'''
# first 0x40 byte of shellcode, for example
shellcode = b"\x7c\x98\x39\x52\x45\x84\x52\x73\xA9\xEB\xDB\x07\x5F\xEC\x20\x1D" \
b"\xD2\xE1\xE3x22\x02\x92\x36\xE8\x8C\x6C\x76\x2E\x11\x55\x42\xD3"\
b"\x1F\x1A\x03\x94\xD8\xFF\x88\xD0\x90\x81\x72\xFB\xF0\x2F\x42\x14"\
b"\x82\xC9\x8F\xBD\xD8\xE2\xDD\x3C\xBA\x62\xBB\x9B\x5D\x72\x09\xE5"
def decrypt(enc_one, enc_two):
key0 = c_uint32(0xc6ef3720)
# four parts of one group
key1 = c_uint32(0x5aabd3f6)
key2 = c_uint32(0xf770d8de)
key3 = c_uint32(0x9ad9a390)
key4 = c_uint32(0x5a454ee9)
tmp_one = c_uint32(0)
times = 0x20
value_one = c_uint32(int.from_bytes(enc_one, byteorder='little'))
value_two = c_uint32(int.from_bytes(enc_two, byteorder='little'))
while times > 0:
# 由于加法或程序有可能大于0x100000000, 所以需要与0xffffffff.
value_two.value = value_two.value - ((key0.value + value_one.value)\
^ ((key3.value + (value_one.value << 4) & 0xffffffff) & 0xffffffff)\
^ (key4.value + (value_one.value >> 5) & 0xffffffff) & 0xffffffff)
tmp_one.value = (key0.value + value_two.value)\
^ ((key1.value + (value_two.value << 4) & 0xffffffff) & 0xffffffff)\
^ ((key2.value + (value_two.value >> 5) & 0xffffffff) & 0xffffffff)
key0.value += 0x61c88647
value_one.value -= tmp_one.value
times -= 1
result = struct.pack('I', value_one.value)
result += struct.pack('I', value_two.value)
return result
if __name__ == "__main__":
plain = bytes()
for i in range(0, len(shellcode), 8):
args_one = shellcode[i : i+4]
args_two = shellcode[i+4 : i+8]
plain += decrypt(args_one, args_two)
print("decrypt over")
2、释放勒索病毒本体(分析内存中的shellcode)
shellcode解密勒索病毒主体,将主体各个section覆写原始进程的section.
知识补充:动态定位API函数
- 解决shellcode通用性的问题,以调用MessageBox为例
- kernel32.dll (LoadLibraryA) -> User32.dll (MessageBox)
win32下kernel32.dll和ntdll.dll默认加载
- 首先通过段选择子FS在内存中找到当前的线程环境块TEB
TEB偏移位置为0x30的地方存放着指向进程环境块PEB的指针
// Current PEB for 64bit and 32bit processes accordingly
PVOID GetPEB()
{
#ifdef _WIN64
return (PVOID)__readgsqword(0x0C * sizeof(PVOID));
#else
return (PVOID)__readfsdword(0x0C * sizeof(PVOID));
#endif
}
进程环境块PEB中偏移位置为0x0C的地方存放着指向PEB_LDR_DATA结构体的指针,其中,存放着已经被进程装载的动态链接库的信息。
- PEB_LDR_DATA结构体偏移位置为0x1C的地方存放着指向模块初始化链表的头指针InInitizationOrderModuleList.
- 模块初始化链表InInitizationOrderModuleList中按顺序存放着PE装入运行时初始化模块信息,第一个链表结点是ntdll.dll,第二个链表结点就是kernel32.dll
- 找到属于kernel32.dll的结点后,在其基础上再偏移0x08就是kernel32.dll在内存中的加载基地址(0x1C+0x1+0x08=0x20)
- 从kernel32.dll的加载基址算起,偏移0x3C的地方就是其PE头
- PE头偏移0x78的地方存放着指向函数导出表的指针
- 导出表0x1C处的指针指向存储导出函数偏移地址(RVA)的列表,导出表偏移0x20处的指针指向存储导出函数函数名的列表
- 函数的RVA地址和名字按照顺序存放在上述两个列表中,可以在名称列表中定位到所需的函数是第几个,然后在地址列表中找到对应的RVA获得RVA后,再加上前面已经得到的动态链接库的加载基址,就获得了所需API此刻在内存中的虚拟地址。
1)shellcode获取LoadLibraryA基地址
3)获得其他必要函数地址
2)分配内存解密勒索病毒
4)填充导入表地址
5)判断是否需要重定位
6)跳转至勒索病毒OEP
3、Rapid勒索病毒执行
1)调用ShellExecuteA执行清理工作,防止用户恢复系统
- 清除Windows卷影拷贝:防止受害者使用卷影拷贝恢复文件。
- 禁用修复功能,忽略错误:降低系统崩溃概率。
2)添加计划任务
创建计划任务
3)注册表添加开机启动项
- “recovery.txt”文件是勒索信息文件
4) 对文件进行加密
首先创建了一个PROV_RSA_FULL类型的CSP容器,然后将通过Base64的硬编码在程序中的RSA的公钥(命名为RSA1)导入
创建新的注册表键
- 创建新的注册表项
- RegCreateKeyEx:创建指定的注册表项。如果键已经存在,函数将打开它
- RegOpenKeyEx:打开一个指定的注册表键,得到的将要打开键的句柄
- RegQueryValueEx:检索一个已打开的注册表句柄中,指定的注册表键的类型和设置值,返回0表示检索成功
创建了一个PROV_RSA_FULL类型的CSP容器,并且调用CryptGenKey()生成了随机RSA密钥对(命名为RSA2)
调用CryptExportKey()导出刚刚生成的RSA2私钥数据,并调用RSA1公钥对RSA2私钥加密。
- 加密完成后,将RSA私钥数据写入注册表项HKEY_CURRENT_USER\Software\EncryptKeys\local_enc_private_key,将数据长度写入注册表项HKEY_CURRENT_USER\Software\EncryptKeys\local_enc_private_key_len
- 再次调用CryptExportKey()导出刚刚生成的随机RSA2公钥数据,这次不需要加密,直接写入注册表HKEY_CURRENT_USER\Software\EncryptKeys\local_public_key和HKEY_CURRENT_USER\Software\EncryptKeys\local_public_key_len
- 找到可操作的所有盘符
- 加密文件(跳过勒索信息文件)
- 开始对文件进行加密,获取选取文件的大小,如果文件大小小于0x4D0字节,则直接进入加密流程;否则读取文件尾部0x20字节的数据,并判断这部分数据是不是加密标志“F5 D5 CD CD CD 7D CD CD 95 91 C1 C1 CD AD CD CD 41 CD 41 CD C1 99 FD 1D 59 95 81 FD 99 79 25 A5”,如果不是则进入加密流程,否则选取下一个文件。因为加密过的文件是大于0x4D0的,并且在其文件尾部添加了0x20个字节的加密标志
- 程序进入加密流程后,会先调用CryptGenKey()生成随机AES密钥。并调用CryptExportKey()导出AES密钥数据,BLOBTYPE=PLAINTEXTKEYBLOB。使用RSA2公钥加密AES密钥,加密的是“BLOB格式数据+AES密钥+填充数据”这整个0x80字节的数据
- 读取文件数据,使用AES密钥对读取的文件数据进行加密。
- 加密数据回填
- AES加密是按照128bit进行分组,当原文件字节数不是128bit的整数倍时,加密后的密文数据将会大于明文数据,所以程序在加密前在明文尾部填充了0x10个字节的0x00(一个AES分组的字节数)。向文件覆写加密后的数据,首先只写入原文件大小的密文数据,变多的0x10字节的数据接下来再写;继续向文件中写数据,写入0x4D0字节的数据。这0x4D0字节的数据包括五部分:第一部分0x10字节,这部分就是变多的数据;第二部分0x20字节,包含源文件文件大小的字符串和0xCD的填充数据;第三部分0x80字节,是被加密的AES密钥数据;第四部分0x400字节,是被加密的RSA2私钥数据;第五部分0x20字节,是文件加密标志数据。
- 添加 .rapid 后缀
- 显示勒索信息
相关服务器信息分析
本节可以提供一些详细的目标域名, IP 地址,邮件地址等等相关信息。这样可以方便企业/政府用户更好的了解/追踪该恶意代码的作者/运营者。
预防及修复措施
当然,如果就职于某行业内公司,本节通常会提供相关产品的修复操作步骤。
不过这里我们还是为那些没有安装安软的普通用户来介绍一下,需要安装的安全补丁,如何手动恢复被感染的环境,例如如何一步步的删除/修改相关注册表键值,文件等等。
1) 对重要的数据文件定期进行非本地备份。
2) 不要点击来源不明的邮件以及附件。
3) 重命名vssadmin.exe进程,防止勒索病毒利用它一次性清除文件的卷影副本。
4) 开启防火墙,并升级到最新版本,阻止勒索病毒与其C&C服务器通信。
5) 及时给电脑打补丁,修复漏洞。
6) 使用长度大于10位的复杂密码,禁用GUEST来宾帐户。
7) 尽量不要使用局域网共享,或把共享磁盘设置为只读属性,不允许局域网用户改写文件。
8) 关闭不必要的端口,如:445、135、139、3389等。
技术热点及总结
参考:https://www.freebuf.com/articles/network/162033.html
勒索病毒技术总结
1、母体执行
- 解密shellcode,完成病毒换体
- LoadLibrary、GEtProcAddress、LocalAlloc、VirtualProtect
2、执行变体代码
- 创建一个互斥,防止自身被多次执行
- OpenMutex、CreateMutex
- 创建线程,监控感染主机上的指定进程或服务,解除对应进程的文件占用
- 枚举进程:CreateToolhelp32Snapshot、Process32First、Process32Next、TerminateProcess
- 枚举服务:OpenSCManagerW、EnumServicesStatusExW、StopService
- 创建开机自启动项
- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
- 删除磁盘卷影,防止受害者恢复数据
- 卷影副本功能可提供网络共享上的文件的即时点副本。利用共享文件夹的卷影副本,用户可以查看网络文件夹在过去某一时间点的内容。
- CreateProcess cmd
- 删除磁盘卷影的命令:“mode con cp select=1251 vssadmin delete shadows /all /quiet Exit”
- 扫描局域网共享目录并对扫描到的文件进行加密
- 盘符:ABCDEFGHIJKLMNOPQRSTUVWXYZ
- GetLogicalDrives函数获取磁盘驱动器
- 遍历逻辑驱动器,每个驱动器创建一个文件加密线程,对逻辑驱动器下的文件进行加密
- 内置的一段加密的RSA公钥对随机生成的AES密钥进行加密,并将加密后的内容发给黑客,黑客使用RSA私钥进行解密,得到加密文件的AES密钥。
- 为了保障随机性,黑客对每个文件进行加密的时候都使用随机的IV,被加密后的文件按照特定的文件格式进行存储。
- GetVolumeSerialNumber:获取C盘序列号
- rdtsc:获取CPU自从启动以来的时钟周期数(也就是一个随机数)