震驚,我被Redis入侵了
好吧,我也做了回標(biāo)題黨,像我這么細(xì)心的同學(xué),怎么可能讓服務(wù)器被入侵呢?
其實(shí)是這樣的,昨天我和一個(gè)朋友聊天,他說(shuō)他自己有一臺(tái)云服務(wù)器運(yùn)行了 Redis 數(shù)據(jù)庫(kù),有一天突然發(fā)現(xiàn)數(shù)據(jù)庫(kù)里的數(shù)據(jù)全沒(méi)了,只剩下一個(gè)奇奇怪怪的鍵值對(duì),其中值看起來(lái)像一個(gè) RSA 公鑰的字符串,他以為是誤操作刪庫(kù)了,幸好自己的服務(wù)器里沒(méi)啥重要的數(shù)據(jù),也就沒(méi)在意。
經(jīng)過(guò)一番攀談交心了解到,他跑了一個(gè)比較古老已經(jīng)停止維護(hù)的開(kāi)源項(xiàng)目,安裝的舊版本的 Redis,而且他對(duì) Linux 的使用不是很熟練。我就知道,他的服務(wù)器已經(jīng)被攻陷了,想到也許還會(huì)有不少像我這位朋友的人,不重視操作系統(tǒng)的權(quán)限、防火墻的設(shè)置和數(shù)據(jù)庫(kù)的保護(hù),我就寫(xiě)一篇文章簡(jiǎn)單看看這種情況出現(xiàn)的原因,以及如何防范。
PS:這種手法現(xiàn)在已經(jīng)行不通了,因?yàn)樾掳姹?Redis 都增加了 protect mode,增加了安全性,我們只能在本地簡(jiǎn)單模擬一下,就別亂試了。
事件經(jīng)過(guò)
其實(shí)這種攻擊手法都是 2015 年的事了,那時(shí)候 Redis 的安全保護(hù)機(jī)制比較差,只能靠運(yùn)維人員來(lái)合理配置以保證數(shù)據(jù)庫(kù)的安全。有段時(shí)間,全球幾萬(wàn)個(gè) Redis 節(jié)點(diǎn)遭到了攻擊,出現(xiàn)了上述奇怪的現(xiàn)象,所有數(shù)據(jù)被清空,只剩一個(gè)鍵叫 crackit,它的值形似 RSA 公鑰的字符串。
后來(lái)查證,攻擊者利用 Redis 動(dòng)態(tài)設(shè)置配置和數(shù)據(jù)持久化的功能,把自己的 RSA 公鑰寫(xiě)入到了被攻擊服務(wù)器的 /root/.ssh/authored_keys 這個(gè)文件,從而可以用私鑰直接登錄對(duì)方的 root 用戶,侵入對(duì)方系統(tǒng)。
淪陷的服務(wù)器安全防護(hù)做的很不好,具體如下:
- Redis 的端口是默認(rèn)端口,而且可以從公網(wǎng)訪問(wèn)。
- Redis 還沒(méi)設(shè)密碼。
- Redis 進(jìn)程是由 root 用戶啟動(dòng)的。
以上每個(gè)點(diǎn)都是比較危險(xiǎn)的,合在一起,那真是很致命了。且不說(shuō)別人把公鑰寫(xiě)到你的系統(tǒng)里,就說(shuō)連上你的數(shù)據(jù)庫(kù)然后刪庫(kù),那損失都?jí)虼罅恕D敲淳唧w的流程是什么呢,下面我在本地回環(huán)地址上簡(jiǎn)單演示一下。
本地演示
Redis 監(jiān)聽(tīng)的默認(rèn)端口是 6379,我們?cè)O(shè)置它接收網(wǎng)卡 127.0.0.1 的連接,這樣我從本地肯定可以連接 Redis,以此模擬「從公網(wǎng)可以訪問(wèn) Redis」這一條件。
現(xiàn)在我是名叫 fdl 的普通用戶,我想用 ssh 登錄我系統(tǒng)上的 root 用戶,要輸入 root 的密碼,我不知道,所以沒(méi)辦法登錄。
除了密碼登錄之外,還可以使用 RSA 密鑰對(duì)登錄,但是必須要把我的公鑰存到 root 的家目錄中 /root/.ssh/authored_keys。我們知道 /root 目錄的權(quán)限設(shè)置是不允許任何其他用戶闖入讀寫(xiě)的:

