0x00 前言
之前挖src 的时候,想着用幽灵猫来挖,但是由于没有理解原理,导致测试的时候直接用脚本扫描出错了也一脸懵逼,所以想好好分析分析这个漏洞,全面了解原理,也学习学习tomcat
0x01 漏洞介绍
0x02 环境搭建:
1. 下载t omcat :
**tomcat源码压缩包(https://archive.apache.org/dist/tomcat/tomcat-7/v7.0.99/src/apache-tomcat-7.0.99-src.zip ),另一个是tomcat可执行的压缩包。( https://mail.qq.com/cgi-bin/mail_spam?action=check_link&spam=0&spam_src=1&mailid=ZL1201-fIhPFlrtPhTAnCF_p7MIGa6&url=https%3A%2F%2Farchive.apache.org%2Fdist%2Ftomcat%2Ftomcat-7%2Fv7.0.99%2Fbin%2Fapache-tomcat-7.0.99-windows-x64.zip) )
参考配置: https://blog.csdn.net/u013268035/article/details/81349341
2.没有自动导入maven
3.坑:
一定亲自为项目配置低版本的jdk ,jdk 11 过不了
启动成功:
默认8089端口是开启的:
0x03 ajp协议介绍:
参考 https://www.cnblogs.com/guanghuiqq/p/11204719.html
0x04 审计前言:
开源项目爆出漏洞的时候可以去github查看commit 或者在提高了版本的时候可以使用compare 来对比
先去查看commit :
compare:
0x04 复现:
准备读取manager/WEB-INF/1.txt
【使用 的脚本地址 : https://github.com/hypn0s/AJPy 】
(为了按照后文的步骤调试文件读取 , 把/xxxxx.jsp 修改为/xxxxx, 也就是修改requesturi不然和后文调试的过程不太一样)
wireshark 抓包:
对话流:
一次会话,回复了三次
设置的参数
0x05 调试前的准备知识:
(1) tomcat 的架构 https://www.guildhab.top/?p=2406 热气球工会 epicccal 师傅
https://blog.csdn.net/xlgen157387/article/details/79006434 徐刘根师傅 四张图读懂tomcat 架构
可以看下面这张图:
简单的总结就是:
server 是tomcat 中最顶层的容器,一个tomcat 只有一个容器
service 对外提供服务连接,可以提供不同的协议连接,比如http , https ,ajp ,这取决于connectors 的设置,一个service 包含一个container 和 多个connectors
connectors 就是来处理不同连接的,把socket 请求封装成Request 请求,交给container 处理
container 用于封装和管理servlet ,并且处理来自connetors 的Requests 请求,返回Response 响应,返回给connectors 组件
对于container :
【引自热气球公会 https://www.guildhab.top/?p=2406】
(3)理解requestsHeaderMessage (prepareRequests的时候经常遇到)
requestsHeaderMessage 是AJPMessage类的一个实例
AJPMessage 类中的getBytes() 和 getByte() ,里面有个pos 记录当前读或者写的buf位置,每次getBytes 和 getByte 都会改变这个pos 。
getByte() 函数:
getBytes函数后面会讲到
(4) tomcat 对静态资源的处理: 参考光辉飞翔师傅:https://www.cnblogs.com/chuonye/p/10816345.html
cacheEntry:
0x06 调试:
ðparepareReques
Tomcat在接收ajp请求的时候调用org.apache.coyote.ajp.AjpProcessor来处理ajp消息,prepareRequest()方法将ajp里的内容取出,并设置成request对象的属性。既然如此,我们先在调用prepareRequest()方法的地方下一个断点。
具体文件路径:
跟进这个函数: (其实就是在一步步处理requestsHeaderMessage , 把 requestsHeaderMessage的值写到requests里面)
发现很多getBytes() ,于是跟进getBytes() 函数,
set 之后,可以看到requests,remoteAddr() 的值如下:
然后就是解析headers :
解析完成后
接下来就是解析额外的标记:
可以看到对比7.0.100 和 7.0.99 版本;
然后读了三次之后: requests.attributes 就读入了我们添加的属性
接着检查如果需要secret 的话是否提交了secret ,没有的话就返回403
所以防御的时候可以设置secret:
检查是否是完整的uri
然后设置requests中的host :
到此解析完成
然后process the request in the adapter:
跟进adapter:
然后调用容器:
跟进invoke:
再跟进invoke:
跟进getNext:
一步步跟进,到context :
然后一直跟进回到wrapper:
(这里如果开始脚本没有修改为/xxxxx的话,会是jsp)
一路跟进,会看到分配servlet:
接着下面会有doFilter:
跟进doFilter ,看到servlet.service (到servlet 了,正式处理request 和 response 了)
一步步跟进service ,会到一个getRelativePath 函数:
接着下面关键点,会到一个lookupCache()函数:
跟进到cacheLookup函数中:
一直跟进cacheLoad: (第一次访问,自然不会找到缓存条目,后面测试,即使进入了else分支 ,else 里面也会进入后面的new File 的)
跟进:
跟进:
跟进,可以看到会new 一个File 对象,【也就是漏洞的触发点】
其中validate 函数限制了file 的合格性:
后面就是把读取的资源输出来
调用栈:
参考:
https://www.guildhab.top/?p=2406 热气球工会 epicccal 师傅 cve-2020-1938 复现
https://www.cnblogs.com/r00tuser/ 水泡泡师傅 cve-2020-1938 复现
https://blog.csdn.net/xlgen157387/article/details/79006434 徐刘根师傅 tomcat 系统架构
https://www.cnblogs.com/chuonye/p/10816345.html wskwbog 师傅 tomcat 静态文件处理
https://blog.csdn.net/u013268035/article/details/81349341 包华杰师傅 配置idea 调试tomcat源码
https://github.com/hypn0s/AJPy hypn0s 大佬的工具
后记
第一次调试java 源代码来漏洞复现,学到了tomcat 整个容器的架构 , 怎么处理请求,以及tomcat如何处理静态文件.
收益颇多,继续学习