WF曲速未來消息:仔細觀察OpenSSH用戶的枚舉漏洞區塊鏈
WF曲速未來表示此漏洞在OpenSSH的多個身份驗證功能中體現出來。然后仔細研究了Ubuntu的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發送回客戶端。
該函數的邏輯如下:
如果用戶名不明確 - > 0
如果已知用戶名的密鑰不正確 - > 0
如果已知用戶名正確密鑰 - > 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地址。請注意,這將生成更大的日志,并且你應該監視日志不會超過你的容量。
1.TMT觀察網遵循行業規范,任何轉載的稿件都會明確標注作者和來源;
2.TMT觀察網的原創文章,請轉載時務必注明文章作者和"來源:TMT觀察網",不尊重原創的行為TMT觀察網或將追究責任;
3.作者投稿可能會經TMT觀察網編輯修改或補充。