WF曲速未來消息:仔細(xì)觀察OpenSSH用戶的枚舉漏洞區(qū)塊鏈
WF曲速未來表示此漏洞在OpenSSH的多個(gè)身份驗(yàn)證功能中體現(xiàn)出來。然后仔細(xì)研究了Ubuntu的OpenSSH實(shí)現(xiàn)公鑰身份認(rèn)證中的這個(gè)漏洞。
介紹
OpenSSH用戶通過GitHub提交公開枚舉漏洞(CVE-2018-15473)。
此漏洞不會(huì)生成有效用戶名列表,但它允許猜測用戶名。
WF曲速區(qū)將在這篇文章中講解這個(gè)漏洞并提出了緩解和監(jiān)控措施。
技術(shù)細(xì)節(jié)
WF曲速未來表示此漏洞在OpenSSH的多個(gè)身份驗(yàn)證功能中體現(xiàn)出來。然后仔細(xì)研究了Ubuntu的OpenSSH實(shí)現(xiàn)公鑰身份認(rèn)證中的這個(gè)漏洞。
通過向OpenSSH服務(wù)器發(fā)送格式錯(cuò)誤的公鑰身份認(rèn)證消息,可以確定是否存在特定用戶名。如果用戶不存在,則將向客戶端發(fā)送身份驗(yàn)證失敗消息。如果用戶存在,則無法解析消息將中止通信:連接將關(guān)閉而不發(fā)回任何消息。此漏洞利用在Python PoC腳本中實(shí)現(xiàn)。
該漏洞的存在是因?yàn)樵谕耆馕鱿⒅埃瑫?huì)發(fā)生有關(guān)用戶名不存在的通信。修復(fù)漏洞本質(zhì)上很簡單:反轉(zhuǎn)邏輯。首先完全解析消息,然后進(jìn)行通信。
測試PoC的一種方法是在調(diào)試模式下啟動(dòng)OpenSSH服務(wù)器:
之后,使用現(xiàn)有用戶名運(yùn)行PoC腳本:
在服務(wù)器端,將發(fā)生錯(cuò)誤:
也可以在/var/log/auth.log中找到此錯(cuò)誤:
無法解析消息導(dǎo)致客戶端和服務(wù)器之間的連接關(guān)閉而沒有來自服務(wù)器的消息:
請注意,最后一個(gè)數(shù)據(jù)包是粉紅色的(即客戶端數(shù)據(jù)包),沒有后續(xù)的藍(lán)色數(shù)據(jù)包(即服務(wù)器數(shù)據(jù)包)。
使用不存在的用戶名執(zhí)行PoC腳本時(shí):
沒有出現(xiàn)“不完整消息”錯(cuò)誤:
服務(wù)器向客戶端發(fā)回消息:
注意通信結(jié)束時(shí)的藍(lán)色服務(wù)器數(shù)據(jù)包。
這就是如何利用公鑰認(rèn)證中的漏洞來披露用戶名的有效性。
當(dāng)然,OpenSSH的行為在源代碼中定義。函數(shù)userauth_pubkey是已實(shí)現(xiàn)的身份驗(yàn)證功能之一,特定于通過公鑰進(jìn)行身份驗(yàn)證。驗(yàn)證失敗時(shí)返回0,驗(yàn)證成功時(shí)返回1。當(dāng)收到消息SSH2_MSG_USERAUTH_REQUEST(類型為publickey)時(shí)調(diào)用它,之后結(jié)果用于將消息SSH2_MSG_USERAUTH_FAILURE或SSH2_MSG_USERAUTH_SUCCESS發(fā)送回客戶端。
該函數(shù)的邏輯如下:
如果用戶名不明確 - > 0
如果已知用戶名的密鑰不正確 - > 0
如果已知用戶名正確密鑰 - > 1
這可能是因?yàn)楹瘮?shù)packet_get_string:
如果存在用戶名,則在步驟1之后將從消息中提取字段。
要提取的第一個(gè)字段是布爾值(1個(gè)字節(jié)),帶有函數(shù)packet_get_char()。當(dāng)認(rèn)證類型為publickey時(shí),該字段等于1。接下來是2個(gè)字符串:算法和密鑰。在SSH消息中,字符串被編碼為長度值對。字符串由4個(gè)字節(jié)(字符串的長度)組成,后跟包含字符串的可變字節(jié)數(shù)(等于長度)。長度編碼為bigendian,即首先放置4字節(jié)整數(shù)的最高有效字節(jié),然后是較低有效字節(jié)。
函數(shù)packet_get_string從消息中提取字符串,同時(shí)驗(yàn)證它,即檢查指定的長度是否正確。此功能依賴于其他功能:
首先有一個(gè)函數(shù)ssh_packet_get_string的定義:
函數(shù)ssh_packet_get_string調(diào)用函數(shù)sshpkt_get_string,如果其返回值不為0,則調(diào)用函數(shù)致命。函數(shù)致命記錄致命錯(cuò)誤事件,然后終止生成的OpenSSH進(jìn)程,而不發(fā)回任何消息。
現(xiàn)在跟隨另一個(gè)函數(shù)鏈:函數(shù)sshpkt_get_string調(diào)用sshbuf_get_string:
sshbuf_get_string調(diào)用sshbuf_get_string_direct:
sshbuf_get_string_direct調(diào)用sshbuf_peek_string_direct:
最后,sshbuf_peek_string_direct執(zhí)行字符串驗(yàn)證:
如果消息中的剩余數(shù)據(jù)小于4個(gè)字節(jié)(因此不能包含字符串的長度),或者消息中的剩余數(shù)據(jù)小于消息的長度,則返回錯(cuò)誤SSH_ERR_MESSAGE_INCOMPLETE(在日志中找到的消息)字符串。
總結(jié)這一系列函數(shù):當(dāng)packet_get_string用于從消息中提取字符串時(shí),如果字符串格式錯(cuò)誤,則會(huì)發(fā)生致命異常,從而導(dǎo)致OpenSSH進(jìn)程終止。
這正是PoC Python腳本觸發(fā)的內(nèi)容。首先,它與OpenSSH服務(wù)器建立加密連接,然后發(fā)送格式錯(cuò)誤的SSH2_MSG_USERAUTH_REQUEST(類型公鑰)消息。該腳本將Paramiko的add_boolean函數(shù)重新定義為NULL函數(shù)。Paramiko是用于SSH通信的Python模塊。通過重新定義add_boolean函數(shù),消息中省略了布爾字段(就在算法和鍵字符串字段之前)。
當(dāng)函數(shù)userauth_pubkey解析此格式錯(cuò)誤的消息時(shí),首先讀取布爾字段。由于該字段實(shí)際上是丟失的,因此讀取下一個(gè)字段的第一個(gè)字節(jié)(函數(shù)packet_get_char):算法字符串的4字節(jié)長度的最高有效字節(jié)。調(diào)用下一個(gè)函數(shù)packet_get_string來讀取(并驗(yàn)證)算法字符串。由于缺少布爾字段,這將失敗。
以下是格式良好的消息的解析:
對于格式錯(cuò)誤的消息,缺少布爾值。解析函數(shù)當(dāng)然不知道這一點(diǎn),因此它將字符串的第一個(gè)字節(jié)解析為布爾字段:它看起來像消息向左移一個(gè)字節(jié):
結(jié)果是解析了1907字節(jié)的字符串長度(0x00000773十六進(jìn)制),這比消息本身長。因此,函數(shù)ssh_packet_get_string將調(diào)用函數(shù)致命以導(dǎo)致OpenSSH進(jìn)程終止。
漏洞摘要
這是一個(gè)微妙的錯(cuò)誤。它不是緩沖區(qū)溢出導(dǎo)致遠(yuǎn)程代碼執(zhí)行或缺少輸入驗(yàn)證。
沒有緩沖區(qū)溢出,所有輸入在使用前都經(jīng)過驗(yàn)證。這里的問題是輸入驗(yàn)證在一些功能處理已經(jīng)發(fā)生之后發(fā)生:可能出于性能原因,首先檢查用戶名以查看它是否存在。如果它不存在,則不必進(jìn)行進(jìn)一步的輸入驗(yàn)證和處理。
使用現(xiàn)有用戶名,將進(jìn)行輸入驗(yàn)證,并且可以在不發(fā)送消息的情況下關(guān)閉連接。這可用于導(dǎo)出用戶名的存在。
這個(gè)問題的解決方案很簡單:在任何功能處理之前切換順序并首先進(jìn)行所有輸入驗(yàn)證。
在其他身份驗(yàn)證功能中可能會(huì)出現(xiàn)相同的錯(cuò)誤。檢查這個(gè)的粗略,不完整的方法是檢查表達(dá)式“!authctc-> valid”,如下所示:
確實(shí)在基于主機(jī)的身份驗(yàn)證中犯了同樣的錯(cuò)誤(可以在GitHub提交中看到):
和Kerberos身份驗(yàn)證:
并且可能是SSH1 RSA身份驗(yàn)證(我們還沒有進(jìn)一步檢查,因?yàn)樗贠penBSD等實(shí)現(xiàn)中不再存在):
請注意,評論甚至警告這種風(fēng)險(xiǎn)!
結(jié)論
根據(jù)你對OpenSSH的使用,可以減輕此漏洞。區(qū)塊鏈安全公司W(wǎng)F曲速未來提醒在修補(bǔ)程序可用并部署之前,可以禁用易受攻擊的身份驗(yàn)證機(jī)制。例如,通過禁用公鑰身份驗(yàn)證,PoC腳本不再有效,因?yàn)榫芙^了格式錯(cuò)誤的身份驗(yàn)證請求。
當(dāng)然,如果你不使用公鑰認(rèn)證,我們只建議你禁用公鑰認(rèn)證。如果你使用它,請不要切換到密碼驗(yàn)證,但繼續(xù)使用公鑰驗(yàn)證!這不是遠(yuǎn)程執(zhí)行代碼漏洞,而是一個(gè)信息泄露漏洞。
你還可以檢查日志中是否有利用此漏洞的跡象。致命錯(cuò)誤可能是一個(gè)跡象。在Ubuntu上使用此PoC,致命錯(cuò)誤是“不完整的消息”。但是,此消息可能略有不同,具體取決于你的OpenSSH版本,還有其他方法可生成格式錯(cuò)誤的消息,這可能會(huì)導(dǎo)致另一個(gè)致命錯(cuò)誤。例如,可以創(chuàng)建一個(gè)字符串長度超過最大允許值的身份驗(yàn)證請求。
在默認(rèn)配置中,你只會(huì)收到此致命錯(cuò)誤。例如,不會(huì)記錄客戶端的IP地址。可以通過將日志級別(LogLevel)從INFO增加到VERBOSE來包含此信息:這將創(chuàng)建額外的日志條目,其中包含客戶端的IP地址。請注意,這將生成更大的日志,并且你應(yīng)該監(jiān)視日志不會(huì)超過你的容量。
1.TMT觀察網(wǎng)遵循行業(yè)規(guī)范,任何轉(zhuǎn)載的稿件都會(huì)明確標(biāo)注作者和來源;
2.TMT觀察網(wǎng)的原創(chuàng)文章,請轉(zhuǎn)載時(shí)務(wù)必注明文章作者和"來源:TMT觀察網(wǎng)",不尊重原創(chuàng)的行為TMT觀察網(wǎng)或?qū)⒆肪控?zé)任;
3.作者投稿可能會(huì)經(jīng)TMT觀察網(wǎng)編輯修改或補(bǔ)充。