投放方式是一個zip包,里面是一個快捷方式文件xxx.lnk。xxx.lnk里的內容是mshta運行網址轉向的xx.hta文件。中途還要收集一波點開人員的機器信息。
hta里的加密形式遇見了好幾次都是手工解的。效率很低,而且相關的樣本很多。使用Python腳本進行解密是一個不錯的選擇。
兩種混淆加密形式原理
- JS動態調用轉成base64編碼的C# DLL函數
- C# DLL調用轉成base64編碼的compressed壓縮數據
JS動態調用轉成base64編碼的C# DLL函數
網上用的比較多的方法,把C#寫的DLL轉成base64,然后動態調用DLL類里的方法。
Jvascript代碼如下:
//動態調整窗口大小
window.resizeTo(0,0);
// 設置.net執行的版本
function setversion() {
var shell = new ActiveXObject('WScript.Shell');
ver = 'v4.0.30319';
try {
shell.RegRead('HKLM\\SOFTWARE\\Microsoft\\.NETFramework\\v4.0.30319\\');
} catch(e) {
ver = 'v2.0.50727';
}
shell.Environment('Process')('COMPLUS_Version') = ver;
// Base64轉碼后的C# DLL代碼賦值到da變量。
var pa = "rk...DLL base64 CODE....";
// 指定入口類名
var fire = 'C# DLL類名';
// Base64解碼函數
function base64ToStream(b) {
var enc = new ActiveXObject("System.Text.ASCIIEncoding");
var length = enc.GetByteCount_2(b);
var ba = enc.GetBytes_4(b);
var transform = new ActiveXObject("System.Security.Cryptography.FromBase64Transform");
ba = transform.TransformFinalBlock(ba, 0, length);
var ms = new ActiveXObject("System.IO.MemoryStream");
ms.Write(ba, 0, (length / 4) * 3);
ms.Position = 0;
return ms;
}
//執行函數
try {
// 設置.net運行環境
setversion();
// 解碼Base64
var Streamline = base64ToStream(pa);
// 調用庫
var fireline = new ActiveXObject('System.Runtime.Serialization.For'+'matters.Binary.BinaryFormatter');
var arraylist = new ActiveXObject('System.Collections.ArrayList');
// 反序列化解開base64后的代碼
var d = fireline.Deserialize_2(Streamline);
arraylist.Add(undefined);
// 動態調用,fire變量里是C# DLL的類
var realObject = d.DynamicInvoke(arraylist.ToArray()).CreateInstance(fire);
// 調用類的方法
realObject.類方法(參數1,參數2)} catch (e) {}
finally{window.close();}
解碼python
Input.txt文件里放加密后的代碼,Output2.dat是輸出的解密代碼。
## 第一階段 文件Base64解碼,提取MZ文件頭到末尾部分,拖到ILSpy就可以看C#代碼。
with open('Input.txt', 'r') as input_file :
decoded = base64.b64decode(input_file.read())
peIndex = decoded.find(b'\x4D\x5A')
outData = decoded[peIndex:]
with open('Output2.dat', 'wb') as Outputfile:
Outputfile.write(outData)
C# DLL調用轉成base64后的compressed壓縮數據
C# DLL從Javascript代碼里讀取被壓縮轉碼成Base64代碼的EXE,然后執行。
舉個例子,編碼后的文本:
EgAAAB+LCAAAAAAABAALycgsVgCi4vzcVAWFktSKEgC9n1/fEgAAAA==
解碼后的原文:
This is some text
使用以下的C#函數做解密:
當然代碼里是不應該用Encoding.Default.GetString
的。對於中文來說,不同的語言編碼占的字節數是不同的。攻擊者顯然沒有注意這點,直接調用的默認編碼,中文系統無法順利運行。
// 解壓縮函數
public string decompressData(string compressedText)
{
byte[] array = Convert.FromBase64String(compressedText);
string @string;
using (MemoryStream memoryStream = new MemoryStream())
{
int num = BitConverter.ToInt32(array, 0);
memoryStream.Write(array, 4, array.Length - 4);
byte[] array2 = new byte[num];
memoryStream.Position = 0L;
using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
{
gZipStream.Read(array2, 0, array2.Length);
}
@string = Encoding.Default.GetString(array2);
}
return @string;
}
解碼python
Input.txt文件里放加密后的代碼,Output2.dat是輸出的解密代碼。
# 第二階段文件Base64解碼,解compressed壓縮
with open('Input.txt', 'r') as input_file :
decoded = base64.b64decode(input_file.read())
struct.unpack('i', decoded[:4])[0]
with open('Output2.dat', 'wb') as Outputfile:
Outputfile.write(gzip.decompress(decoded[4:]))
加密GZIP Compress/Decompress in C#/JAVA
既然有解密,那就肯定有加密代碼。
Program.cs
using System;
using System.IO;
using System.IO.Compression;
using System.Text;
class Program {
private static string Compress(string text)
{
byte[] buffer = Encoding.UTF8.GetBytes(text);
MemoryStream ms = new MemoryStream();
using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
{
zip.Write(buffer, 0, buffer.Length);
}
ms.Position = 0;
MemoryStream outStream = new MemoryStream();
byte[] compressed = new byte[ms.Length];
ms.Read(compressed, 0, compressed.Length);
return Convert.ToBase64String(compressed);
}
public static string Decompress(string compressedText)
{
byte[] gZipBuffer = Convert.FromBase64String(compressedText);
using (var memoryStream = new MemoryStream())
{
int dataLength = BitConverter.ToInt32(gZipBuffer, 0);
memoryStream.Write(gZipBuffer, 0, gZipBuffer.Length);
var buffer = new byte[dataLength];
memoryStream.Position = 0;
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
{
gZipStream.Read(buffer, 0, buffer.Length);
}
return Encoding.UTF8.GetString(buffer);
}
}
public static void Main(string[] args) {
string original = "Mary had a little LAMB";
string compressed = Compress(original);
string decompressed = Decompress(compressed);
Console.WriteLine("Original String: "+original);
Console.WriteLine("Compressed String: "+compressed);
Console.WriteLine("Decompressed String: "+decompressed);
}
}
Program.java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* Created by salar on 10/3/16.
*/
public class Program {
private static String Compress(String data) {
try {
// Create an output stream, and a gzip stream to wrap over.
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length());
GZIPOutputStream gzip = new GZIPOutputStream(bos);
// Compress the input string
gzip.write(data.getBytes());
gzip.close();
byte[] compressed = bos.toByteArray();
bos.close();
// Convert to base64
compressed = Base64.getEncoder().encode(compressed);
// return the newly created string
return new String(compressed);
} catch(IOException e) {
return null;
}
}
private static String Decompress(String compressedText) throws IOException {
// get the bytes for the compressed string
byte[] compressed = compressedText.getBytes("UTF8");
// convert the bytes from base64 to normal string
Base64.Decoder d = Base64.getDecoder();
compressed = d.decode(compressed);
// decode.
final int BUFFER_SIZE = 32;
ByteArrayInputStream is = new ByteArrayInputStream(compressed);
GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
StringBuilder string = new StringBuilder();
byte[] data = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = gis.read(data)) != -1)
{
string.append(new String(data, 0, bytesRead));
}
gis.close();
is.close();
return string.toString();
}
public static void main(String args[]) {
String input = "Mary had a little LAMB";
String compressed = Compress(input);
String uncompressed = null;
try {
uncompressed = Decompress(compressed);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Original String: " + input);
System.out.println("Compressed String: "+compressed);
System.out.println("Uncompressed String: "+uncompressed);
}
}
參考
- How to decompress text in Python that has been compressed with gzip?
https://stackoverflow.com/questions/52478874/how-to-decompress-text-in-python-that-has-been-compressed-with-gzip - 壓縮和解壓縮的代碼
https://gist.github.com/TheSalarKhan/a5242147e7bc2d431b2c0a8670e33a0f