前言
前段时间,涛哥安排了个Confluence站点的测试,网上搜了下存在模板注入可导致命令执行,编号CVE-2020-4027。网上没有复现的文章,直到要交报告了还是没成功执行命令,只能交个模板注入导致文件读取悻悻而归。这件事如鲠在喉,于是抽空搭个环境复现了下。
前期准备
复现环境本文使用的是Confluence 7.4.4的版本,官网有部署包可下,考虑到要下断点调试,没有使用Docker部署,数据库可以使用Docker起一个postgres,配置步骤网上有很多教程,本文就不具叙。
前期准备主要是IDEA怎么去调试的问题。开头就遇到坑,Xloggc的日志文件不支持中文,环境直接都启动不起来,最后排查下在service.bat里有Xloggc文件名参数,系统是中文的文件名也会是中文,删除掉百分号的内容即可。部署包自带一个tomcat,包里的confluence目录是项目的Web目录,刚开始想着从IDEA里启动tomcat,但不过是自带的tomcat,还是自己的tomcat启动后访问都是404。最后学着远程调试的方法,在自带tomcat的catalina.bat脚本开头加入以下一行调试命令,接着运行启动文件start-confluence.bat,并开启调试即可。
复现步骤
虽然网上没有找到具体的漏洞点,但根据CVE的描述和@Xiao_C师傅的复现截图可得知漏洞点是出在用户宏(User macros)里,再查阅下文档和根据上一个模板注入漏洞CVE-2019-3396可知,用户宏可通过管理员的一般设置的用户宏处设置,然后在编辑文章的其他宏里预览触发。
用CVE-2019-3396的payload如下,试了下无法执行命令直接输出了模板的内容,根据CVE的描述得知是因为使用了沙箱导致的。
1 | #set($e="exp") |
那么先来看一个简单的velocity demo如下,最基本的会实例化模板引擎VelocityEngine和模板上下文VelocityContext。
1 | public static void main(String[] args) throws Exception { |
调试可以先从VelocityEngine的init方法下手。在init下断点,然后重新运行网站的启动脚本,用于初始化的Properties对象有很多的配置,其中runtime.introspector.uberspect是与沙箱相关的一个配置。其使用ConfluenceAnnotationBoxingUberspect类进行配置。
复现/屏幕截图 2021-10-11 163940.png)
跟进ConfluenceAnnotationBoxingUberspect,最终找到它的父类SecureUberspector,是Volecity的默认沙箱。
复现/屏幕截图 2021-10-11 170656.png)
用前面的Demo加上runtime.introspector.uberspect属性,使用之前模板注入的payload进行测试,会抛出一句告警。
复现/屏幕截图 2021-10-15 154941.png)
搜寻一番,发现是在SecureIntrospectorImpl的getMethod方法输出的日志。跟进到同一个类中的checkObjectExecutePermission方法,验证对象是否合法。常规模板注入获取Class实例,一般通过String类型的Class实例调用forName方法,也就是java.lang.Class已经在黑名单类内,所以这种方式在这里就无法使用了。
复现/屏幕截图 2021-10-15 161716.png)
再回去看看CVE的描述,说是通过上下文绕过沙箱。接下来找找有哪些上下文属性,我这里在模板中执行String的codePointBefore方法并下断点。顺着调用栈往上找,在GenericVelocityMacro的execute方法里调用了MacroUtils的defaultVelocityContext方法。
复现/屏幕截图 2021-10-16 202253.png)
跟进defaultVelocityContext方法可以看到默认设置了req、res、action和webwork四个上下文属性。
1 | public static Context createDefaultVelocityContext() { |
其中req做最终是实现ServletRequest接口的,具有getServletContext方法,可获得Servlet的上下文。而上下文中有attributes属性,其中包括org.apache.tomcat.InstanceManager的键值对,这个类名在Struts2的Poc中看过,可以通过newInstance方法new一个给定类名的实例。
复现/屏幕截图 2021-10-19 155958.png)
然后可以通过ScriptEngineManager或各种表达式语言执行命令。其实这个模板注入本质上是漏洞作者@pwntester的另一个CVE漏洞Remote Code Execution in Apache Velocity,而且作者也给出了POC如下。
1 | ${req.getServletContext().getAttribute('org.apache.tomcat.InstanceManager').newInstance('javax.script.ScriptEngineManager').getEngineByName('js').eval("java.lang.Runtime.getRuntime().exec('touch /tmp/pwned')")} |
复现/屏幕截图 2021-10-20 121613.png)
在这之前遇到大坑了,官方说受影响版本包括7.5.0,我自己搭了个7.5.0版本,包括使用测试站点,用上面的payload是会直接原样输出的,也就是被沙箱拦截了。这一度让我以为方向错了,后来换个7.4.4版本就成功了,这就很无语了。
复现/屏幕截图 2021-10-20 151313.png)
后记
水这篇文章的时间跨度好大,从九月底到现场,过了个国庆人都懈怠了。感觉写得有点乱,文中若有错误的地方,望各位师傅不吝斧正。
参考
https://securitylab.github.com/advisories/GHSL-2020-045-atlassian_confluence/
https://securitylab.github.com/advisories/GHSL-2020-048-apache-velocity/
https://twitter.com/XiaoC75068775/status/1309673425984610306