1. 程式人生 > >WF曲速未來訊息:仔細觀察OpenSSH使用者的列舉漏洞

WF曲速未來訊息:仔細觀察OpenSSH使用者的列舉漏洞

介紹

OpenSSH使用者通過GitHub提交公開列舉漏洞(CVE-2018-15473)。

此漏洞不會生成有效使用者名稱列表,但它允許猜測使用者名稱。

WF曲速區將在這篇文章中講解這個漏洞並提出了緩解和監控措施。

技術細節

WF曲速未來表示此漏洞在OpenSSH的多個身份驗證功能中體現出來。然後仔細研究了Ubuntu的OpenSSH實現公鑰身份認證中的這個漏洞。

通過向OpenSSH伺服器傳送格式錯誤的公鑰身份認證訊息,可以確定是否存在特定使用者名稱。如果使用者不存在,則將向客戶端傳送身份驗證失敗訊息。如果使用者存在,則無法解析訊息將中止通訊:連線將關閉而不發回任何訊息。此漏洞利用在Python PoC指令碼中實現。

該漏洞的存在是因為在完全解析訊息之前,會發生有關使用者名稱不存在的通訊。修復漏洞本質上很簡單:反轉邏輯。首先完全解析訊息,然後進行通訊。

測試PoC的一種方法是在除錯模式下啟動OpenSSH伺服器:

之後,使用現有使用者名稱執行PoC指令碼:

在伺服器端,將發生錯誤:

也可以在/var/log/auth.log中找到此錯誤:

無法解析訊息導致客戶端和伺服器之間的連線關閉而沒有來自伺服器的訊息:

請注意,最後一個數據包是粉紅色的(即客戶端資料包),沒有後續的藍色資料包(即伺服器資料包)。

使用不存在的使用者名稱執行PoC指令碼時:

沒有出現“不完整訊息”錯誤:

伺服器向客戶端發回訊息:

注意通訊結束時的藍色伺服器資料包。

這就是如何利用公鑰認證中的漏洞來披露使用者名稱的有效性。

當然,OpenSSH的行為在原始碼中定義。函式userauth_pubkey是已實現的身份驗證功能之一,特定於通過公鑰進行身份驗證。驗證失敗時返回0,驗證成功時返回1。當收到訊息SSH2_MSG_USERAUTH_REQUEST(型別為publickey)時呼叫它,之後結果用於將訊息SSH2_MSG_USERAUTH_FAILURE或SSH2_MSG_USERAUTH_SUCCESS傳送回客戶端。

該函式的邏輯如下:

  1. 如果使用者名稱不明確 - > 0
  2. 如果已知使用者名稱的金鑰不正確 - > 0
  3. 如果已知使用者名稱正確金鑰 - > 1

這可能是因為函式packet_get_string:

如果存在使用者名稱,則在步驟1之後將從訊息中提取欄位。

要提取的第一個欄位是布林值(1個位元組),帶有函式packet_get_char()。當認證型別為publickey時,該欄位等於1。接下來是2個字串:演算法和金鑰。在SSH訊息中,字串被編碼為長度值對。字串由4個位元組(字串的長度)組成,後跟包含字串的可變位元組數(等於長度)。長度編碼為bigendian,即首先放置4位元組整數的最高有效位元組,然後是較低有效位元組。

函式packet_get_string從訊息中提取字串,同時驗證它,即檢查指定的長度是否正確。此功能依賴於其他功能:

首先有一個函式ssh_packet_get_string的定義:

函式ssh_packet_get_string呼叫函式sshpkt_get_string,如果其返回值不為0,則呼叫函式致命。函式致命記錄致命錯誤事件,然後終止生成的OpenSSH程序,而不發回任何訊息。

現在跟隨另一個函式鏈:函式sshpkt_get_string呼叫sshbuf_get_string:

sshbuf_get_string呼叫sshbuf_get_string_direct:

sshbuf_get_string_direct呼叫sshbuf_peek_string_direct:

最後,sshbuf_peek_string_direct執行字串驗證:

