0x1 定位密码加密过程
在sql语句里有"passencode"函数, 搜索这个字符串可以看到passencode绑定到了sub_115D73F0这个函数
在sub_115D73F0中, 若没有登录会调用encryptProc_noLogin函数对密码进行加密(如前辈文章中所分析的),
如果登录了,则还会进入下面的流程对noLogin加密的结果再进行一层加密:
0x2 登录状态下的密码加密流程
本例中经过noLogin加密的结果: (4B01F200ED01)J1rQAkGUN4Jg4fsy+3FtFiHnCHKZnfw9aDpQLj1XbnY=
0x21 第一部分 (产生aes密钥)
-
将noLogin的加密结果与(51637587F6BB463a92D17DD7903A1F6F)字符串比较
-
之后通过全局变量获取一个随机字符串(randStr),并将randStr 和一个固定的字符串当作参数, 调用login_encrypt_one函数
-
跟进login_encrypt_one函数: 此函数内的加密算法都可以通过常量值和动态调试猜出来, 这里直接贴上ida重命名后的截图
整体逻辑为: ①先把randStr和constStr进行拼接 ②将拼接后的字符串进行sha256摘要 ③将sha256的结果再进行md5摘要运算 ④将md5的hex结果转为字符串返回
login_encrypt_one的结果将当作第二部分加密的密钥
0x22 第二部分 (对noLogin的加密结果再进行一层加密)
-
将noLogin加密的结果, 和第一部分login_encrypt_one的结果作为参数, 调用login_encrypt_two
-
跟进login_encrypt_two函数, 首先将noLgin加密的结果进行了奇偶混淆:
这一点通过ida也能看出来,跟进noLgEnCStrObfuscate函数体内, 反编译结果和未登录流程里的奇偶混淆代码反编译结果几乎一样:
-
之后进行aes加密(aes_128_ecb_pkcs7_encrypt): 密钥为第一部分(sha256+md5)结果的前16个字符
-
最后将aes加密的结果进行base64编码并拼接上(51637587F6BB463a92D17DD7903A1F6F):
-
结果
0x3 流程总结
问题在于要通过randStr来产生aes的密钥, randStr是怎么生成的
通过切换账号可以发现, randStr也会变化, 所以肯定和用户信息有关, 所以randStr的生成算法也就没必要逆向了
0x4 抓取randStr
脚本用于CobaltStrike
(1) Beacon为32位
会执行BOF, bof32GetRandStr.o, 从外部读取randStr
(2) Beacon为64位
写了个shellcode用来读取并保存, 因为从外部读取ReadProcMemory会失效(64位程序读32位程序? 具体什么原因没有深究),所以将shellcode注入到360safe.exe中同进程读取
randStr会保存在目标主机的C:\Users\Public\Downloads\360config.txt并会自动下载
(注入shellcode时一定要选择父进程的PID, 即没有任何命令行参数的进程)
(3) 下载assis2.db
登录用户的assis2.db并不在installPath\360se6\User Data\Default\apps\LoginAssis\assis2.db
而是在installPath\360se6\User Data\Default\idStr\assis2.db, 路径中的idStr与账号相关, 随机字串
所以需要手动下载
同时修改了前辈的c#代码, 支持解密登录状态的密码保存数据库 (详情见附件)