行业新闻

DDG的新征程——自研P2P协议构建混合P2P网络

DDG的新征程——自研P2P协议构建混合P2P网络

概述

DDG Mining Botnet 是一个活跃已久的挖矿僵尸网络,其主要的盈利方式是挖 XMR。从 2019.11 月份至今,我们的 Botnet 跟踪系统监控到 DDG Mining Botnet 一直在频繁跟新,其版本号和对应的更新时间如下图所示:

imgDDG Version Timeline

其中,v4005~v4011 版本最主要的更新是把以前以 Hex 形式硬编码进样本的 HubList 数据,改成了 Gob 序列化的方式;v5009 及以后的版本,则摒弃了以前基于 Memberlist 来构建 P2P 网络的方式,改用自研的 P2P 协议来构建混合模式 P2P 网络 。简化的网络结构如下:

imgP2P Hybrid Model

右边服务器是 Cip:port> 列表;

承载原始的恶意 Shell 脚本、主样本和其他组件的下载服务。

我们的 Botnet 跟踪系统追踪到 DDG 当前的 一部分 P2P Nodes(失陷主机),最近每天平均可以追踪到 900 个 Nodes,其中可验证存活的比例达 98%:

img

根据我们合作伙伴提供的统计数字,中国大陆境内活跃的 Bot 有17,590 个。根据我们的追踪数据,中国大陆境内的 Bot 数量约占总量的 86%,以此反推,DDG 目前在全球范围内的 Bot 数量约 20,000。

DDG 支持的传播途径,有以下 4 个:

SSH 服务暴破;

Redis 未授权访问漏洞;

针对 Nexus Repository Manager 3 RCE 漏洞(CVE-2019-7238)的利用;

针对 Supervisord RCE 漏洞(CVE-2017-11610)的利用。

根据我们的追踪数据,DDG 最近一段时间一直没有开启公网传播,而只利用 SSH 暴破在内网传播。其内网传播的开关,在 slave config 里设置:

img

另外,根据我们对 DDG 过去一年的追踪统计,它从 2019.1 月份至今共用了 24 个 Cip:port> 列表。Bot 可以与他们通信交换数据。

xhub 即 Cip:port> 列表,数据量比较大,共 0x8E2 Bytes:

img

而且 DDG 样本对 xSeeds 解析步骤与 xhub 的解析略有不同,经过分析,xSeeds 经过以下 3 层处理,而不用 ed25519 校验:

  1. msgpack 序列化编码;
  2. gzip 压缩
  3. 自定义 Alphabet 的 Base64 编码

xSeeds 数据的解析方法:

https://github.com/0xjiayu/DDGBotnetTracker/blob/master/v2/tools/dec_seeds.go

2.2.3 解析内置弱口令字典

在全局初始化函数 ddgs_global_init 中,DDG 调用了一个函数 ddgs_global_decodePasswords ,在这个函数中解密并校验内置的弱口令字典,这些弱口令将在后续传播阶段被用来暴破 SSH 服务(暴破 SSH 服务时用的用户名为 root ):

img

弱口令数据是经过 AES 加密、gzip 压缩后内置在样本中的,密文数据共 0x2BCFE Bytes:

img

DDG 会首先对上面数据用 gzip 解压,解压后密文数据结构如下:

img

DDG 会先用 ed25519 对上述密文数据的 Sha256 值进行校验(公钥与前面校验 xhub 时用的公钥相同),校验成功之后才会用 AES 算法将其解密,解密后得到一份 17,907 条密码的弱口令字典:

img

2.2.4 创建全局 ed25519 密钥对

在函数 ddgs_global_init 中,DDG 还有另外一项关键全局变量的初始化工作:创建一对全局 ed25519 密钥,用以在后续存取 BoltDB 中数据时对数据进行签名和校验:

img

创建密钥对的种子如下:

0x5C, 0x9E, 0xAE, 0xAE, 0x43, 0x26, 0xB7, 0xA2,
0x52, 0xDC, 0x43, 0xF9, 0xBD, 0x3F, 0xD1, 0xA6,
0xC8, 0xB0, 0x28, 0xE1, 0xDF, 0xA8, 0xB0, 0xF5,
0xCF, 0x43, 0xE7, 0x82, 0xD1, 0x90, 0x11, 0x6B

2.3 创建工作目录

旧版本的 DDG 会直接把当前用户的 HOME 目录作为自己的工作目录,主要是在此目录下创建隐藏的 BoltDB 文件,文件中存放 Hublist 数据(旧版本的 P2P Node List)。现在新版本的 DDG 会用特定算法生成目录名,并在 /var/lib//usr/local/ 目录下创建相应的隐藏目录。Go 语言实现的工作目录名生成算法如下(假设当前 DDG 二进制样本文件的路径为 /root/ddgs_x64):

