概述
Lazarus APT组织是疑似具有东北亚背景的APT团伙,该组织攻击活动最早可追溯到2007年,其早期主要针对韩国、美国等政府机构,以窃取敏感情报为目的。自2014年后,该组织开始针对全球金融机构 、虚拟货币交易所等为目标,进行以敛财为目的的攻击活动。
2019年,Fortinet安全研究人员深入研究了NukeSped恶意软件样本,这些样本与朝鲜APT Lazarus Group使用的其他恶意软件家族具有多个相似之处,美国政府将其称为Hidden Cobra。本文将对20167年以及2017年的NukeSped样本进行分析。
样本信息
MD5 | FileName | First submission | CreateTime(不准确) |
---|---|---|---|
9b656f5d7e679b94e7b91fc3c4f313e4 | Adobe Flash Player 11.2 | 2017-08-02 | 2014-09-30 |
e48fe20eb1f5a5887f2ac631fed9ed63 | REGSVR32 | 2016-03-30 | 2016-03-30 |
由于大多数APT组织都会选择修改文件时间戳,因此我们看到的文件CreateTime只能作为参考,通常以样本首次提交到VT的时间作为明线。根据First Submission可知Adobe Flash Player 11.2有可能是更新版本的NukeSped,因此,本文选择对Adobe Flash Player 11.2进行详细分析。
Adobe Flash Player 11.2
样本md5:9b656f5d7e679b94e7b91fc3c4f313e4
首次上传VT时间:2017-08-02
创建时间:2014-09-30
基本信息
原始样本为32为应用程序,样本文件名为:Adobe Flash Player 11.2.exe
文件资源的Icons中有Flash Player的应用程序图标,因此可知这是模仿Adobe Flash Player 的攻击样本
解密模块
样本WinMain入口,首先是通过五个函数调用,动态获取了程序所需的一些api函数地址
前三个函数功能一致,首先获取了GetProcAddress函数的地址,然后通过GetProcAddress函数去获取指定的API地址,程序会将经过处理的API字符串传入40159D解码函数中解码成正常函数名然后通过GetProcAddress获取其地址
解码算法如下:
程序会遍历传入进来的字符串,将e-j的字符ascii码增加15,将t-y字符所对应的ascii码减少15
本地持久化模块
接着程序通过call 地址的方法调用GetModuleFileName获取当前的运行进程路径并将其写入到Run注册表中以实现本地持久化,写入的注册表键值为msnconf
写入注册表
本地持久化设置完成之后,程序则会转入到WinMain末尾的402811函数中继续执行
上线模块
首先通过lopen尝试打开c_126705.nls文件,若打开成功则lread读取文件内容
若打开失败,程序则先通过memset将指定的内存空间清空,然后从指定位置开始,每0x10填充一个02,填充的02是后面socket通信中connect参数sockaddr结构体中的sa_family。
接下来,程序会依次将请求地址的端口和ip地址填充到上面清空并分割的内存中,此样本中程序预定义了五个ip地址
分别是
0x53.0x5f.0x8a.0xd2:0x35 -> 83.95.138.210:53
0x4a.0xc6.0x21.0x42:0x1bb -> 74.198.33.66:443
0x40.0xf7.0xa6.0x5a:0x1bb -> 64.247.166.90:443
0x54.0xfd.0x37.0x99:0x1bb -> 84.253.55.153:443
0x50.0x4d.0x99.0x24:0x3h -> 80.77.153.36:53
在内存中的呈现如下
根据时间因子计算一个整数随机数,然后加上基地址0x40B5A2,也就是之前清空然后赋值请求地址的那段内存起始地址,通过这种方式,可以每次随机请求五个ip中的一个
然后connect请求该地址:0x54.0xfd.0x37.0x99:0x1bb -> 84.253.55.153:443
若成功建立连接,程序则尝试通过select的方式通信,并且向C2发送上线/测试数据,若请求失败,程序则休眠0xEA60,也就是60秒重新生成随机数请求。
若第二次请求成功,程序则会跳转到下面尝试将0x40B498地址处的内容发送到C2:
40B498其实就是之前读取文件的buffer,若本地存在c_126705.nls文件,该地址将指向文件内容,若该文件不存在,该地址将被赋值为0x64,服务器可根据该请求值判断当前攻击进行到哪一阶段
获取服务器返回值并且写入到c_126705.nls文件中
远控模块
成功上线之后,程序将会向C2服务器发送0x1243451并解析返回值传入到switch case分支中
跳转表:
分支结构如下
远控模块代码较多,但逻辑比较简单,这里就不对每个分支进行详细分析了,代码是通过call 地址的方式实现API调用,但之前也已经成功解密,例如case值为0x1243435时,程序则会删除C2指定的文件,删除成功向服务器返回0x1243459,删除失败返回0x1243456
case值为0x1243436,程序则会根据C2返回的具体指令,判断是清楚痕迹或收集信息写入文件
case 等于 0x1243437,程序则终止指定进程运行
后面case的功能包括但不限于:创建文件、收集本机信息、上传信息、创建线程、移动文件、遍历文件、远程加载shellcode等。
REGSVR32
样本MD5:e48fe20eb1f5a5887f2ac631fed9ed63
首次上传vt时间:2016-03-30
创建时间:2016-03-30
样本分析
样本是32位应用程序,程序入口点首先是给一个数组赋值
将数组begin地址传入到解密函数中解密数组,然后创建线程实现后续操作
新线程过来,同样是先通过五个call动态获取API调用地址,但是解密算法和上面的样本有些许改变
此样本中的解密算法是:遍历字符串,若字符在b-y之间,则使用0xdb减去自身得到新的值
API加载完毕,程序会尝试调用WSAStartup进行初始化,初始化成功之后进行7个call调用,前面六个函数功能主要是设置注册表、获取操作系统版本信息、获取网卡信息、获取计算机名和用户名等
第七个call里面先解密了C2:125.212.132.222:443
解密第二个C2:175.100.189.174
连接175.100.189.174
尝试senddata
这里程序是通过两次的数据send和recv判断与服务器的连接状态
若程序能与C2通信,则创建线程执行sub_4085a0函数,在该函数中再次请求C2并接收服务器返回的指令
连接C2,接受并解码返回值:
根据解码之后的返回值进入到switch case分支,和新版本的NukeSped指令类似, 远控指令大致包括:
遍历文件夹、创建进程、遍历进程、终止进程、创建进程、写文件、读取文件、删除文件、移动文件、获取计算机基本信息、上传信息、执行服务器返回的shellcode等。
IOCs
MD5
9b656f5d7e679b94e7b91fc3c4f313e4
e48fe20eb1f5a5887f2ac631fed9ed63
C&C
83[.]95.138.210:53
74[.]198.33.66:443
64[.]247.166.90:443
84[.]253.55.153:443
80[.]77.153.36:53
125[.]212.132.222:443
175[.]100.189.174:443