导语:Spartacus勒索软件是2018年发现的一个新勒索软件样本。该勒索软件是用C#编写的,通过对该样本的分析,可以为分析其他勒索软件样本作为基准和参考。
Spartacus是一个比较直接的勒索软件样本,使用了ShiOne,Blackheart等过去的一些勒索软件的技术和代码。但是该恶意软件与这些勒索软件和攻击单元没有直接的关系。
Satyr和Blackheart中的代码基本上相同,而Spartacus的代码流虽然相似,但是做了一定的修改。研究人员作出假设,这可能来源于同一攻击单元或者不同的攻击单元使用相同的代码。但是,还没有证据能够证明。
总的来说,所有的.NET勒索软件弹出的字符串或多或少是相似的。这只是犯罪分子创建的一种简单形式的勒索软件,因为花费的时间相对很少。
Spartacus的分析可以作为分析其他.net勒索软件样本的一个参考和基准。本文的两个主要目的是详细理解代码和如何将一个混淆后的.NET勒索软件样本进行反混淆变成可读的状态。
Spartacus
Spartacus开始就使用Rijndael算法(AES加密的一种)生成一个唯一的加密密钥。该密钥用于加密每个单独的文件,意味着两个系统的文件会有相同的密文。AES密钥是用文件中嵌入的RSA密钥进行加密的。密文会被编码并在勒索信息中展示给用户。
RSA密钥静态嵌入勒索软件的事实说明私钥存在于勒索软件作者的系统服务端。所以,如果私钥泄漏,那么所有受害者的AES密钥就可以用该私钥解密。
如果勒索软件极其复杂,就需要对其进行深度技术分析和代码走查。
解包
首先,用ILSpy软件打开Spartacus样本:
因为所有的代码都是混淆过的,所以函数的代码是不可见的。
然后使用de4dot工具,该工具可以处理文件并输出可读的代码。-r标记是设定目录用的,含有混淆后的.NET样本。
分析
首先看一下main函数。
首先它确保系统只有一个该恶意软件的实例运行,这是通过CheckRunProgram函数创建mutex来确保唯一性的。
检查完成后,会在线程中执行smethod_3。
在smethod_3开始前,该类的构建者会自动化地调用并设置所有的私有成员(变量),其中包含所有要搜索和加密的特殊文件夹。还有使用KeyGenerator.GetUniqueKey(133)函数来创建AES密钥,该密钥对受害者来说是唯一的。这些特殊的文件夹可以在下面看到,可以通过勒索软件进行参考来开始文件夹转化。
上面提到的密钥生成函数是GetUniqueKey(),该函数会用RNGCryptoServiceProvider.GetNonZeroBytes API函数创建一系列的加密的强随机数。然后使用一系列随机数作为字符集的索引array = “abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890”来建立唯一的字符串。这就是AES密钥,可以用来加密所有的文件。
这样就初始化了类的构造器,下面我们看一下调用的smethod_3函数。
该函数重复了特殊文件夹列表,这是构造器中生成的,并且用smethod_6函数中文件夹中开始递归遍历加密文件。这里的加密循环中并不区别文件的类型或特殊文件,会加密所有遍历到的文件。
下面是调用的smethod_1,这是程序设计者的一个错误,因为其输出并没有在程序的其他部分使用,只有在向用户显示加密密钥时被调用了。
smethod_6函数是执行所有加密的函数,smethod_5函数是进行递归的函数,不管从什么位置开始递归,都调用smethod_6函数加密子文件夹中的文件。
该函数还会调用自己来最终覆盖所有的子文件夹。然后调用smethod_6来进行实际的加密,在文件夹中对每个文件完成一个回环。
该方法会重复当前文件夹的所有文件,唯一的说明就是该文件没有被加密。这是通过扩展名是不是.spartacus来确认的。
if (Path.GetExtension(text) == ".Spartacus") { return; }
如果检查通过,就会调用smethod_7,该函数会用加密的内容对文件内容进行重写。
该函数调用smethod_0函数,加密原始的文件数据,接下来的两行将加密的数据写入文件,并将文件扩展名修改为.Spartacus。另一个所有的文件都有相同密钥进行加密的标记是勒索软件并没有将加密的AES密钥写入文件中。
如果使用Rijndael方法的ECB模式,构造器就会用MD5进行哈希,事实上密钥本事也是这么使用的。
整个文件系统的文件加密过程是通过smethod_3的子函数完成的。
下面看一下主函数的下一行,调用了smethod_4()函数:
smethod_4执行的是smethod_3中的递归函数调用。除了在特殊文件夹中loop外,还会对文件系统中挂载的所有逻辑驱动进行重复。所以所有的外部和映射驱动也会被加密。
需要注意的是smethod_6被调用了2次,可能是运行了两个线程来加速加密的过程。
回到主函数,下一个也是最后一个重要的函数调用时:
Application.Run(new Form1());
该函数会向用户展示勒索信息,并在勒索信息中显示加密的AES密钥。
这是通过调用smethod_1()开始的,这里简单的使用了签名生成的AES密钥,并用硬编码的公开的RSA密钥进行加密。
public static string smethod_1() { return Convert.ToBase64String(Class1.smethod_2("<RSAKeyValue><Modulus>xA4fTMirLDPi4rnQUX1GNvHC41PZUR/fDIbHnNBtpY0w2Qc4H2HPaBsKepU33RPXN5EnwGqQ5lhFaNnLGnwYjo7w6OCkU+q0dRev14ndx44k1QACTEz4JmP9VGSia6SwHPbD2TdGJsqSulPkK7YHPGlvLKk4IYF59fUfhSPiWleURYiD50Ll2YxkGxwqEYVSrkrr7DMnNRId502NbxrLWlAVk/XE2KLvi0g9B1q2Uu/PVrUgcxX+4wu9815Ia8dSgYBmftxky427OUoeCC4jFQWjEJlUNE8rvQZO5kllCvPDREvHd42nXIBlULvZ8aiv4b7NabWH1zcd2buYHHyGLQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>", Encoding.UTF8.GetBytes(Class2.smethod_0()))); }
RSA密钥是硬编码的,并且嵌入在勒索软件中,这意味着勒索软件的作者提前在服务端生成了私钥。
然后在所有的驱动之间重复,并写入勒索信息。
最后,打开勒索信息展示消息和RSA加密的AES密钥,受害者可以用来解密。
完成了这些之后,还需要调用smethod_0,该函数会删除所有的Shadow Volume来防止用户用它来进行Windows恢复。
该勒索软件是完全离线的,因为没有与C2或其他服务器进行通信。直到受感染者向其发送个人ID(AES密钥),勒索软件作者才知道谁被感染了。这也就意味着作者发送的解密工具可能是嵌入在AES密钥中的,而每个受害者也是不一样的。
虽然该样本没有什么特殊性,也没有太多的创新性,但是不意味着它就不危险。截止目前针对该勒索软件还没有解密器。如果用户感觉可能感染了该恶意软件,那么最好的办法就是执行进程内存dump,从中可能会提取到密钥。