https://github.com/0xjiayu/DDGBotnetTracker/blob/master/v2/tools/gen_workdir_name.go

上面程序的执行结果是 jsfc ,那么 DDG 就会尝试创建目录 /var/lib/.jsfc,后续工作目录的结构如下:

/var/lib/.jsfc
├── 5023
│  └── cache
│     └── static
│        ├── bb3
│        │  ├── busybox.x86_64
│        │  └── busybox.x86_64.sig
│        ├── wordpress
│        └── wordpress.sig
└── .local

其中 .local 文件即为 BoltDB 格式的文件,其它的还有从 C--> xhub

DDG 会首先向 xhub 如下 HTTP POST 请求:

img

以上 HTTP 通信中,

  • Request Header Host,即为事先随即生成的域名。值得一提的是,这个域名不会被 DNS 服务解析,因为以上 HTTP 通信是复用了已建立的 TCP Socket Session,在已有 TCP Socket 连接上 Send/Recv 数据并把数据用 HTTP 协议来解析而已。攻击者这样做,可能是为了逃避或混淆某些安全设备的流量检测;
  • Request Header X-Hub,即为 DDG 样本当前持有的硬编码在样本中的 xhub 信息,详见 2.2.2 节;
  • Request Header X-Port,即为 DDG 样本当前随即开启并监听的 P2P 通信端口;
  • Request Header X-Uid,即事先生成的 UID;
  • Request Header X-Relay,是 DDG 综合 X-UidX-Port 字段的值通过 Adler 算法算出来的校验值;
  • Response Header X-Seed,是对方从自己持有的 Peers 列表中随机选取的 20 个 Peers 地址列表信息,DDG 样本收到后会合入自身持有的 200 个 Peers 列表,总数不超过 200;
  • Response Header X-Hub,是对方持有的 xhub 信息,DDG 样本收到后会用它替换掉自身持有的 xhub 信息。

最后,HTTP 响应中的 jobs config 数据,是经过 msgpack 序列化编码后又用 AES 加密过的数据,数据的组织结构与 gzip 解压后的样本内置弱口令字典数据相同,解析过程也完全相同。最新解密后的 jobs config 数据见:

https://github.com/0xjiayu/DDGBotnetTracker/blob/master/v2/data/jobs.json

jobs Config 的内容来看,攻击者对 Bot 的行为控制的更为复杂精细,该配置文件的核心功能在流程图里已有说明,此处总结如下:

  • 针对每个低级版本 DDG 都有不同的处理,或 Kill 或 Discard 或 Upgrade;
  • 引入了 Busybox 执行更复杂的命令,主要用来干掉竞争对手;
  • 干掉竞争对手的姿势复杂多样,杀进程、禁用服务、清除 SSH Key、删除 Cron Jobs,重置 Lock File 等等,最显眼的是通过篡改 /etc/hosts 文件屏蔽一大批竞争对手需要访问的域名。

其中,最显眼的一部分配置,是 DDG 通过篡改 /etc/hosts 文件屏蔽竞争对手要访问的域名,大多数都是 LSDMinersystemdMiner 相关的域名:

LSDMiner    img.sobot.com
LSDMiner    lsdu.b-cdn.net
LSDMiner    thyrsi.com
LSDMiner    aliyun.one
systemdMiner    an7kmd2wp4xo7hpr.onion.sh
systemdMiner    an7kmd2wp4xo7hpr.tor2web.su
systemdMiner    aptgetgxqs3secda.onion.ly
systemdMiner    aptgetgxqs3secda.onion.pet
systemdMiner    dns.rubyfish.cn
systemdMiner    aptgetgxqs3secda.onion.in.net
systemdMiner    aptgetgxqs3secda.tor2web.fyi
systemdMiner    an7kmd2wp4xo7hpr.d2web.org
systemdMiner    an7kmd2wp4xo7hpr.timesync.su

3.3 Peer --> Peer

在与 xhub 通信过后,DDG 样本就开始与自身持有的 200 个 Peers 进行通信。 Peers 之间的通信有 4 个关键步骤:

  1. Ping/Pong
  2. 拉取对方的 slave config 和 jobs config;
  3. 拉取对方的其他恶意组件,比如恶意矿机程序和 Busybox 二进制程序;
  4. 响应(服务)别的 Peers 的以上 3 种请求

3.3.1 Ping/Pong

