Sandworm 使用 Industroyer2 攻击乌克兰电力系统
· 3 分钟阅读 · @admin

Sandworm 归属于俄罗斯总参谋部主要情报局主要特殊技术中心军事单位 74455。2016 年该组织用 Industroyer 切断过乌克兰电力。2022 年 4 月,ESET 在针对乌克兰高压变电站的活动里发现新变种,命名为 Industroyer2。
第一代能和 IEC-101、IEC-104、IEC 61850、OPC DA 设备交互。Industroyer2 只实现了 IEC-104,用来和变电站保护继电器通信。配置不再放 ini,而是硬编码在程序里。
1 样本
| 文件名 | SHA1 | 角色 |
|---|---|---|
108_100.exe |
FD9C17C35A68FC505235E20C6E50C622AED8DEA0 |
Industroyer2 |
zrada.exe |
6FA04992C0624C7AA3CA80DA6A30E6DE91226A16 |
CaddyWiper |
2 硬编码配置
和第一代把配置放在 ini 里不同,Industroyer2 把配置硬编码在程序中,选项之间用空格隔开。

| 位置 | 含义 |
|---|---|
| 0 | IP 地址 |
| 1 | 端口 |
| 2 | 信息对象个数 |
| 3 | 查找工控设备信息对象的方式 |
| 4 | 信息对象起始地址 |
| 5 | 信息对象结束地址 |
| 6 | 未知 |
| 7 | 未知 |
| 8 | 负责和工控设备通信的程序名 |
| 9 | 是否结束该通信程序 |
| 10 | 该程序所在路径 |
| 11 | 某种超时 |
| 12 | 某种超时 |
| 13 | 未知 |
| 14 | 某种超时 |
| 15 | 未知 |
| 16 | 发送 select and execute 时 s_and_e 的初始状态 |
| 17 | 每次发送时是否改 s_and_e |
3 结束合法进程
连接设备之前,样本会尝试结束负责 IEC-104 通信的合法进程。只有配置里 stop_comm_service 为 1 才做这件事。

4 攻击过程
攻击本身不复杂。样本连到配置里的 IP,用配置给出的 ASDU 地址和若干标志拼 ASDU,发给目标。它主要和类型为 single command 或 double command 的 IOA 交互。
4.1 IEC-104
IEC-104 里几个名词:
- APDU:应用规约数据单元
- APCI:应用规约控制信息
- ASDU:应用服务数据单元
起始字符 0x68 标出数据流起点。长度域给出 APDU 长度,含 APCI 的四个控制域八位组和 ASDU。控制域用来避免报文丢失或重复,也管启动、停止和连接监视。

三种帧:
| 帧 | 作用 |
|---|---|
| I | 带计数的信息传输,通常用来传数据 |
| S | 带计数的确认 |
| U | 控制帧,启动、停止或测试,三种里同时只存在一种 |
I 帧由 APCI 和 ASDU 组成,控制域第一个八位组的最低位是 0。ASDU 里 SQ 是可变结构限定词,位于第一个字节的最高位。SQ 为 1 时信息对象地址连续,只有第一个对象带地址,后面的地址依次加 1。SQ 为 0 时每个对象都自带地址。
工控样本里,恶意程序通常关心 single command 和 double command。

struct SCO {
char SCS : 1; /* 0 控分,1 控合 */
char RES : 1;
char QU : 5; /* 0 内部确认,1 短脉冲,2 长脉冲,3 持续脉冲 */
char S_and_E : 1; /* 0 执行,1 选择 */
};
struct SDO {
char SCS : 2; /* 0 控分,1 控合 */
char QU : 5;
char S_and_E : 1;
};
4.2 构造和解析
样本用起始字节和 APDU 长度判断数据包是否合法。

返回的数据放进 apci_packet 和 asdu_packet。


解析时先取出 APCI。

I 帧再解析 ASDU。

发出去的包同样分成两段来填:先填 APCI。

再填 I 帧里的 ASDU。

4.3 测试帧应答
收到 U 帧且控制域是激活测试 0x43 时,样本回确认,控制域为 0x83。


4.4 查找信息对象
IEC-104 没有直接查询信息对象地址的标准做法,所以样本用 Range 模式自己找。Shift 和 sequence 只是取地址的方式不同,流程一样。
第一阶段读配置里的地址范围,对范围内每个 IOA 发 select and execute。设备回确认,就说明这个地址上有信息对象。


第二阶段在循环里对着找到的对象继续发 select and execute。配置要求每次改状态时,改的是 s_and_e,原稿认为它对应开关的分合。配置里如果要求在命令行打印日志,会打出下面这些信息。

5 CaddyWiper
同一环境里还有新版 CaddyWiper。入口附近的反编译和字符串表明,它是 IDA 远程调试工具 win32_remote 的木马化版本。

恶意代码加在库函数 __acrt_GetModuleFileNameA 里,而且这个函数在入口点之前执行,不容易被注意到。Shellcode 接收三个参数。

加密的 shellcode 和解密用的异或 key 都从命令行参数读入。

解密就是简单异或,解完就执行。

Shellcode 负责擦除。C:\Users 以及 D 到 Z 盘上的文件用 0 覆盖,单次覆盖不超过 0xA00000 字节。

最后调用 DeviceIoControl,控制码 IOCTL_DISK_SET_DRIVE_LAYOUT_EX,把分区信息写成 0,主要落在 MBR 或 GPT。覆盖之后操作系统起不来。

6 检测
| SHA1 | TopEDR | YARA |
|---|---|---|
FD9C17C35A68FC505235E20C6E50C622AED8DEA0 |
Trojan/Generic!AA1E45BC9A34D80C |
Topsec-APT.Sandworm.Industoryer2.a |
6FA04992C0624C7AA3CA80DA6A30E6DE91226A16 |
Trojan/Generic!B15317C0D0BE6B30 |
Topsec-APT.Sandworm.CaddyWiper.a |
7 IOC
FD9C17C35A68FC505235E20C6E50C622AED8DEA06FA04992C0624C7AA3CA80DA6A30E6DE91226A16PService_PPD.exeD:\OIK\DevCounter
8 ATT&CK
| 战术 | ID | 名称 | 在这次活动里 |
|---|---|---|---|
| Impact | T1561.002 | Disk Wipe: Disk Structure Wipe | 覆盖 MBR 或 GPT |
| Impact | T1561.001 | Disk Wipe: Disk Content Wipe | 用 0 覆盖文件 |
| Discovery | T1057 | Process Discovery | 查找并结束 PServiceControl.exe |
| Privilege Escalation | T1068 | Exploitation for Privilege Escalation | 擦除磁盘前需要更高权限 |

