Apache HTTP Server mod_lua�?榛撼迩绯雎┒捶治觯–VE-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�?槭茿pache上的一个扩展�?�,适用于2.3以上版本 。该�?樵市硎褂胠ua脚本扩展服务器,还包罗许多其他�?榭捎玫墓匙雍� 。例如将请求 Map 到文件,生成动态响应,访问控制,身份验证和授权等 。如果开启该�?�,可能会造成一些宁静隐患 。

在/etc/httpd/httpd.cnf配置文件中取消下面这行注释,即可开启该�?榈墓π� 。


代码文件.png

当收到.lua文件请求时,mod_lua�?榈饔胠ua-script的handle函数进行处置 。下图为handle函数实例 。


代码文件.png

apr内存池


为了减少系统内存分配的时间,提高法式运行效率,Apache的开发者创建了一套基于池看法的内存管理方案 。这套要领移到apr中成为通用的内存管理方案,也就是apr内存池 。

apr的内存池结构其实是一种树状的条理结构,parent指向当前内存池的父内存池,child指向当前内存池的子内存池,sibling则指向当前内存池的兄弟内存池 。用户使用的内存空间,则是active管理的一个节点链表 。用户要申请内存空间的时候就会在active管理的内存节点中寻找 。


结构体如下所示:


代码文件.png


用户申请内存过程:


(1)首先取最接近不小于8字节倍数巨细的空间(8字节对齐),然后凭据申请巨细判断active节点可用空间是否足够 。若内存足够,移动first_avail指针,返回其地址;若空间不足,则继续进行2之后的步骤 。


(2)判断下一个内存节点的剩余空间是否足够,若足够则使用之,并将之脱离当前链表;若不足,则通过分配子分配新的内存节点 。


(3)将第2步中得到的节点插入active节点之前,并成为新的active节点 。


(4)计算旧的active节点的剩余空间巨细,而且与其链表后的所有节点的剩余空间巨细比力,并插入链表中正确的位置 。


代码文件.png

补丁分析


该漏洞在Apache HTTP Server 2.4.52中进行了修复,在内存申请之前,增加了对长度的合法性校验 。当end-crlf小于即是8,法式会直接退出,制止整数溢出 。


代码文件.png


漏洞分析


凭据漏洞通告,可知漏洞存在于mod_lua�?橹�,lua脚本调用了r:parsebody()函数发生了缓冲区溢出 。结合patch信息,直接定位到req_parsebody函数 。

本文使用Apache HTTP Server 2.4.49版本进行分析,代码中红色方框标识出来的部门即漏洞代码位置,图片中对要害部门进行了相应的注释 。


代码文件.png


下面结合post数据包来分析法式处置逻辑 。结构如下post数据包:


代码文件.png


首先,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分配内存 。


代码文件.png


法式没有对vlen值的合法性进行检查,如果上面参数中的特殊字符缺失,计算的vlen值就可能变为负数,造成整数溢出 。当申请空间的时候,会泛起宁静问题 。



动态调试


凭据差异畸形包的结构,考虑以下两种情况,结合动态调试进行分析 。

申请超大的空间

假设缺失'/r/n--'这4个特殊字符,且数据部门为2字节,vlen=(2+4-8)=-2 。调用apr_pcalloc(r->pool, vlen+1)申请内存时,vlen+1=0xffffffffffffffff 。

使用gdb附加进程,进行动态调试 。在漏洞函数处设置断点,然后发送特殊的post请求 。


代码文件.png


apr内存池无法提供这么大的内存,这时apr的分配子就会向系统申请内存空间,但是申请的巨大内存空间是系统无法提供的,所以系统会直接将进程kill掉(0x75是进程号),造成拒绝服务 。

代码文件.png


溢出超长的字节

假设缺失'/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字节的空间 。



代码文件.png


代码文件.png


参考链接:


[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