但是,我發(fā)現(xiàn)自己竟然可以直接訪問(wèn) Redis:

如果 Redis 是以 root 的身份運(yùn)行的,那么我就可以通過(guò)操作 Redis,讓它把我的公鑰寫(xiě)到 root 的家目錄中。Redis 有一種持久化方式是生成 RDB 文件,其中會(huì)包含原始數(shù)據(jù)。
我露出了邪惡的微笑,先把 Redis 中的數(shù)據(jù)全部清空,然后把我的 RSA 公鑰寫(xiě)到數(shù)據(jù)庫(kù)里,這里在開(kāi)頭和結(jié)尾加換行符目的是避免 RDB 文件生成過(guò)程中損壞到公鑰字符串:

命令 Redis 把生成的數(shù)據(jù)文件保存到 /root/.ssh/ 中的 authored_keys 文件中:

現(xiàn)在,root 的家目錄中已經(jīng)包含了我們的 RSA 公鑰,我們現(xiàn)在可以通過(guò)密鑰對(duì)登錄進(jìn) root 了:

看一下剛才寫(xiě)入 root 家的公鑰:

亂碼是 GDB 文件的某種編碼吧,但是中間的公鑰被完整保存了,而且 ssh 登錄程序竟然也識(shí)別了這段被亂碼包圍的公鑰!
至此,擁有了 root 權(quán)限,就可以為所欲為了。。。
吸取教訓(xùn)
雖然現(xiàn)在基本不會(huì)受到這種攻擊(新版本的 Redis 沒(méi)有密碼時(shí)默認(rèn)不對(duì)外網(wǎng)開(kāi)放),但是對(duì)于系統(tǒng)的安全性是每個(gè)人都應(yīng)該重視的。
我們自己折騰東西,用個(gè)低配云服務(wù)器,為了省事兒一般也不認(rèn)真配置防火墻,數(shù)據(jù)庫(kù)不設(shè)密碼或者設(shè)成 admin、root 這樣簡(jiǎn)單的密碼,反正也沒(méi)啥數(shù)據(jù)。這樣肯定不是個(gè)好習(xí)慣。
現(xiàn)在我們的計(jì)算機(jī)系統(tǒng)越來(lái)越完善,每個(gè)成熟的項(xiàng)目都由最優(yōu)秀的一幫人維護(hù),從技術(shù)上說(shuō)應(yīng)該算是無(wú)懈可擊了,那么唯一可能出問(wèn)題的地方就在于使用它們的人。
就像經(jīng)常看到有人的 QQ 被盜,我相信盜號(hào)的人肯定不是跑到騰訊的數(shù)據(jù)庫(kù)里盜號(hào),肯定是 QQ 號(hào)主安全防范意識(shí)差,在哪個(gè)釣魚(yú)網(wǎng)站輸入了自己的賬號(hào)密碼,導(dǎo)致被盜。我基本沒(méi)見(jiàn)過(guò)微信被盜的,可能是微信弱化密碼登錄,改用二維碼掃描登錄的原因。這應(yīng)該也算是一種安全方面的考量吧,畢竟微信是有支付功能的。
上面這種騙局對(duì)于技術(shù)人來(lái)說(shuō),看看 url,瀏覽器分析一下網(wǎng)絡(luò)包就很容易識(shí)別出來(lái),但是你還別不信,一般人真的搞不明白怎么識(shí)別釣魚(yú)網(wǎng)站和官方網(wǎng)站。就像我真沒(méi)想到都 2020 年了,還有人在找 Redis 的這個(gè)漏洞,而且還有人中招。。。
那么說(shuō)回 Redis 數(shù)據(jù)庫(kù)的使用,在官網(wǎng)上明確寫(xiě)出了安全防護(hù)的建議,我簡(jiǎn)單總結(jié)一下吧:
- 不要用 root 用戶啟動(dòng) Redis Server,而且一定要設(shè)置密碼,而且密碼不要太短,否則容易被暴力破解。
- 配置服務(wù)器防火墻和 Redis 的 config 文件,盡量不要讓 Redis 與外界接觸。
- 利用 rename 功能偽裝 flushall 這種危險(xiǎn)命令,以防被刪庫(kù),丟失數(shù)據(jù)。