Clarifications on the Incapsula Redis security report

Salvatore Sanfilippo

關於 Incapsula Redis 安全性報告的澄清

幾天前,我一早打開 Twitter,動態牆上滿是標題類似「75% 的 Redis 伺服器感染惡意軟體」的文章。這個明顯的誤引,指的是 Incapsula 的一項研究,他們發現那些在網際網路上完全開放、沒有任何防護、直接以公開 IP 位址暴露的 Redis 執行個體中,有 75% 已遭到感染 [1]。

[1] https://www.incapsula.com/blog/report-75-of-open-redis-servers-are-infected.html

許多人其實不需要對此多做說明,因為只要對電腦安全和 Redis 運作方式有一定了解,就能輕易掌握整件事的脈絡。不過我寫這篇部落格文章有兩個原因。最顯而易見的原因是,它能幫助媒體以及對安全和/或 Redis 不太熟悉的其他使用者理解究竟發生了什麼事。第二個原因是,暴露在外的 Redis 執行個體是關於 safe defaults(安全預設值) 的一個案例研究,對資安圈來說應該頗具參考價值。

Incapsula 報告

先從 Incapsula 的報告談起。他們做的是分析暴露在網際網路上的 Redis 執行個體。這些執行個體由於在公開 IP 位址上監聽連線,且沒有任何密碼保護,因此網際網路上的任何人、從任何地方都能存取。這就好像它們是 HTTP 伺服器一樣,只不過這裡跑的是 Redis,而 Redis 並非設計來以這種方式暴露在外的。

這並不是什麼新鮮事。由於 Redis 非常受歡迎,整體安裝數量相當龐大,其中有一小部分安裝就這樣被暴露在外。基本上從一開始就是如此。人們在某個雲端服務商上建立一台虛擬機器、安裝 Redis,發現無法連線,就把虛擬機器的連接埠對所有人開放,此時該執行個體就在毫無防護的狀態下運行。唯一改變的是,過去大多數此類執行個體在許多情況下即使暴露也相安無事。頂多有些 script kiddie(腳本小子)會連上來執行「INFO」或其他幾個指令,看看裡面有什麼內容,大多時候也就僅此而已。而如今,對 crypto mining(加密貨幣挖礦)的狂熱給了攻擊者一個非常充分的理由去入侵他人的系統。其實是最充分的理由:金錢。因此,同樣那些暴露的執行個體,現在被入侵並被安裝某種用來挖掘加密貨幣的軟體。Incapsula 調查的就是看起來已遭入侵的執行個體比例。

他們收集針對 Redis 執行個體的攻擊手法的方式,是刻意運行一組暴露的執行個體,以監控攻擊者如何對其下手。許多攻擊看起來都是我自己示範的攻擊範例 [2] 的變體。

[2] http://antirez.com/news/96

另外值得注意的是,要掃描整個 IPv4 位址空間以找出任何種類服務的暴露執行個體,是輕而易舉的事。例如,你可以使用 masscan。不過,20 年前你也可以用我自己寫的 hping 做到這件事,而且我記得當時確實成功做到了。

TLDR:網際網路上存在開放的 Redis 執行個體,是因為它們被錯誤設定。攻擊者藉由安裝某種挖礦軟體或其他方式從中獲利。但還有更多內情……請繼續讀下去。

Protected mode(保護模式)

在我看來,資安是個很糟的領域。我曾在這個領域工作過,一旦它不再是地下圈子的事情,我就決定離開。人們對於安全議題往往意見強烈,但同時,卻很少有人真正關心——例如——對真實世界的系統進行安全稽核(順帶一提,Google Project Zero 正在稍稍改變這一點)。因此,在第 N 次收到以 PGP 加密、聲稱 Redis 存在暫存檔建立攻擊弱點的電子郵件後,我寫了 [2] 那篇部落格文章,只是想說:「也許你們搞錯了 Redis 安全的重點」。我基本上公開了一個針對自己系統的攻擊手法,那是我花幾分鐘研究就找到的,而且非常嚴重。訊息還是一樣,Redis 並非設計來暴露在外的。如果你真的想耍 hack3rzzz 那一套,還有更有意思的事情可以做。然而,這麼做卻把一個強大的武器交到了腳本小子們手上,讓他們得以入侵數以千計暴露在各地的 Redis 執行個體。

為了彌補我的過失、試圖贖罪,我開始思考能做些什麼來讓情況變得簡單一些。Redis 3.x 的一個問題是,預設會監聽所有 IP 位址,因此很容易設定錯誤:只要把連接埠開放,或是完全沒有防火牆,執行個體就會暴露。那時關於安全的口頭禪是「run with safe defaults」。以 Redis 這個網路化快取來說,這意味著預設組態基本上開箱即用就無法滿足大多數真實世界使用者的需求。更糟的是,完全不懂的人會直接用「bind *」來解決問題,於是又回到最初的狀態。因此,我試著找出一個更聰明一點的方法,也就是我命名為「protected mode」的功能,讓一群 386 處理器在我家門前抗議了好幾天,大失所望。

