0x0 写在前面
新人一枚,注册看雪好多年了,第一次发分析贴,有很多不足,如果发现错误,请大家多加指点。
Petya勒索病毒在6月底爆发,然后各大安全公司都发出了相关的报告,但是出于对该样本的兴趣,以及想了解更多
关于该样本的技术细节,就尝试进行了一次详细分析,希望这个报告可以帮助到一些想自己动手分析该样本的同学们。
下面就是详细的分析流程:
0x1 概述
样本名:PetYa
MD5:71b6a493388e7d0b40c83ce903bc6b04
分析环境及工具:winXp sp3、IDA6.8、吾爱OD1.1
0x2、相关文件
PetYa.dll:样本主体
X.tmp :样本释放pe文件,用于提取本机账户密码的工具
Dllhost.dat:样本释放的pe文件,用于远程执行命令
0x3、行为预览
1、进程自身提权、检测杀软
2、拷贝自身代码到堆内存执行,并卸载自身主模块,躲避内存扫描
3、加密MBR引导扇区数据,篡改MBR代码
4、创建重启计划任务
5、释放密码抓取以及远程命令执行工具
6、通过多种方式进行传播自身以及远程执行
7、加密磁盘指定格式的文件数据,只加密固定磁盘,不对可移动存储设备加密,通过生成AES128密钥加密文件数据、然后用样本内置的RSA公钥加密AES密钥
8、系统重启后加密NTFS文件系统的MFT表
0x4、报告正文
样本介绍:
该样本为一个DLL文件,有一个导出序号为1的函数,该函数为样本整个行为的入口。
分析过程:
1、提升进程权限、检查当前运行的进程、打开自身pe,读取自身pe数据以及保存自身文件信息
(1)首先需要写个dllload加载该样本并且调用1号导出函数:
(2)提升进程权限,如果提升成功则保存到一个全局变量作为标记:
(3)遍历当期进程列表,判断是否有预期的3个进程在运行,该样本通过自定义的算法将进程字符串计算后得出一个DWORD数值,
然后与事先计算好的3个进程名对应的DWORD数值进行比较,判断是否有这三个进程在运行:
经过分析这3个DWORD数值分别对应杀软:
0x2E214B44:卡巴斯基
0x6403527E/651B3005:诺顿
(4)读取自身数据到堆buffer,并且保存buffer首地址以及文件大小到全局变量:
2、拷贝自身pe数据到堆buffer中,并且修复重定位,然后流程转移到堆中执行代码,接着卸载掉样本自身的主模块,
删除自身pe文件,然后再次调用导出函数1,这么做是为了躲避杀软的内存扫描
(1)申请堆空间,拷贝自身代码,修复重定位,流程转移:
(2)卸载自身主模块,删除自身文件然后调用导出函数1:
3、调用WSAStartUp初始化,检查c:\\windows目录是否存在自身样本文件,如果存在则退出进程:
(1)初始化全局socket:
(2)检查c:\\windows目录下是否有样本自身的文件,如果存在则结束进程,不存在则创建文件:
4、篡改硬盘mbr代码:
(1)如果debug权限提升成功,则进行篡改mbr:
(2)打开c盘驱动设备,获取磁盘信息得到扇区大小,然后根据该大小乘以10申请buffer,将buffer写入到第二个扇区中:
(3)判断卡巴斯基进程是否存在 如果存在则不执行mbr篡改:
(4)获取系统所在的盘符,然后查询该盘符对应的物理磁盘驱动器编号:
4.1)获取系统路径:
4.2)覆盖后得到系统所在盘符的符号链接:
4.3)打开系统盘符号链接,获取该盘所在的物理磁盘编号,然后将该编号数值转为字符串:
4.4)拼接出完整的物理磁盘符号链接。拷贝到参数指向的buffer内,作为传出数据:
(5)检查\\.\PhysicalDrive0磁盘设备的分区类型是否为MBR,如果不是则不执行篡改代码:
磁盘分区类型:
(6)生成60个字节的随机数,然后按字节取余0x3A,得出的值作为一个全局数组的下标,用该下标访问,拼接出一个疑似序列号的字符串:
最终生成的序列号:
(7)读取PhysicalDrive起始扇区的mbr引导代码进行异或加密:
加密前的起始扇区数据:
异或加密后的数据:
接着将一个大小为0x200的栈buffer全部初始化为0x7:
然后分别生成了两个32个字节和8字节的随机数,这两个随机数分别是salsa20算法的key以及iv,在MBR代码里面会运用到Key和iv来进行MFT加密:
接着拷贝了一串字符串到栈buffer里,这段字符串为比特币钱包地址:
(8)申请分别申请两块内存,大小分别是0x200和0x22B1,然后分别拷贝样本自身的mbr代码到这两个buffer内:
(9)循环写入样本的mbr代码,长度为19个扇区:
篡改前的代码:
篡改后的代码:
(10)然后将之前通过60字节随机数当做下标生成的序列号字符串、以及用来加密MFT的32字节的key和8字节的iv、
还有样本内置的字符串数据(经后面的分析得知该串为比特币钱包)写入第32个扇区:
(11)将之前初始化全是0x7的buffer写入第33个扇区:
(12)将加密后的起始扇区mbr引导代码写入第34个扇区:
5、创建重启的任务计划:
该任务计划是在样本运行之后一个小时进行重启:
6、样本自身的传播与远程执行 首先该样本通过三种途径传播自身:
(1) 通过局域网勘测,检测一些可以访问的内网ip并且保存起来,然后对这些ip进行传播自身并且远程执行自身
(2) 通过windows远程桌面的登录凭据记录,获取这些凭据来进行传播自身以及远程执行
(3) 通过(1)步骤获取到的ip地址,利用永恒之蓝漏洞进程传播
远程执行的方式:
样本通过WNetAddConnection2函数连接远程主机,然后将自身pe写入到远程主机的c:\windows目录接下来通过两种方式执行:
通过资源中释放出来的psexec的远程命令执行工具去运行rundll32.exe ,通过该系统exe加载自身dll并且执行导出函数1
通过wimc运行rundll32.exe ,通过该系统exe加载自身dll并且执行导出函数1
(1)创建线程,进行可攻击ip的勘测,首先样本首先会调用同一个函数初始化两个0x34大小的结构,接下来会对该结构进行分析说明:
结构初始化函数:
经过分析还原出如下结构体:
调用该函数初始化的结构体,作用是用来保存一些信息,这些信息用来后续的自身传播以及远程执行,接下来经过实例来说明该结构的作用:
1.1) 首先样本拿到了之前初始化好的结构,然后调用函数,参数分别是一个ip地址、然后是一个常量值、接下来就是结构的首地址,
该函数的目的是要将参数1的字符串数据添加到参数3的结构中:
1.2)10006FC7函数分析:该函数将参数1的字符串拷贝到栈内,然后调用函数10007298,
参数分别是结构首地址、拷贝到栈内的字符串、以及外面参数2的常量值:
1.3)10007298函数分析,由于该结构内有临界区对象,造成idaF5错乱,所以下面贴出反汇编代码
首先使用结构中的临界区对象进行同步,然后判断要添加的字符串是否已经存在于结构中,如果不存在则添加:
接下来判断m_pppPointerArray数组的当前下标是否已经超出最大值(m_IndexRange) 如果超出则不添加:
然后申请8字节大小的堆内存,如果申请成功,则将该内存首地址根据m_CurrentIndex下标保存在m_pppPointerArray数组中,并且这个堆内存是算是个二级指针:
然后再次申请堆内存,大小为结构中的m_remote_buffer_size成员,这次申请的堆内存是用来保存参数2的字符串,
如果申请成功,则将该段内存的首地址保存在上一步骤中申请的8字节堆内存的首地址处:
然后将参数3的常量值,这里暂时看作为flag,将这个常量值保存在第一次申请的8个字节堆内存首地址+4处:
接着拷贝参数2的字符串到第二次申请的堆buffer中:
到此一个新的信息就添加完毕了,接下来用od调试一下上述的过程,
此处调用10007298函数进行将参数字符串的信息添加到结构中:
参数:
接下来在内存中查看该结构的分布情况:
根据上面静态分析添加远程传播执行所需信息的过程,首先m_pppPointerArray中保存了一个8字节大小的堆buffer地址:
然后继续查看这个8字节大小的buffer:
继续查看第二次申请的buffer:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)