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