一、 漏洞简介
CVE-2020-1938是针对tomcat的AJP协议漏洞进行的安全攻击,当AJP协议开放且端口可以访问的时候,即可在存在漏洞的版本实现站点目录下的任意文件读取(很多网文说任意文件读取,那都是打擦边球的可耻行为),远程命令执行(之所以会去研究这个漏洞,主要是因为看中远程命令执行,= =!)。
影响版本:
1、Apache Tomcat 6
2、Apache Tomcat 7 < 7.0.100
3、Apache Tomcat 8 < 8.5.51
4.、Apache Tomcat 9 < 9.0.31
这个漏洞出来有一段时间了,网上也有很多大佬进行了分析和转载,并提供了一些POC,但很多转载原理部分说的比较含糊,不容易弄懂原理,同时提供的poc只能在python2.7的环境运行,我个人是python3.6的环境,导致花了很长的时间修改代码(菜是原罪)。
二、 漏洞分析
二.1 AJP简述
Tomca根据默认配置(conf/server.xml)启动两个连接器。一个是HTTP Connector默认监听8080端口处理HTTP请求,一个AJP connector默认8009端口处理AJP请求,随便找了张网图(懒得截图了),如下:
对于刚接触的人来说,看到AJP协议一脸懵逼,其实经过我多次实验后发现,AJP协议对于使用者来说,与HTTP协议区别不大,也是通过发送一个类似于GET或者POST请求的方式去访问相关资源,只不过协议层使用的是AJP,就当成访问网站的时候使用的是 AJP://XXX.COM,只不过浏览器不识别而已,所以需要一个能实现AJP通信的模块。
二.2 文件读取
这里我参考了http://gv7.me/articles/2020/cve-2020-1938-tomcat-ajp-lfi/的文章,写的非常好,代码漏洞过程的分析很清晰,这里就不重复叙述详细过程了,有兴趣的可以自行研究。
总结一下我的理解,也方便给刚接触的人更好的理解其工作原理。在AJP传输的过程中,用户(攻击者)可以控制输入的部分有四个:
1、RequestUri:/docs/test.jpg
2、javax.servlet.include.request_uri: /
3、javax.servlet.include.path_info: WEB-INF/web.xml
4、javax.servlet.include.servlet_path: /
其中第一个部分是用来引导流量加载方法的,这也是为啥文件读取和命令执行的代码略微有所不同的原因。
对于文件读取,是通过设置RequestUri字段为一个普通的文件(非jsp文件),这时tomcat会把2、3、4的内容交给org.apache.catalina.servlets.DefaultServlet的doGet方法处理(具体方法的代码实现可以看我分享的链接内容,对原创作者的尊重),当2不为空的时候,需要访问资源的拼接路径就是4+3的组合。
这里不能真正实现任意文件读取的原因就是拼接内容中../会被过滤,所以读取文件内容也局限于该tomcat站点目录下。
所以实现该攻击的两个条件就是:
1、能够实现AJP协议通信
2、自定义这4个字段,完成想读取的内容。
二.3 命令执行
命令执行的本质是把任意文件当成jsp脚本执行,具体代码分析还是参见我分享的链接。所以要想实现命令执行,还需要一个条件就是目标站点存在上传点并能够获取到路径(猜出来的也是牛逼)。其大致原理跟文件读取是一样的,唯一的区别如下:
1、需要通过1字段引导jsp处理模块,RequestUri:/docs/test.jsp
2、通过2、3、4字段拼接(同文件读取),指向需要执行的文件路径
三、 漏洞复现
1、找个有漏洞版本的tomcat部署起来。
2、使用POC攻击
我自己复现比较懒,之前研究shiro反序列化漏洞的时候正好有个环境就是tomcat,版本也存在漏洞,直接就用了。
POC是我经过修改的版本,可用性比github上的更好用一点(主要是兼容性和AJP协议直接拉出来省的还要装环境又有兼容性问题,万恶的python2,都快淘汰了大佬还喜欢用,因为kali默认python2的原因么),这里就不放出丢人了,部分代码如下:
我设置了多个参数选择,为了增加利用的成功率。
三.1 文件读取
三.2 命令执行
这里偷懒了,直接虚拟机里写了一个jsp反弹shell的脚本,为txt文件(实战可以上传图片码)。
这里也说明了不需要jsp文件可以访问,引导处理代码文件用的。