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