外国人 做的中国字网站,莱芜信息网莱芜在线,新品推广策划方案,德阳响应式网站建设0.前言
今天公司服务器中招LockBit2.0勒索病毒#xff0c;损失惨重#xff0c;全体加班了一天基本解决了部分问题#xff0c;首先是丢失的文件数据就没法恢复了#xff0c;这一块没有理睬#xff0c;主要恢复的是两个数据库#xff0c;一个是16GB大小的SQLserver数据库损失惨重全体加班了一天基本解决了部分问题首先是丢失的文件数据就没法恢复了这一块没有理睬主要恢复的是两个数据库一个是16GB大小的SQLserver数据库另一个是一个15GB大小的Mysql数据库最后丢失了1%左右的内容顺利恢复了两个数据库因为lockbit勒索病毒的分享给文章太少这里就记录下自己恢复的过程。
1.恢复逻辑
lockbit2.0的锁定逻辑是针对有价值的文件头部4KB给你加密尾部4KB给你加密然后中间隔一段随机也可能是固定间隔没有考证过给你加密大约4KB全局给你大约加密不到1%的数据因此恢复的逻辑也就是舍弃这些被加密的数据尽可能恢复数据库正常。
注意lockbit2.0不存在找人破解的可能性找人弄也是按照上面的逻辑懂程序原理的都知道lockbit的加密是无法被破解的因此注意各位不要被骗
另外我们能恢复数据库主要是我们的数据库有以下特点数据库极大表内条数极多这样被损坏的数据才能最大概率着落在表内数据的并且表内多是流水账数据丢失部分的损失可控因此修复的可能性最高如果你的数据库不大几百兆内容不多表结构复杂的没什么修复的价值。
2.sqlserver恢复
sqlserver市面是存在恢复软件的我找的是达思科技的软件1399元买了一天的使用权限通过被锁的文件和1年前数据库文件一半大小一起合并进行了恢复最后的回复结果是大致回复了99%的数据部分表格少几条数据有一个表格是40000多条数据少了20条另一个表格18000条数据少了8条少的数据就是被加密的数据被舍掉了。因为sqlsever按照我查的资料主要被加密的数据一个是头文件也就是表结构主要是通过过去的备份文件恢复的中间的数据就是舍弃。这个恢复成功的思路对我后面回复mysql提供了较大的帮助。
最终sqlsever恢复但是因为是财务软件的数据库少的数据还是会导致很多模块计算有问题这个只能后续慢慢反查和处理了。
注意一天时间比较宝贵请提前给自己的机子搭建好本地sql server环境到恢复成功大约耗时要18个小时需要通宵干。
3mysql恢复
mysql恢复是最复杂的首先mysql市面上是没有成品恢复软件的不要被骗。因此只能动手恢复mysql的原始文件是分立的文件每一个文件都被加密了原始数据库是二进制文件因此恢复原始数据库文件的难度最大几乎是不可能被恢复。
因此我们恢复瞄准的是备份的.sql文件.sql文件是一个类似文本文件可读性高恢复起来比较容易。
3.1 mysql文件的逻辑与查看
mysql文件的基本逻辑是如下
建立数据库一句话
{ 建立表A
建立表A结构列
插入表A的数据 *N
。。。。
} *N个表循环 其中头部的4KB是建立表头和建立表结构这一块只能手敲具体方法是自己建立数据库复原表结构后导出为sql文件然后比对着sql文件自己手动恢复头部4KB文件。
第二部分是建立表结构表结构不复杂的话大约是1KB左右的样子
第三部分是插入表数据这个是数据库中最大的一块我们的mysql会将一大堆数据写成一个insert插入每一个insert的最长是2MB字节的大小因此如果损坏的4KB落在这里的话就要排除掉这2MB后续再维修这2MB。
加密的逻辑是随机加密待考因此文件内部被锁的4KB落在insert中的概率最大。
对于这种单文件超大的sql文件是没有查看工具的因此首先用c#写一个分析工具逐行分析这个sql文件是干什么的
使用下面的代码可以将每一行都打印到log文件中使用文本打开log文件可以查看sql语句的结构。
static void Main(string[] args){///* sql有效性验证算法打印算法int linenum 0;string filename I:\\mysql_backup_20231008__00_00.sql.lockbit;string filename1 I:\\log.text;string filename2 I:\\xiufuz_error.sql;String line;bool bResult;int[] errorcode new int[5];try{StreamReader sr new StreamReader(filename);StreamWriter sw1 new StreamWriter(filename1);//StreamWriter sw2 new StreamWriter(filename2);StringBuilder sb new StringBuilder(); //定义sb.Clear();int isbinary 0;int errortick 0;int isrightorerror 0;while (!sr.EndOfStream){//lstchar2 lstchar1;//lstchar1 currentChar;string readlinest sr.ReadLine();byte[] charArray Encoding.Default.GetBytes(readlinest);sb.Append(readlinest);if (charArray.Count() 0){if (charArray[charArray.Count() - 1] 0x3b){line sb.ToString();sb.Clear(); //清空linenum;byte[] bytetemp Encoding.Default.GetBytes(line);isbinary 0;errortick 0;isrightorerror 0; //正确for (int i 0; i line.Length; i){if (i 7 line.Length){if (line[i] _){try{if (line[i1]bline[i2]iline[i3]nline[i4]aline[i5]r){isbinary 1;}}catch{}}}if (isbinary 0){if (!IsChineseLetter(line, i)){errorcode[errortick] Char.ConvertToUtf32(line, i);errortick;if (errortick 3){if (Char.ConvertToUtf32(line, i) 0xff00){}isrightorerror 1; //错误break;}}}else{ }}if (isrightorerror 1){//错误//sw2.WriteLine(line);sw1.WriteLine(行: linenum.ToString(D5) 错误,内容: line.Substring(0, 50) --- errorcode[0].ToString(X4) , errorcode[1].ToString(X4) , errorcode[2].ToString(X4));//Console.WriteLine(错误字符,line: linenum.ToString() ,长度:line.Length.ToString()--- errorcode[0].ToString(X4) , errorcode[1].ToString(X4) , errorcode[2].ToString(X4));}else{ //正确//sw1.WriteLine(line);sw1.WriteLine(行: linenum.ToString(D5) 正确,内容: line.Substring(0, line.Length 50 ? 50 : line.Length));}if (linenum % 100 0)Console.WriteLine(Line: linenum.ToString());}}}sr.Close();sw1.Close();//sw2.Close();Console.WriteLine(Final Line: linenum.ToString());}catch (Exception e){Console.WriteLine(Exception: e.Message);}finally{Console.WriteLine(Executing finally block.);}while (true) ;
}
通过上述文件打印出来的log可以观察到非常多的信息
如下图这是一个正确的建立表格插入数据的结构由7行的建立表头若干行的INSERT数据和1行的解锁组成按照这个逻辑可以查看每一个表格的语句是否完成如图我战士的after_sales这个表格就非常完整。
如下图所示这是一个典型的中间有损失的表可以看到表结构是正确的插入语句在21393行出现了错误这一条语句的数据就要被舍弃后续再根据重要性选择恢复剩余的细节但是这个表的绝大多数部分都会恢复并且是好的 3.2 使用程序辅助分离sql文件中的好的部分和坏的部分
这里我使用的C#写的处理程序处理逻辑是按照分号加换行符来确认不同的sql语句行在每一行中逐个字节判断字节是不是有效的文本信息如果本行文件中出现了三次以上的非Unicode字符的字节我们就判定这一行被加密了将这一行复制到错误的文件中等待修复反之则复制到正确的文件中修复。
附C#代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace 勒索修复程序
{class Program{//我的数据库中各个国家的文字都有因此这里做了针对性的排除static bool IsChineseLetter(string input, int index){int code 0;int chfrom Convert.ToInt32(4e00, 16); //范围0x4e000x9fff转换成intchfromchendint chend Convert.ToInt32(9fff, 16);if (input ! ){code Char.ConvertToUtf32(input, index); //获得字符串input中指定索引index处字符unicode编码if (code 0x80) //英文是正确的return true;if (code chfrom code chend){return true; //当code在中文范围内返回true}if (code 0xa0 code 0xff){return true; //当code在中文范围内返回true}if (code 0xff00 code 0xffee){return true; //当code在中文范围内返回true}if (code 0x3000 code 0x30ff){return true; //当code在中文范围内返回true}if (code 0x3300 code 0x36ff){return true; //当code在中文范围内返回true}if (code 0x13a0 code 0x13ff){return true; //当code在中文范围内返回true}if (code 0x2000 code 0x22ff){return true; //当code在中文范围内返回true}if (code 0x2400 code 0x27ff){return true; //当code在中文范围内返回true}if (code 0x0100 code 0x02ff){return true; //当code在中文范围内返回true}if (code 0x0370 code 0x03ff){return true; //当code在中文范围内返回true}if (code 0x0400 code 0x05ff){return true; //当code在中文范围内返回true}if (code 0x0600 code 0x06ff){return true; //当code在中文范围内返回true}if (code 0x0e00 code 0x0fda){return true; //当code在中文范围内返回true}if (code 0xac00 code 0xd7a3) //韩文{return true; //当code在中文范围内返回true}if (code 0xaa80 code 0xaac2) {return true; //当code在中文范围内返回true}if (code 0x1d00 code 0x1eff){return true; //当code在中文范围内返回true}if (code 0x0900 code 0x0bff){return true; //当code在中文范围内返回true}if (code 0x3400 code 0x4dbf) //繁体{return true; //当code在中文范围内返回true}else{return false; //当code不在中文范围内返回false}}return false;}static void Main(string[] args){///* sql有效性验证算法int linenum 0;string filename I:\\mysql_backup_20231008__00_00.sql.lockbit; //目标文件string filename1 I:\\xiufuz_right.sql; //正确的保存文件string filename2 I:\\xiufuz_error.sql; //错误的保存文件String line;bool bResult;try{StreamReader sr new StreamReader(filename);StreamWriter sw1 new StreamWriter(filename1);StreamWriter sw2 new StreamWriter(filename2);StringBuilder sb new StringBuilder(); //定义sb.Clear();int isbinary 0;int errortick 0;int isrightorerror 0;while (!sr.EndOfStream){//lstchar2 lstchar1;//lstchar1 currentChar;string readlinest sr.ReadLine();byte[] charArray Encoding.Default.GetBytes(readlinest);sb.Append(readlinest);if (charArray.Count() 0){if (charArray[charArray.Count() - 1] 0x3b){line sb.ToString();sb.Clear(); //清空linenum;byte[] bytetemp Encoding.Default.GetBytes(line);isbinary 0;errortick 0;isrightorerror 0; //正确for (int i 0; i line.Length; i){if (i 7 line.Length){if (line[i] _){try{if (line[i1]bline[i2]iline[i3]nline[i4]aline[i5]r){isbinary 1;}}catch{}}}if (isbinary 0){if (!IsChineseLetter(line, i)){errorcode[errortick] Char.ConvertToUtf32(line, i);errortick;if (errortick 3){Console.WriteLine(错误字符,line: linenum.ToString() ,长度:line.Length.ToString()--- errorcode[0].ToString(X4) , errorcode[1].ToString(X4) , errorcode[2].ToString(X4));if (Char.ConvertToUtf32(line, i) 0xff00){}isrightorerror 1; //错误break;}}}else{ }}if (isrightorerror 1){//错误sw2.WriteLine(line);}else{ //正确sw1.WriteLine(line);}}}}sr.Close();sw1.Close();sw2.Close();Console.WriteLine(Final Line: linenum.ToString());}catch (Exception e){Console.WriteLine(Exception: e.Message);}finally{Console.WriteLine(Executing finally block.);}while (true) ;// */while(true);}}
}
执行效果如下图 可以看到被攻击的段落中至少出现三个FFFD以上的这个就是被攻击的段落的特点将没被攻击的干净的sql文件导出后进行下一步处理。 3.3 mysql文件导入库
mysql文件导入mysql库的过程需要自己执行导入过程中发现错误随时进行处理和补全表结构这里因为表是你自己建的别人也帮不了你是一个苦功夫但是我的数据库16GB大小表结构占位不到1MB因此表结构被加密的概率较低实际恢复过程中我的数据库就一个表结构被损坏了因此就补了一个表结构就完成了数据库的恢复。
3.4 其他被损坏的文件的处理 首先我通过C#将500MB左右的损坏文件拆成了10个50MB的文件按照每个文件50行
附代码
static void Main(string[] args){///* //拆分算法try{string line;int linenum0;byte lstchar10, lstchar20;byte currentChar0;int block 0;string filename I:\\xiufuz_error.sql;string filename1 I:\\error1.sql;string filename2 I:\\error2.sql;string filename3 I:\\error3.sql;string filename4 I:\\error4.sql;string filename5 I:\\error5.sql;string filename6 I:\\error6.sql;string filename7 I:\\error7.sql;string filename8 I:\\error8.sql;string filename9 I:\\error9.sql;string filename10 I:\\error10.sql;StreamReader sr new StreamReader(filename);StreamWriter sw1 new StreamWriter(filename1);StreamWriter sw2 new StreamWriter(filename2);StreamWriter sw3 new StreamWriter(filename3);StreamWriter sw4 new StreamWriter(filename4);StreamWriter sw5 new StreamWriter(filename5);StreamWriter sw6 new StreamWriter(filename6);StreamWriter sw7 new StreamWriter(filename7);StreamWriter sw8 new StreamWriter(filename8);StreamWriter sw9 new StreamWriter(filename9);StreamWriter sw10 new StreamWriter(filename10);//Read the first line of textStringBuilder sb new StringBuilder(); //定义sb.Clear();while (!sr.EndOfStream){//lstchar2 lstchar1;//lstchar1 currentChar;string readlinest sr.ReadLine();byte[] charArray Encoding.Default.GetBytes(readlinest);sb.Append(readlinest);if (charArray.Count() 0){if (charArray[charArray.Count() - 1] 0x3b){line sb.ToString();sb.Clear(); //清空linenum;if (linenum % 100 0)Console.WriteLine(Line: linenum.ToString());//清空前处理if (block 0)sw1.WriteLine(line);else if (block 1)sw2.WriteLine(line);else if (block 2)sw3.WriteLine(line);else if (block 3)sw4.WriteLine(line);else if (block 4)sw5.WriteLine(line);else if (block 5)sw6.WriteLine(line);else if (block 6)sw7.WriteLine(line);else if (block 7)sw8.WriteLine(line);else if (block 8)sw9.WriteLine(line);else if (block 9)sw10.WriteLine(line);if (linenum 50){if (block 9){linenum 0;block;}}} }}sw1.Close();sw2.Close();sw3.Close();sw4.Close();sw5.Close();sw6.Close();sw7.Close();sw8.Close();sw9.Close();sw10.Close();Console.WriteLine(Final Line: linenum.ToString());while(true);}catch (Exception e){Console.WriteLine(Exception: e.Message);}finally{Console.WriteLine(Executing finally block.);}// */while(true);}
拆成50MB左右的文件后就可以使用notepad打开了打开后根据每一条的重要程度选择性恢复这里的回复只能自己手动回复的具体的办法是将里面损坏的部分删除后手动对齐格式把剩余能插入的数据再执行插入回数据库中。是一个手工的水磨细活。 4 总结
全部恢复耗时两个人24小时通宵解决了尽可能的减少了勒索病毒对公司的影响。
勒索病毒是对公司的损失是重大的本次勒索病毒我们自己总结如下经验
1首先杀毒系统要装有钱就买个卡巴斯基装上淘宝有便宜的没钱装一个360一定要有杀软
2内网别偷懒该划分vlan就划分vlan至少能做好数据隔离
3核心数据库资产一定要做一个云端备份可以用阿里云或者腾讯云的付费产品不要迷信本地备份我们就是本地备份顺着共享文件夹全部一锅端了三个备份机制全部失效。
4如果真的依靠本地备份就在vm exsi中做镜像级别的备份这个备份不会被干掉反之所有的windows级别的备份都会被勒索病毒干掉。