DDG 一旦成功与某个 Peer 建立连接,会至少经过 2 轮 Ping/Pong 通信,间隔 30s ,对端响应的 Pong 包与 Ping 包完全相同,长度为 3 Bytes

img

3 Bytes 的 Ping 包生成规则如下:

  • 第 1 字节为 0x00;
  • 第 3 字节在 (0, 0xFF] 中随机产生;
  • 第 2 字节为第 3 字节与 0x42 XOR 运算的结果。

Go 语言代码描述如下:

// Generate ping packet bytes
func GenPingbytes(globalRand *rand.Rand) []byte {
    pkt := make([]byte, 3)
    pkt[0] = 0x00
    pkt[2] = byte((globalRand.Intn(0xFE) + 1) & 0xFF)
    pkt[1] = (pkt[2] ^ 0x42) & 0xFF

    return pkt
}

3.3.2 传播 slave/jobs config data

经过 2 轮的 Ping/Pong 通信,DDG 会随机选成功通信的 Peers 向对方请求拉取 slave config 或 jobs config,请求方式类似于上面向 xhub 请求 jobs config,以拉取对方 slave config 为例:

img

img

值得注意的两点:

  1. DDG Peers 之间发送 HTTP Post 请求,HTTP Request Header 中相比请求 xhub 时少了一个 X-Port
  2. 发往 Peer 的 HTTP 请求,复用了前面 Ping/Pong 通信中用到的 TCP 连接,即同一个 TCP Session,刚开始用来 Ping/Pong 交互,后面直接基于这个 TCP Session 发送 HTTP 请求、接收 HTTP 响应,所以 HTTP Header 中 Host 字段里随机生成的域名并不会经过 DNS 解析

对端响应的 slave config 数据,是经 msgpack 序列化编码过的二进制数据,数据格式与旧版本变化不大,解码方式可以参考 以 P2P 的方式追踪 DDG 。最新解码后的 slave config 数据已上传到 Github:

https://github.com/0xjiayu/DDGBotnetTracker/blob/master/v2/data/slave.json

解码后的 slave config 数据包含自身数据的数字签名,DDG 样本会以此校验 slave config 数据,校验时用到的 RSA 公钥硬编码在样本中:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1+/izrOGcigBPC+oXnr2
S3JI76iXxqn7e9ONAmNS+m5nLQx2g0GW44TFtMHhDp1lPdUIui1b1odu36i7Cf0g
31vdYi1i6nGfXiI7UkHMsLVkGkxEknNL1c1vv0qE1b2i2o4TlcXHKHWOPu4xrpYY
m3Fqjni0n5+cQ8IIcVyjkX7ON0U1n8pQKRWOvrsPhO6tvJnLckK0P1ycGOcgNiBm
sdA5WDjw3sg4xWCQ9EEpMeB0H1UF/nv7AZQ0etncMxhiWoBxamuPWY/KS3wZStUd
gsMBOAOOpnbxL9N+II7uquQQkMmO6HriXRmjw14OmSBEoEcFMWF2j/0HPVasOcx2
xQIDAQAB
-----END PUBLIC KEY-----

3.3.3 下载恶意组件

没有被选中拉取 slave config 和 jobs config 的 Peer,DDG 会继续与他们的 Ping/Pong 通信。从某个 Peer 拉取的 slave config 中指定了恶意矿机程序 Miner 的下载 URI、本地存放路径和 MD5,DDG 接下来会随机选取另一个 Ping/Pong 中的 Peer,复用 Ping/Pong 的 TCP Session,通过 HTTP 协议向其发起 Miner 的下载请求:

img

下载到的恶意矿机程序,DDG 不仅会将其存放到 slave config 中指定的本地路径,还会连同 HTTP Response Header 中的 X-Sig 内容作为矿机程序的数字签名数据一起放到自己创建的工作目录中:

/var/lib/.jsfc
├── 5023
│  └── cache
│     └── static
│        ├── bb3
│        │  ├── busybox.x86_64
│        │  └── busybox.x86_64.sig
│        ├── wordpress
│        └── wordpress.sig
└── .local

DDG 从 Peer 下载已编译的 Busybox 程序的过程同上。

3.3.4 响应其他 Peers 的请求

P2P 协议中,Peers 之间的功能、角色是对等的。DDG 样本既然可以从其他 Peer 那里拉取数据和文件,自然也可以响应其他 Peer 的对等请求。

当 Peer 来请求 slave config或 jobs config 时,DDG 样本会从内存中整理好一份自己持有的数据,经过与前面阐述的解码、解密相反的编码、加密处理,返回给 Peer。