protected mode 的概念是,仍然監聽所有位址,但如果連線並非來自本機,伺服器會回覆一個錯誤訊息,說明*為何*無法如預期般運作、該怎麼做,以及僅僅為了把執行個體對所有人開放而停用 protected mode 這種愚蠢做法所涉及的風險。以下是該功能運作方式的範例:

$ nc 192.168.1.194 6379
-DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.

這樣做的好處在於:

  1. 使用者知道該如何解決這個狀況。這比單純的「connection refused」好得多。
  2. 我們試圖避免使用者在不了解所涉風險的情況下就停用 protected mode,而且讓他們知道還有其他解決方案(設定密碼或綁定特定介面)。

幻滅

因此,我的幻想是,也許它能比 safe defaults 更有幫助。但不幸的是,你無法改變一個事實:有一部分使用者根本不在乎,有些人甚至不知道自己正在安裝 Redis,它只是作為其他東西的相依套件而附帶出現,或是由腳本安裝,或是包含在你正在執行的 ABI 映像檔中,諸如此類。

一開始透過在 Shodan 上搜尋,看起來 Redis 4.0 的 protected mode 確實幫了很大的忙!我能找到的開放執行個體大多回覆「-DENIED」。那很棒。然而在 [1] 發表後,我請 Shodan(順帶一提,他們超棒,在 Twitter 上非常熱心幫忙)提供暴露的 Redis 執行個體的版本分布。結果是,仍然有大量的 Redis 4.0 執行個體暴露在外 [3]。

[3] https://asciinema.org/a/8heQvivQkFmUrisbb9FQLfMBj

誠然,它們的數量比 3.0 的執行個體少,但仍然很多。進一步調查後,我甚至被告知,有些 VM 映像檔的安裝腳本預設就會 *移除* Redis 的 protected mode,因為有時人們會被安全功能搞得很煩。他們希望東西開箱即用就能在網路上運作,所以就這麼做,把惱人的東西拿掉。然後這樣的映像檔變得熱門,許多人在不知情的狀況下安裝它,而當安裝 Redis 4 時,protected mode 是關閉的,執行個體也就暴露了。

我認為這是關於可被使用者輕易停用的 safe defaults 的一個教訓。看起來它們在某種程度上確實有幫助,但僅止於將事件數量降低若干百分比,而無法讓此類事件成為罕見的例外。

下一步是什麼?

Redis 安全模型中的一個根本問題是,伺服器可以透過一般的 API,使用像 CONFIG 指令這類特殊指令來重新設定。這是 Redis 一項非常有價值的功能,但一旦取得 Redis API 的存取權限,就會讓入侵執行個體變得更加容易,而一般使用 Redis 的應用程式其實不需要這種層級的存取權限。

因此,在 Redis 6 的開發過程中,我們將引入 ACLs(存取控制清單)。同樣地,這項功能的導入方式將盡量讓現有使用者「無痛」體驗。如果你在沒有任何憑證的情況下連線,Redis 會自動使用「default」使用者為客戶端登入,該使用者可以執行應用程式通常會做的所有事情,但會拒絕所有管理指令。當然,也可以透過不同的設定讓它更嚴格,建立只能對符合特定模式的鍵執行特定指令的新使用者,諸如此類。

在 Redis 6 的開發過程中,我們也計畫合併對 SSL 連線的支援,雖然這不太可能對此處討論的問題產生任何影響,因為預設情況下 Redis 仍將以未加密方式運行,且此功能為選擇性加入(opt-in),不過在某些環境中,SSL 也是邁向更安全的 Redis 體驗的一步。

然而,我的希望寄託在 ACLs 上,因為看起來一般使用者不太可能讓 default 帳號擁有執行管理指令的權限。尤其是因為我們計畫將來自本機主機的連線直接以「admin」使用者的身分登入。如果一切如我所願,我們仍會繼續看到暴露的 Redis 6 執行個體,因為這是無可避免的,但至少那些 Redis 6 執行個體應該會讓入侵整個系統變得更加困難。至少在理論上是如此:Redis 的 EVAL 指令允許執行 Lua 腳本,而這項功能應該會預設保持開放,因為它是 Redis 的一項基本功能。我們試圖提供一種有點沙箱化的 Lua 執行環境,但如果你關注 IT 安全已有一段時間,你就會知道沙箱始終是不完美的,與其說是封閉的解決方案,不如說更像是一場尋找如何逃脫的練習。不過這一次,我會避免僅僅為了證明觀點就公開攻擊手法。

原文由 Salvatore Sanfilippo 發布

本文章由 muse-spark-1.2-contributor 進行翻譯