Kimsuky APT继续使用AppleSeed后门攻击韩国政府
· 5 分钟阅读 · @admin

Kimsuky 是一个源自朝鲜的 APT 组织,也被称为 Mystery Baby、Baby Coin、Smoke Screen、BabyShark、Cobra Venom 等,最早由卡巴斯基实验室于 2013 年披露。
该组织长期针对韩国的智库、政府外交机构、新闻组织、教育学术机构等发起攻击。近年来,其攻击目标已扩展至美国、俄罗斯和欧洲各国,主要以窃取情报和开展间谍活动为目的。
Kimsuky 惯用鱼叉式网络钓鱼和社会工程学手段来获取对受害者网络的初始访问权限。
样本详情
| 文件名 | ESTCommon.dll |
|---|---|
| Md5 | 6844589e2962b3914824cc8b90a552a6 |
| 文件类型 | Dll x64 |
详细分析
字符串解密
恶意程序将所有可见的字符串和重要的 API 使用自定义加密算法进行加密,加密后的数据以十六进制的 ANSI 格式存储,在需要使用时调用解密函数进行解密,如下图所示:

首先将加密数据转换为十六进制,然后取前 16 个字节作为异或密钥,剩余数据为已加密的字符串。解密算法如下,当 i 为 0 时,string[i-1] 为 0。
key[i] ^ string[i-1] ^ string[i]
以上图中的加密数据为例,解密过程如下:
异或 Key 为:5a a6 54 15 c2 fc 1b e5 25 29 0b 29 23 75 89 4b
加密字符为:31 f2 d4 af 08 98 b0 67 6c 21 46 03
依次异或解密:
0x5a ^ 0x00 ^ 0x31 = 'k'
0xa6 ^ 0x31 ^ 0xf2 = 'e'
0x54 ^ 0xf2 ^ 0xd4 = 'r'
0x15 ^ 0xd4 ^ 0xaf = 'n'
0xc2 ^ 0xaf ^ 0x08 = 'e'
0xfc ^ 0x08 ^ 0x98 = 'l'
0x1b ^ 0x98 ^ 0xb0 = '3'
0xe5 ^ 0xb0 ^ 0x67 = '2'
0x25 ^ 0x67 ^ 0x6c = '.'
0x29 ^ 0x6c ^ 0x21 = 'd'
0x0b ^ 0x21 ^ 0x46 = 'l'
0x29 ^ 0x46 ^ 0x03 = 'l'
最后解密出字符串 "kernel32.dll"
使用 Python 脚本编写的解密代码如下:
def decrypt(s):
s_bytes = bytes.fromhex(s)
key = s_bytes[0:16]
str = s_bytes[16:]
decrypt_str = ""
for i in range(0, len(str)):
if i == 0:
ch = 0
else:
ch = str[i-1]
ch = key[i%16] ^ ch ^ str[i]
decrypt_str = "%s%c" % (decrypt_str, ch)
print(decrypt_str)
判断互斥量
恶意程序在 API 解析完成后会判断互斥量 SpyRegsvr32-20210604170153 是否存在,如果存在则退出程序以避免重复运行。

权限提升
恶意程序通过检测ConsentPromptBehaviorAdmin和PromptOnSecureDesktop的值来判断UAC是否被启用,如果这两个注册表项值都为0, 则表示UAC已被禁用无需做提权操作。
- HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
ㄴConsentPromptBehaviorAdmin
- HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
ㄴ PromptOnSecureDesktop
UAC检测代码如下:

判断当前进程是否具有 TokenElevation 权限:

如果 UAC 被禁用且当前进程没有 TokenElevation,则通过 PowerShell 间接使用 regsvr32 启动恶意进程,此时恶意程序将具有与 regsvr32 相同的权限。

线程执行主要功能
恶意程序使用多个线程来实现主要功能,创建的线程如下:

屏幕截图线程
该线程每隔 5 分钟执行一次屏幕截图,并通过 SMTP 协议发送到邮件服务器。截图文件保存到目录 c:\ProgramData\{random}.tmp,当整个文件的数据被加密后,文件名会更改为 {random}.tmp.tmp。
键盘按键记录线程
该线程用于监听键盘按键并记录相应的窗口名称。每记录 256 次按键就将其写入文件,然后休眠 1 秒,最后每隔 10 分钟将按键记录文件发送到邮件服务器。

文件监控线程
该线程每隔一分钟从指定目录搜索特定后缀的文件,监控的目录包括:
%Desktop%
%Downloads%
%Documents%
AppData\Local\Microsoft\Windows\INetCache\IE
如果发现指定后缀的文件,将文件名写入到 list.fdb 文件中。

USB 文件监控线程
恶意程序通过 get_usbs 函数找到所有存在的 USB 驱动器,然后通过 dir 命令获取该驱动器的文件列表,压缩加密后发送到邮件服务器。