如果訊息中的剩餘資料小於4個位元組(因此不能包含字串的長度),或者訊息中的剩餘資料小於訊息的長度,則返回錯誤SSH_ERR_MESSAGE_INCOMPLETE(在日誌中找到的訊息)字串。

總結這一系列函式:當packet_get_string用於從訊息中提取字串時,如果字串格式錯誤,則會發生致命異常,從而導致OpenSSH程序終止。

這正是PoC Python指令碼觸發的內容。首先,它與OpenSSH伺服器建立加密連線,然後傳送格式錯誤的SSH2_MSG_USERAUTH_REQUEST(型別公鑰)訊息。該指令碼將Paramiko的add_boolean函式重新定義為NULL函式。Paramiko是用於SSH通訊的Python模組。通過重新定義add_boolean函式,訊息中省略了布林欄位(就在演算法和鍵字串欄位之前)。

當函式userauth_pubkey解析此格式錯誤的訊息時,首先讀取布林欄位。由於該欄位實際上是丟失的,因此讀取下一個欄位的第一個位元組(函式packet_get_char):演算法字串的4位元組長度的最高有效位元組。呼叫下一個函式packet_get_string來讀取(並驗證)演算法字串。由於缺少布林欄位,這將失敗。

以下是格式良好的訊息的解析:

對於格式錯誤的訊息,缺少布林值。解析函式當然不知道這一點,因此它將字串的第一個位元組解析為布林欄位:它看起來像訊息向左移一個位元組:

結果是解析了1907位元組的字串長度(0x00000773十六進位制),這比訊息本身長。因此,函式ssh_packet_get_string將呼叫函式致命以導致OpenSSH程序終止。

漏洞摘要

這是一個微妙的錯誤。它不是緩衝區溢位導致遠端程式碼執行或缺少輸入驗證。

沒有緩衝區溢位,所有輸入在使用前都經過驗證。這裡的問題是輸入驗證在一些功能處理已經發生之後發生:可能出於效能原因,首先檢查使用者名稱以檢視它是否存在。如果它不存在,則不必進行進一步的輸入驗證和處理。

使用現有使用者名稱,將進行輸入驗證,並且可以在不傳送訊息的情況下關閉連線。這可用於匯出使用者名稱的存在。

這個問題的解決方案很簡單:在任何功能處理之前切換順序並首先進行所有輸入驗證。

在其他身份驗證功能中可能會出現相同的錯誤。檢查這個的粗略,不完整的方法是檢查表示式“!authctc-> valid”,如下所示:

確實在基於主機的身份驗證中犯了同樣的錯誤(可以在GitHub提交中看到):

和Kerberos身份驗證:

並且可能是SSH1 RSA身份驗證(我們還沒有進一步檢查,因為它在OpenBSD等實現中不再存在):

請注意,評論甚至警告這種風險!

結論

根據你對OpenSSH的使用,可以減輕此漏洞。區塊鏈安全公司WF曲速未來提醒在修補程式可用並部署之前,可以禁用易受攻擊的身份驗證機制。例如,通過禁用公鑰身份驗證,PoC指令碼不再有效,因為拒絕了格式錯誤的身份驗證請求。

當然,如果你不使用公鑰認證,我們只建議你禁用公鑰認證。如果你使用它,請不要切換到密碼驗證,但繼續使用公鑰驗證!這不是遠端執行程式碼漏洞,而是一個資訊洩露漏洞。

你還可以檢查日誌中是否有利用此漏洞的跡象。致命錯誤可能是一個跡象。在Ubuntu上使用此PoC,致命錯誤是“不完整的訊息”。但是,此訊息可能略有不同,具體取決於你的OpenSSH版本,還有其他方法可生成格式錯誤的訊息,這可能會導致另一個致命錯誤。例如,可以建立一個字串長度超過最大允許值的身份驗證請求。

在預設配置中,你只會收到此致命錯誤。例如,不會記錄客戶端的IP地址。可以通過將日誌級別(LogLevel)從INFO增加到VERBOSE來包含此資訊:這將建立額外的日誌條目,其中包含客戶端的IP地址。請注意,這將生成更大的日誌,並且你應該監視日誌不會超過你的容量。