使用JPDA调试Tomcat(三)

本文承接之前的两篇:

使用JPDA调试Tomcat(一)
使用JPDA调试Tomcat(二)

在本文中,我们继续动态调试工作:

动态调试

前一篇文章中,我们在IntelliJ中完成了对调试环境的配置,创建了tc6-jpda这个profile。

点击这个bug icon:

使用JPDA调试Tomcat(三)_第1张图片

可以在下面的console窗口看到,IntelliJ已经连接到了Tomcat的8000调试端口上面:

使用JPDA调试Tomcat(三)_第2张图片

一切准备就绪,我们打开浏览器,重现BUG。首先访问 http://127.0.0.1:8080/secured-webapp/admin,用户名及密码使用user/user:

使用JPDA调试Tomcat(三)_第3张图片

点击Login,此时,IntelliJ窗口会弹出到最前面,并显示Tomcat停到了断点上面:

使用JPDA调试Tomcat(三)_第4张图片

这就是JPDA的强大之处-它是一个基于网络协议的调试架构。我们顺便看一下IntelliJ下面的调试窗口。IntelliJ的调试窗口共分为三个部分,我们从左到右依次查看:

使用JPDA调试Tomcat(三)_第5张图片

如上图所示,最左边是StackTrace,我们可以很方便地看到程序是怎样一层一层执行到断点,这在分析复杂问题的时候,非常有用。比如在这里,我们可以看到Tomcat是怎么样从SingleSignOnValve一步一步执行到RealmBase中的断点处的。因为本文的重点是介绍工作方法,而不是分析Tomcat的技术细节,所以这里不展开讨论。但是你在对自己手里的项目进行调试的时候,必须要对项目的设计架构和源代码有相当的熟悉程度才可以,这个学习和分析工作是最花时间的。

接下来是参数列表:

使用JPDA调试Tomcat(三)_第6张图片

IntelliJ帮我们把当前Scope下的参数及其Value都列在了这里,方便分析代码。接下来是Watches窗口:

使用JPDA调试Tomcat(三)_第7张图片

我们在这里可以添加一些默认的参数列表中没有监测到的变量,也可以添加表达式。在这个具体的问题中,我们关心的是这个:

if (requestURI.endsWith(Constants.FORM_ACTION))


所以,可以在Watches里面点+号,添加这个表达式:

使用JPDA调试Tomcat(三)_第8张图片

这样我们就可以很方便地检查这个表达式的判断结果:

使用JPDA调试Tomcat(三)_第9张图片

总结上面的分析过程,并点击Go按钮,让Tomcat继续服务:



此时浏览器这边会返回这个页面:

使用JPDA调试Tomcat(三)_第10张图片

接下来我们访问这个地址,重现BUG: http://127.0.0.1:8080/secured-webapp/admin/j_security_check

这个时候IntelliJ再次把Tomcat停到这个断点上面,这次看到不同的是,Watches中的表达式判断变成了true,于是点击单步执行的按钮:



可以很清楚地看到,hasResourcePermission方法直接返回true,bypass掉了权限检查:

使用JPDA调试Tomcat(三)_第11张图片

点击Go按钮,让程序继续执行,在浏览器里面,我们看到user用户能够进到了Admin的页面:

使用JPDA调试Tomcat(三)_第12张图片

Okay,动态调试及验证过程到这里就算是完成了。 接下来做一些清理收尾工作,去掉断点,点击Stop按钮,结束调试过程:



最后不要忘记停掉Tomcat:

使用JPDA调试Tomcat(三)_第13张图片

我们接下来试着Fix这个BUG:

修复BUG

这个BUG比较容易,我们删掉这段多余的代码就可以了:

使用JPDA调试Tomcat(三)_第14张图片

接下来编译Tomcat的源代码。找到源码中的BUILDING.txt,看一下应该如何编译Tomcat的源代码:

使用JPDA调试Tomcat(三)_第15张图片

编译过程取决于你的机器速度,完成后,会显示编译成功:

使用JPDA调试Tomcat(三)_第16张图片

接下来要做的是找找这个Patch过的RealmBase被封装在哪个jar里面,因为我们只需要把改变过的jar替换到运行的Tomcat当中,而不需要把全部的组件全部替换:

使用JPDA调试Tomcat(三)_第17张图片

从上面的图中可以看出,catalina.jar中包含RealmBase,可以具体验证一下:

使用JPDA调试Tomcat(三)_第18张图片

确定了就是这个jar包含RealmBase.class。我们将这个jar拷贝到在使用的tomcat中,替换原有的:

使用JPDA调试Tomcat(三)_第19张图片

然后启动Tomcat:

使用JPDA调试Tomcat(三)_第20张图片

接下来的工作是验证BUG已经被修复。

验证PATCH有效性

首先我们访问照例访问 http://127.0.0.1:8080/secured-webapp/admin,并使用user登录:

使用JPDA调试Tomcat(三)_第21张图片

登录后照例出现权限不足的页面:

使用JPDA调试Tomcat(三)_第22张图片

接下来我们要验证这个地址: http://127.0.0.1:8080/secured-webapp/admin/j_security_check,确保权限认证没有被bypass掉:

使用JPDA调试Tomcat(三)_第23张图片

成功!我们的PATCH生效了,user不再能通过这个漏洞访问admin的页面。

CVE

对于Tomcat这样的成熟社区项目,一般类似这样的BUG都会被很快发现,并会产生一个标准的CVE安全报告。比如我们在本文中用到的这个BUG,它的CVE报告在这里:

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-3546

在里面有对问题的描述,以及相关的PATCH。我们看一下报告中link的PATCH:

http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java?r1=1377892&r2=1377891&pathrev=1377892

可以看到和我们分析的结果是一样的。所以说,给社区中的项目做开发,并没有想象的那么难对不对?

总结

在这套文章中,我介绍了我在社区中进行日常工作中的流程,使用到的工具,分析问题的思路和方法。在实际的工作过程中,遇到的问题难易程度不一样,但分析问题的方法万变不离其踪。

此外,本文中使用IntelliJ做为调试环境,如果你用Eclipse,可以参考我写的这篇文章:

灵活使用Eclipse与Java远程调试功能

你可能感兴趣的:(jpda)