文件泄露线程
该线程用于从受害者机器上收集各种数据,收集到的文件列表保存到路径:
C:\ProgramData\Software\ESTsoft\Common\list.fdb
文件格式如下:
struct format {
uint16_t magic; // 值为 0xFEFF
char* file_or_dir_name[]; // 多个完整文件名或目录名
}
该线程的主要功能是将 list.fdb 中的文件或目录列表信息压缩加密后发送到邮件服务器。一旦发送成功,恶意程序就会清除 list.fdb 中的文件或目录列表数据,只保留 magic 字段。
C&C 通信机制
读取电子邮件
攻击者将邮件服务作为发送 C&C 指令和接收泄露数据的中转站。C&C 指令由 C&C 服务器发起,以电子邮件的形式存放在特定邮件账户的特定目录中。邮件正文为空,但包含加密的附件,该附件提供后门要执行的命令。恶意程序每隔 30 秒读取一次邮件。
邮件读取过程如下:
- 发送 IMAP 命令
UID SEARCH ALL获取所有邮件的 UID,响应内容为* SEARCH 1 2 3 4,后面的数字即为邮件的 UID - 根据获取到的 UID 发送请求到邮件服务器获取邮件数据,请求链接为:
imaps://imap.daum.net:993/cmd/;Uid={uid}
邮件处理步骤:
- 在邮件中搜索关键字
Subject:找到邮件主题数据 - 附件内容在邮件中以 Base64 编码,以
filename=开头,结尾一般是--,通过搜索这两个字符串可以找到对应的附件数据 - 附件保存为临时文件,然后发送 POST 请求让邮件服务器删除该邮件
请求连接:imaps://imap.daum.net:993/cmd/;Uid={uid}
传输参数:STORE 1 +Flags \Deleted
电子邮件附件解密
恶意程序通过 IMAP 协议从账号 k2x0604@daum.net 的邮箱 cmd 文件夹中获取要执行的 C&C 命令,C&C 指令以加密的形式存放在邮件附件中。
恶意程序获取到邮件后,首先将邮件附件下载并进行第一次解密后保存到临时目录,文件名为 {temp_name}.enc。邮件附件使用如下结构保存加密的 C&C 指令数据:
struct encrypt_Command {
char fake_pdf_head[0x10]; // 伪装成 PDF 文件,值为 "%PDF-1.7..4 0 obj"
uint32_t vertifity_crc; // xor_key 和 encrypt_command 的 CRC32 值的取反值
// 用于验证数据是否被修改
char xor_key[0x10]; // 用于解密 C&C 指令
char encrypt_command[]; // 加密的 C&C 指令
}
首先查找 PDF 标识,如果不是 PDF 格式则取消解密操作,否则进行解密 C&C 指令操作。恶意程序通过将邮件附件伪装成 PDF 文件的手段绕过邮件安全系统的检测。

恶意程序采用自定义算法生成一个密钥,该密钥与 xor_key、encrypt_command 通过自定义算法计算出 CRC32 值,将该值取反后与 vertifity_crc 比较来验证邮件附件是否被修改过。

解密加密的 C&C 指令时,使用 xor_key 来进行解密,解密后写入临时文件。

C&C 指令解密
恶意程序在第一次解密邮件附件后,C&C 指令部分仍处于加密状态,对应的格式如下:
struct encrypt_cmd {
uint32_t cmd_len; // 解密后 C&C 指令数据的大小
char key[0x80]; // 使用 RSA 算法加密的 RC4 密钥
char crypt_cmd[]; // 已加密的 C&C 指令
}
为防止 C&C 指令数据被解密,攻击者将用于解密 C&C 指令的 RC4 密钥使用 RSA 算法加密。发送邮件时使用公钥对 RC4 密钥加密,接收到邮件时使用 RSA 私钥解密 RC4 密钥。
RSA 公钥与私钥以硬编码和加密的形式存放在程序内,解密方法与解密字符串一样。解密后的数据为十六进制字符串,转换为十六进制后为对应的 Microsoft Blob Format 格式,使用 OpenSSL 程序可以将其转换成文本形式。
解密后的 RSA 公钥如下:

解密后的 RSA 私钥如下:

恶意程序将要发送的数据加密后上传到电子邮件附件,然后发送到邮件服务器。数据加密过程如下:
- 生成大小为 117 字节的随机数并计算其 MD5 值作为 RC4 算法的密钥
- 使用 RSA 公钥加密 RC4 密钥
- 将原始数据长度写入文件,长度为 4 字节
- 将加密后的 RC4 密钥写入文件,长度为 0x80 字节
- 使用 RC4 算法加密要发送的数据,并写入文件
代码实现如下:

恶意程序从邮件服务器获取邮件时解密邮件附件得到加密的 C&C 指令,解密过程如下:
- 从邮件附件中读取被加密的 RC4 密钥
- 使用 RSA 私钥解密 RC4 密钥
- 使用 RC4 密钥解密加密的 C&C 指令
代码实现如下:

从对邮件附件的加密解密来看,RC4 算法使用的密钥为随机生成且被 RSA 算法加密,只要 RSA 密钥不被泄露,想要解密数据目前是非常困难的。
指令读取
恶意程序要执行的指令包含在攻击者通过邮件服务发送的电子邮件附件中,C&C 指令部分解密后使用的结构如下:
struct C2C_command {
uint32_t commandID; // 指令 ID
uint32_t param_cnt; // 参数个数
uint32_t* params_size; // 保存每个参数的大小
void* params; // 保存所有的参数,参数大小由字段 params_size 指定
}
C&C 指令读取代码如下:

C&C 指令
C&C 指令由恶意程序从邮件附件中解密而来,主要包括以下几种:
| C&C 指令 | 描述 |
|---|---|
| 0x64 | 写入数据到 list.fdb |
| 0x66 | 创建文件 |
| 0x65 | 启用或禁用恶意程序的主要功能 |
| 0x00 | 子指令 1:执行文件并返回输出结果 |
| 0x00 | 子指令 1 或 3:通过 regsvr32.exe 执行命令 |
| 0x02 | DLL 注入 |
写入文件或目录列表到 list.fdb
攻击者在该文件中写入想要从受害者机器上获取的文件和目录,等到下一次执行文件泄露线程时将这些文件泄露出去。该命令使用的结构如下:
struct format {
uint32_t commid; // 0x64
uint32_t param_cnt; // 参数个数为 1
uint32_t param_size; // 参数大小
uint8_t param[]; // 包含文件列表或目录列表,使用 "\r\n" 分隔
}
文件创建
该指令主要用于攻击者在受害者机器上创建文件,使用的指令格式如下:
struct format {
uint32_t command_id; // 0x66
uint32_t param_cnt; // 参数个数为 2,文件名和文件数据
uint32_t file_size; // 文件数据大小
uint8_t file[file_size]; // 文件数据
uint32_t file_name_len; // 文件名长度
uint8_t file_name[file_name_len]; // 文件名
}
启用或关闭主要功能
该指令用于开启或关闭主要功能,比如键盘按键记录、文件监控、屏幕截图等。该指令使用的格式如下:
struct format {
uint32_t command_id; // 0x65
uint32_t param_cnt; // 参数个数为 4
uint32_t param1_len; // 参数 1 长度,值为 1
bool enable_keyboard_mon; // 1 为启用,0 为关闭
uint32_t param2_len; // 值为 1
bool enable_screen_mon; // 1 为启用,0 为关闭
uint32_t param3_len; // 值为 1
bool enable_folder_mon; // 1 为启用,0 为关闭
uint32_t param4_len; // 值为 1
bool enable_usb_mon; // 1 为启用,0 为关闭
}
执行命令并返回执行结果
该指令用于在受害者机器上执行命令,并将执行结果发送到邮件服务器。该指令使用的结构如下:
struct format {
uint32_t command_id; // 值为 0
uint32_t param_cnt; // 值为 1,使用一个参数
uint32_t cmd_str_len; // 命令字符串的长度
wchar_t cmd_str[cmd_str_len]; // 命令字符串
}
使用 regsvr32.exe 调用 DLL 程序
该指令主要使用 regsvr32.exe 来调用 DLL 文件,前提是该 DLL 文件导出了函数 DllRegisterServer。DLL 文件下载后保存到临时目录,使用 regsvr32.exe 注册成功后将该 DLL 文件删除。该指令使用的格式如下:
struct format {
uint32_t command_id; // 值为 0
uint32_t param_cnt; // 参数个数
uint32_t file_size; // 文件长度
uint32_t dll_file_data; // 文件数据
}
DLL 注入
该命令的功能主要是将 DLL 注入到进程中,使用的结构如下:
struct format {
uint32_t command_id; // 值为 2
uint32_t param_cnt; // 使用两个参数
uint32_t name_len; // 函数名长度
uint8_t function_name[name_len]; // 函数名
uint32_t file_size; // DLL 文件长度
uint8_t file_buf[file_size]; // DLL 文件数据
}
将接收到的 DLL 注入到指定的进程中,并执行指令中给定的导出函数 function_name。
ATT&CK 矩阵映射
| Tactic | ID | Name | Description |
|---|---|---|---|
| Exfiltration | T1041 | Exfiltration Over C2 Channel | 通过邮件泄露数据 |
| Command and Control | T1071.003 | Application Layer Protocol: Mail Protocols | 使用邮件服务接收泄露数据或发送 C&C 指令 |
| T1001 | Data Obfuscation | 使用 RC4 加密或解密数据,使用 RSA 算法加密 RC4 密钥 | |
| Collection | T1113 | Screen Capture | 屏幕截图 |
| T1056 | Input Capture | 按键记录 | |
| T1560 | Archive Collected Data | 使用 ZIP 算法压缩收集的数据 | |
| T1005 | Data from Local System | 搜索本地文件 | |
| T1025 | Data from Removable Media | 从 USB 驱动器收集数据 | |
| Discovery | T1083 | File and Directory Discovery | 遍历文件或目录 |
| T1082 | System Information Discovery | 获取操作系统版本号用于机器标识符 | |
| Persistence | T1547 | Boot or Logon Autostart Execution | 注册自启动项 |
| Execution | T1059 | Command and Scripting Interpreter | 使用 cmd 执行命令 |