当 Peer 来请求下载矿机程序(比如上面的 wordpress 文件)或已编译好的 Busybox 程序时,DDG 样本会检查自己的工作目录cache 子目录中是否已经缓存了相应文件,如果缓存了相应文件并且签名有效,就会返回给 Peer。

另外的问题是,很多 DDG 控制的失陷主机都在内网,不一定可以穿透 NAT 对外提供这种服务。所以跟踪程序无法通过 P2P 机制跟踪到所有的 Bot。

3.3.5 Peers 之间的 Proxy 特性

DDG 的 P2P 机制中,还有一个有意思的特性:Peer 的 Proxy 功能。

当某个 Peer 来请求下载矿机程序或 Busybox 程序时,如果 DDG 经过检查发现自己工作目录中暂时不存在相应文件,它就会把自己作为一个 Proxy,向自己成功连接的其他 Peer 随机发送相应的下载请求。如果成功下载,就会返回给向自己请求下载文件的 Peer。

总结

DDG 经过两年多的发展,从最初简单的挖矿木马,到借用第三方协议框架构建简单的 P2P 网络,到现在自研 P2P 协议,已经演化成了一个复杂的 P2P 僵尸网络。可能这是第一个 P2P 结构的挖矿僵尸网络。如果你怀疑自己的主机被 DDG 入侵,建议从以下几个方面排查、处置:

  1. 检查 /var/spool/cron/root/var/spool/cron/crontabs/root 是否存在恶意 Cron Jobs
  2. 检查 ~/.ssh/authorized_keys 文件中是否存在恶意 SSH Public Key
  3. 检查 /var/lib/ , /usr/local/ 目录下的隐藏目录,是否存在 DDG 工作目录
  4. 检查 /usr/bin/, /usr/local/bin/ 目录下是否存在可疑 ELF 文件
  5. 检查 /etc/hosts 文件是否被写入恶意内容

IoCs

C&C:

67.205.168.20:8000

URLs:

http://67.205.168.20:8000/i.sh

http://67.205.168.20:8000/static/wordpress

http://67.205.168.20:8000/static/bb3/busybox.x86_64

http://67.205.168.20:8000/static/bb3/busybox.i686

MD5s:

5e2e0564ee03c743b50e4798c1041cea  5009/ddgs.i686
ea3d5d224ed7474159936f727db7555d  5009/ddgs.x86_64
05d7e2c36d5c58b26b00ca80ee7d8abe  5012/ddgs.i686
38fb3221d43d743a0de12d494ad60669  5012/ddgs.x86_64
91217bdbcc9f5663aac47b9fe803d4c7  5013/ddgs.i686
02e645c3bdd84d7a44b7aefc0f6d9e74  5013/ddgs.x86_64
5f4587df10ba4b3e7b46eb8b46d249bd  5014/ddgs.i686
e956e5b97cd0b73057980d735ee92974  5014/ddgs.x86_64
8e44e7a361c4d91c670072e049e6d729  5015/ddgs.i686
7f87c72701576da704056b38f6fae1ce  5015/ddgs.x86_64
6c164f25cabbcdc112192b1409ae73c5  5016/ddgs.i686
f84a0180ebf1596df4e8e8b8cfcedf63  5016/ddgs.x86_64
c2480ce231cc84130d878cb42bd072dd  5017/ddgs.i686
c8b416b148d461334ae52aa75c5bfa79  5017/ddgs.x86_64
66cd0c4c13670c32f43b0fd3304b0bf6  5018/ddgs.i686
dc87e9c91503cc8f2e8e3249cd0b52d7  5018/ddgs.x86_64
58c9a8561584dd1b70fbcb68b458f293  5019/ddgs.i686
682f839c1097af5fae75e0c5c39fa054  5019/ddgs.x86_64
28b2ee07f7a611d353efd8e037973bca  5020/ddgs.i686
495dfc4ba85fac2a93e7b3f19d12ea7d  5020/ddgs.x86_64
ffe204b87c5713733d5971e7479c0830  5021/ddgs.i686
d2a81a0284cdf5280103bee06d5fe928  5021/ddgs.x86_64
e2430bbeb49a11bfa30c6b01a28362c7  5022/ddgs.i686
e64b247d4cd9f8c58aedc708c822e84b  5022/ddgs.x86_64
d3a203cb0aa963529c0e4f8eccbf8c56  5023/ddgs.i686
2c4b9d01d2f244bb6530b48df99d04ae  5023/ddgs.x86_64

d146612bed765ba32200e0f97d0330c8  miner_1
d146612bed765ba32200e0f97d0330c8  miner_2

*本文作者:JiaYu@360netlab,转载请注明来自FreeBuf.COM

关闭