漏洞分析:OpenSSH使用者列舉漏洞(CVE-2018-15473)分析
Line"/>
介紹
這個漏洞雖然不能生成有效使用者名稱列表,但是它可以允許攻擊者猜測使用者名稱。目前這個OpenSSH使用者列舉漏洞( CVE-2018-15473" ref="nofollow" rel="nofollow,noindex" target="_blank">CVE-2018-15473 )的詳細資訊已經上傳至了GitHub,感興趣的同學可以自行檢視【 傳送門 】。
在這篇文章中,我們將對該漏洞進行深入分析,並提供一些可行的緩解方案。
技術細節
這個漏洞存在於OpenSSH所實現的一些認證功能之中,首先我們一起看一看Ubuntu OpenSSH的公共金鑰認證漏洞。
通過向一臺OpenSSH伺服器傳送惡意的公共金鑰認證訊息,攻擊者將能夠獲取特定的使用者名稱資訊。如果使用者不存在,伺服器將會向客戶端傳送認證失敗的訊息。如果使用者存在,訊息將無法解析並終止通訊,即通訊連線會在沒有任何訊息回傳的情況下斷開。關於該漏洞的漏洞利用程式碼可以從這個Python PoC指令碼中獲取:【 傳送門 】。
這個漏洞之所以存在,是因為伺服器在對訊息完整解析之前,使用者查詢了不存在的使用者名稱。想要修復該漏洞也很簡單,按攻擊邏輯反著來就行了:首先對訊息進行完整解析,然後再建立通訊連線。
測試漏洞利用PoC的一種方法就是在除錯模式下開啟OpenSSH伺服器:
然後用已存在的有效使用者名稱執行PoC指令碼:
在伺服器端將會檢視到錯誤提示:
相關錯誤資訊還可以在/var/log/auth.log中找到:
如果無法正確解析訊息,會導致客戶端跟伺服器端之間的通訊中斷,而且中斷時不會收到伺服器傳送的提示資訊:
注意粉紅色標記的最後一個數據包(客戶端資料包),這裡沒有後續的藍色資料包(伺服器資料包)。
當PoC指令碼以不存在的使用者名稱執行之後:
不會彈出“imcomplete message”錯誤提示:
注意通訊資料結尾處的藍色伺服器資料包。
這就是該漏洞(公共金鑰認證漏洞)暴露有效使用者名稱的整個流程了。
其中,userauth_pubkey函式是認證功能所實現的其中一個函式,專門用於根據公共金鑰來完成身份驗證。如果認證失敗,則返回“0”,成功則返回“1”。當伺服器端接收到了SSH2_MSG_USERAUTH_REQUEST請求後,便會呼叫該函式,之後的結果會用來給客戶端回傳SSH2_MSG_USERAUTH_FAILURE或SSH2_MSG_USERAUTH_SUCCESS訊息。
該函式的執行邏輯為:
1. 如果使用者名稱不存在:返回“0”; 2. 如果使用者名稱存在但金鑰錯誤:返回“0”; 3. 如果使用者名稱存在且金鑰正確:返回“1”;
但是有人發現,我們竟然可以在第一步和第二步中間終止userauth_pubkey函式的執行。第一步執行完後,userauth_pubkey函式會從客戶端獲取訊息字串,如果獲取失敗(惡意字串導致),整個過程都會終止,並在不傳送任何回傳訊息的情況下關閉連線。
packet_get_string所導致的情況如下:
如果使用者名稱存在,第一步會在程式從訊息域中提取完資料後進行。
第一個提取的資料域是一個布林值(1位元組),對應函式為packet_get_char()。如果認證型別為publickey,返回值就是“1”。後續跟著的是兩個字串:演算法和金鑰。在SSH訊息中,字串會以一個“長度-值“鍵值對進行編碼,一個字串為4個位元組。
函式packet_get_string可以從訊息中提取字串,並對其進行驗證,這個函式還需要依賴另一個函式:ssh_ssh_packet_get_string。
ssh_packet_get_string函式會呼叫sshpkt_get_string函式,如果返回的值不是“0”,它還會呼叫fatal函式。函式fatal會記錄致命的錯誤事件,然後終止生成的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 錯誤訊息。這就是我們之前那個Python PoC指令碼所要觸發的東西。首先,它會跟OpenSSH伺服器建立一條加密的通訊連結,然後向其傳送惡意的SSH2_MSG_USERAUTH_REQUEST訊息。通過重定義add_boolean函式,訊息中的布林值域會被忽略。
當函式userauth_pubkey解析了惡意訊息之後,首先會讀取布林值域,由於這個域其實是不存在的,因此讀取的會是下一個域(函式packet_get_char):加密演算法字串的4位元組長度值。然後呼叫下一個函式packet_get_string來讀取加密演算法字串。
下面是解析合法訊息的過程:
下面是解析惡意訊息的過程:
結果就是,程式碼解析了一個1907位元組的字串(十六進位制為0×00000773),這比整個訊息的長度還要長,這會導致ssh_packet_get_string呼叫fatal函式,並中斷OpenSSH程序。
漏洞總結
這是一個非常隱蔽的漏洞,它不是一個緩衝區溢位漏洞,也不是遠端程式碼執行漏洞,更不是錯誤輸入驗證漏洞。這裡不存在任何的緩衝區溢位問題,所有的輸入都在使用之前進行了驗證。問題就是,輸入驗證是在進行了一些函式處理之後完成的。
問題的解決方法也比較簡單:更換函式的呼叫順序即可,也就是首先進行輸入驗證,然後再進行函式處理就可以了。
* 參考來源: nviso ,FB小編Alpha_h4ck編譯,轉載請註明來自FreeBuf.COM