Apache HTTP Server mod_lua模塊緩沖區溢出漏洞分析(CVE-2021-44790)
發布時間 2022-01-20漏洞概述
2021年12月20日,Apache 團隊發布了Apache HTTP Server 2.4.52版本,修復了Apache HTTP Server中的一個緩沖區溢出漏洞(CVE-2021-44790),該漏洞存在于mod_lua解析器中,當服務器解析惡意請求時觸發緩沖區溢出,可導致拒絕服務或執行任意代碼。
影響范圍
影響版本:Apache HTTP Server <= 2.4.51
相關介紹
Mod_lua模塊
Mod_lua模塊是Apache上的一個擴展模塊,適用于2.3以上版本。該模塊允許使用lua腳本擴展服務器,還包括許多其他模塊可用的鉤子函數。例如將請求 Map 到文件,生成動態響應,訪問控制,身份驗證和授權等。如果開啟該模塊,可能會造成一些安全隱患。
在/etc/httpd/httpd.cnf配置文件中取消下面這行注釋,即可開啟該模塊的功能。
當收到.lua文件請求時,mod_lua模塊調用lua-script的handle函數進行處理。下圖為handle函數實例。
apr內存池
為了減少系統內存分配的時間,提高程序運行效率,Apache的開發者創建了一套基于池概念的內存管理方案。這套方法移到apr中成為通用的內存管理方案,也就是apr內存池。
apr的內存池結構其實是一種樹狀的層次結構,parent指向當前內存池的父內存池,child指向當前內存池的子內存池,sibling則指向當前內存池的兄弟內存池。用戶使用的內存空間,則是active管理的一個節點鏈表。用戶要申請內存空間的時候就會在active管理的內存節點中尋找。
結構體如下所示:
用戶申請內存過程:
(1)首先取最接近不小于8字節倍數大小的空間(8字節對齊),然后根據申請大小判斷active節點可用空間是否足夠。若內存足夠,移動first_avail指針,返回其地址;若空間不足,則繼續進行2之后的步驟。
(2)判斷下一個內存節點的剩余空間是否足夠,若足夠則使用之,并將之脫離當前鏈表;若不足,則通過分配子分配新的內存節點。
(3)將第2步中得到的節點插入active節點之前,并成為新的active節點。
(4)計算舊的active節點的剩余空間大小,并且與其鏈表后的所有節點的剩余空間大小比較,并插入鏈表中正確的位置。
補丁分析
該漏洞在Apache HTTP Server 2.4.52中進行了修復,在內存申請之前,增加了對長度的合法性校驗。當end-crlf小于等于8,程序會直接退出,避免整數溢出。
漏洞分析
根據漏洞公告,可知漏洞存在于mod_lua模塊中,lua腳本調用了r:parsebody()函數發生了緩沖區溢出。結合patch信息,直接定位到req_parsebody函數。
本文使用Apache HTTP Server 2.4.49版本進行分析,代碼中紅色方框標識出來的部分即漏洞代碼位置,圖片中對關鍵部分進行了相應的注釋。
下面結合post數據包來分析程序處理邏輯。構造如下post數據包:
首先,start變量指向post數據包開始的位置,也就是對應上面第一個標識符--VILC2R2IHFHLZZ的位置,crlf指向兩個空行(\r\n\r\n)開始的位置,end指向下一個標識符VILC2R2IHFHLZZ開始的位置,那么在crlf和end之間的數據就有下面這些內容,總長度為8(特殊字符長度)+len(數據參數長度)個字節。
‘\r\n\r\ntest\r\n--’
根據上面參數內容,我們就可以理解下面這行代碼的意義了。vlen等于總長度減去多余的8個特殊字符,就可以計算出參數的長度。
vlen=end-crlf-8;
然后,程序調用apr_pcalloc分配內存。
程序沒有對vlen值的合法性進行檢查,如果上面參數中的特殊字符缺失,計算的vlen值就可能變為負數,造成整數溢出。當申請空間的時候,會出現安全問題。
動態調試
根據不同畸形包的構造,考慮以下兩種情況,結合動態調試進行分析。
申請超大的空間
假設缺失'/r/n--'這4個特殊字符,且數據部分為2字節,vlen=(2+4-8)=-2。調用apr_pcalloc(r->pool, vlen+1)申請內存時,vlen+1=0xffffffffffffffff。
使用gdb附加進程,進行動態調試。在漏洞函數處設置斷點,然后發送特殊的post請求。
apr內存池無法提供這么大的內存,這時apr的分配子就會向系統申請內存空間,但是申請的巨大內存空間是系統無法提供的,所以系統會直接將進程kill掉(0x75是進程號),造成拒絕服務。
溢出超長的字節
假設缺失'/r/n--'這4個特殊字符,且數據部分為3字節,vlen=(3+4-8)=-1,調用apr_pcalloc(r->pool, vlen+1)申請內存時,長度vlen+1=0,根據apr內存池內存分配機制,apr內存池會分配最小的內存塊8字節,最后使用函數memcpy的時候:
memcpy(buffer, crlf + 4, vlen)
vlen又為FFFFFFFF.......(-1),就會發生緩沖區溢出。
動態調試時可以看到調用apr_palloc時,長度參數是0,實際上會分配8字節的空間。
參考鏈接:
[1]https://mp.weixin.qq.com/s/XLzXHZYvpPIqNrDz3OHaMA
[2]https://nakedsecurity.sophos.com/2021/12/21/apaches-other-product-critical-bugs-in-httpd-web-server-patch-now/
[3]https://httpd.apache.org/security/vulnerabilities_24.html
[4]https://ubuntu.com/security/CVE-2021-44790
[5]https://github.com/apache/httpd/commit/07b9768cef6a224d256358c404c6ed5622d8acce