导语:在趋势科技漏洞研究服务漏洞报告中,趋势科技研究团队的 Guy Lederfein 和 Dusan Stevanovic 详细介绍了 Apache 网络服务器中最近新出现的一个代码执行漏洞。
在趋势科技漏洞研究服务漏洞报告中,趋势科技研究团队的 Guy Lederfein 和 Dusan Stevanovic 详细介绍了 Apache 网络服务器中最近新出现的一个代码执行漏洞。该漏洞最初是由名为 Chamal 的研究人员发现并报告的。精心设计的请求主体可能会导致 mod_lua 多部分解析器中的缓冲区溢出,这可能会导致代码在安全进程的上下文中执行。Apache httpd 的 mod_lua 模块中出现了一个整数溢出漏洞。该漏洞是由于模块的多部分解析器中的请求主体验证不正确,通过 Lua 脚本中的 r:parsebody() 函数调用。未经身份验证的远程攻击者可以通过向目标服务器发送精心设计的请求来利用此漏洞。成功利用可能导致在服务器进程的安全上下文下远程执行代码,而不成功的攻击可能导致拒绝服务条件。
漏洞介绍
Apache HTTP 服务器是互联网上最流行的网络服务器,该服务器能够与许多不同的选项和配置一起使用,可以使用多种运行时可加载插件模块来扩展其功能。
官方插件模块之一是 mod_lua 模块,与所有其他模块一样,它可以编译为带有“.so”扩展名的单独共享库。该模块的目的是允许使用用 Lua 编程语言编写的脚本扩展 HTTP 服务器。如果在 HTTP 服务器配置文件中加载了该模块,则可以为以“.lua”结尾的文件设置 lua-script 处理程序。下面是一个配置示例:
HTTP 是 RFC 7230 - 7237 和其他 RFC 中描述的请求/响应协议。客户端向服务器发送请求,服务器又将响应发送回客户端。 HTTP 请求由请求行、各种标头、空行和可选消息主体组成:
其中CRLF表示新行序列回车(Carriage Return, CR)后跟换行(line Feed, LF), SP表示一个空格字符。参数可以在Request-URI或消息体中作为name=value对从客户端传递到服务器,具体取决于所使用的Method和Content-Type标头。例如,使用 GET 方法传递名为“param”且值为“1”的参数的简单 HTTP 请求可能如下所示:
使用 POST 方法的类似请求可能如下所示:
如果有多个参数/值对,它们将被编码为 & 分隔的名称=值对:
var1=value1&var2=value2&var3=value3...
HTTP POST请求主体中的数据可以使用各种标准化或专有方法进行编码。标准化的方法之一是RFC 2388中定义的multipart/form-data。Multipart/form-data由多个部分组成,每个部分包含一个Content-Disposition标头。每个部分由一串字符分隔。分隔各部分的字符串由Content-Type标头行上的boundary关键字定义。Content-Type也必须设置为multipart/form-data。Content-Disposition标头包含一个name参数,描述返回的表单元素。额外的标头行可能出现在每个部分,每一行由一个新的行序列分隔。标头由两个连续的新行结束。下面是表单元素的数据。如果主体被分离并存储在一个单独的文件中,filename参数则会提供一个建议的文件名。
mod_lua 模块支持的内置函数之一是 r:parsebody()。该函数允许 Lua 脚本解析发送到服务器的 HTTP POST 请求的主体。该函数返回两个 Lua 表,其中包含从主体解析的参数名称和值。此函数还支持使用 multipart/form-data 内容类型编码的 HTTP POST 请求。
Apache HTTP 服务器中存在整数溢出漏洞。当mod_lua模块被启用,并且r:parsebody()函数在被服务器解析的Lua脚本中被调用时,函数req_parsebody()被调用。该函数检查服务器收到的 HTTP POST 请求是否包含以字符串“multipart/form-data;boundary=”开头的 Content-Type 标头,表示请求主体使用 multipart/form-data 内容类型编码。如果找到,该函数将搜索 ContentType 标头中定义的边界字符串,并保存到 multipart 变量中。在多部分字符串的每次匹配之后,该函数搜索两个连续 CRLF 序列的首次出现,并存储到 CRLF 变量中。如果找到此匹配项,则该函数在以下内容中搜索 multipart 变量的另一个匹配项,该变量存储到 end 变量中,表示表单元素数据的结束。
接着,form元素数据的大小是取end变量,减去CRLF变量,然后减去8(表示元素数据之前的两个CRLF序列,以及元素数据末尾的CRLF和“——”字符)。但是,如果表单元素的格式不正确,使得结束边界字符串出现在两个 CRLF 序列开始后不到 8 个字符内,则此减法将导致负数。减法的结果存储在一个名为 vlen 的 size_t 类型的变量中。因此,如果减法结果为负数,会先转换成较大的正数再存入 vlen 变量,导致整数溢出。具体来说,如果减法结果为 -1,则 vlen 变量将包含 size_t 的最大大小。之后,在堆上分配了一个名为 buffer 的缓冲区,大小为 vlen+1。在上述情况下,这将导致整数溢出,导致分配大小为0的缓冲区。稍后,调用memcpy()函数将元素的数据复制到大小为vlen的缓冲区变量中,从而导致缓冲区溢出。
未经身份验证的远程攻击者可以通过向目标服务器发送带有精心设计的主体(使用 multipart/form-data 内容类型编码)的 HTTP POST 请求来利用此漏洞。成功利用可能导致在服务器进程的安全上下文下远程执行代码,而不成功的攻击可能导致拒绝服务条件。
攻击检测
检测设备必须检查对解析为 Apache 服务器上托管的 Lua 脚本的 URL 的所有 HTTP POST 请求。然后检测设备必须检查 Content-Type 标头并检查它是否设置为“multipart/formdata”。如果找到,检测设备必须检查来自 HTTP 主体中 Content-Type 标头的边界字符串的所有实例。对于找到的边界字符串的每个实例,检测设备必须在找到的边界之后搜索两个连续 CRLF 序列的第一个实例。如果找到,检测设备必须搜索边界字符串的下一个实例。如果找到,检测设备必须计算两个连续 CRLF 序列的开头和后面的边界字符串之间的字符数。如果字符数少于8个,则认为流量是恶意的;利用此漏洞的攻击可能正在进行中。
一个恶意请求示例是在两个连续 CRLF 序列的开头和结束边界字符串之间有 7 个字符。
请注意,字符串匹配必须以区分大小写的方式执行
总结
Apache 已使用 HTTP Server 2.4.52 修补了此漏洞。
本文翻译自:https://www.zerodayinitiative.com/blog/2022/1/25/cve-2021-44790-code-execution-on-apache-via-an-integer-underflow如若转载,请注明原文地址