环境搭建
由于官方的镜像是新版了,这里找到个旧的镜像:
1 | docker run -p 15005:5005 -p 18080:8080 -dt -e acceptEULA=YES -e password=admin vulfocus/vcpe-1.0-a-adobe-coldfusion:2023.0.0.330468-openjdk-release |
上面这个旧版的就打包:/opt/apache-tomcat-9.0.78/webapps
这里就行
新版的直接由官方:
https://hub.docker.com/r/adobecoldfusion/coldfusion
可修改配置文件开启 debug:
1 | /opt/coldfusion/cfusion/bin/jvm.config |
然后把整个 /opt/coldfusion
都打包下来就好了。
调用过程分析
*** 这里建议先把所有 jar
加到同一个文件夹先,比较好引入。***
首先是 web.xml
:
1 | <servlet-mapping id="coldfusion_mapping_4"> |
BootstrapServlet
类会转到 servlet.class
指向的类里,所以直接看 coldfusion.xml.rpc.CFCServlet
就好。
这个类的话看了一下,主要是 filter
的组装,然后就会进入到 filter.invoke
了。
filter
的话,比较关键的点有几个
首先是:
1 | coldfusion.filter.GlobalsFilter |
这个 Filter
会做一些全局属性的组装,就是把GET
POST
里的参数都放在一个 scope
里,方便后面框架的取用
了解一下就好了,然后就是这个:
1 | coldfusion.filter.PathFilter#invoke |
在这里会根据 URL
的路由拼接上路径去找到对应的文件然后载入,具体载入过程就不详细分析了。
然后就是最后的一个 Filter
:
1 | coldfusion.filter.ComponentFilter |
这个 filter
中实现了方法的调用:
*** cfc
、cfm
就是 class
文件,但是他是很多个文件 class 二进制文件拼接起来的。***
用 GPT 写了个脚本进行分割:
1 | def split_file_by_marker(file_path, output_folder, marker=b'\xCA\xFE\xBA\xBE'): |
几个漏洞复现
CVE-2024-20767
这个是个任意文件读的,首先是找到这个类:
1 | coldfusion.monitor.PMSGenericServlet |
看到两处,第一处是验证,第二处是 logging
:
这个函数可以读取文件,没有过滤的,然后看看 validateSecret
函数:
1 | private boolean validateSecret(HttpServletRequest request) { |
这个验证请求头的 uuid
和 header
里是否一致。
那么这个怎么来呢
文件位置:CFIDE/adminapi/_servermanager/servermanager.cfc
分割以后能找到其中有个类叫做:cfservermanager2ecfc1905146815$funcGETHEARTBEAT
可以看到这里调用了 MONITORINGSERVICE#getHeartBeat
,
这里建议把所有的 jar
都拖到一个 libs
里,然后就能找到这里地方:
1 | coldfusion.monitor.module.MonitoringServiceImpl#getHeartBeat |
可以看到这里就是输出了 uuid
(当然,以上过程都是看答案找过程罢了,真正要理解还是要自己想想如何找的)
然后就是找到上面的 PMS:
1 | <servlet-mapping id="coldfusion_mapping_pms"> |
这里是可以 Debug
的,回到这个函数:
1 | coldfusion.monitor.PMSGenericServlet#doGet |
然后就是数据包:
1 | GET /pms?module=logging&file_name=../../../../../../../../../../../../../etc/passwd&number_of_lines=999 HTTP/1.1 |
修复方法
这个修复比较逆天,在新版中已经没有 CFIDE/adminapi/_servermanager
这个文件夹了,好像把 _servermanager
都删了。
一些额外的分析
其实这里还是有一些限制的,会发现不是所有的 servermanager.cfc
下面的方法都能调用。
在根据方法名获取到方法以后,会进入到这里:
1 | coldfusion.runtime.TemplateProxy#invoke(coldfusion.runtime.UDFMethod, String, Object[], Map, coldfusion.runtime.CfJspPage, coldfusion.filter.FusionContext) |
第二个箭头是调用的地方,上面有个 checkAccess
函数:
这里可以看到不是 3
就会做一些判断,具体做了什么判断就先不分析了,也就是说我们需要找到 getAccess
返回 3
的 方法,比如这个:
但是这个也不行,直接执行方法:
1 | /CFIDE/adminapi/_servermanager/servermanager.cfc?method=getVersionString |
会返回说权限不够:
这是因为在 runFunction
实际执行中还是做了一个权限验证:
因此导致不行执行,刚好的是上面提到的 getHeartBeat
没有校验,所以才能获得 UUID
CVE-2023-26360
直接搭建一个官方的:
1 | docker run -p 25005:5005 -p 28500:8500 -dt -e acceptEULA=YES -e password=admin adobecoldfusion/coldfusion2018:2018.0.15 |
这里虽然说是版本 < 2021.0.7
都行,但是我搭建了 2021.0.5
的打 payload
好像失败了,我就直接搭了个 2018
的了。
这个漏洞点在上面提到过的 ComponentFilter
:
1 | coldfusion.filter.ComponentFilter#invoke |
其中有一处:
首先是 URL
中传递一个 _cfclient
,把它设成 true
之后进入 deserializeJSON
,解析 JSON
这一块会有很多逻辑,可以直接定位到关键点:
1 | coldfusion.runtime.JSONUtils#convertToTemplateProxy |
这里会根据传入的 classname
去解析得到文件,然后会进行类似模板编译的操作。
这个漏洞有个 RCE
的方法就是写入到 log
文件,然后把 log
编译出来就好了,可以看看上面提到的参考文章中有。
CVE-2023-29300
参考:
这个漏洞环境用上面一样的也行。
漏洞点还是在 ComponentFilter
,只不过这次在上面两行:
1 | coldfusion.filter.FilterUtils#GetArgumentCollection |
传入的 argumentCollection
会做 json
解析或者进行 WDDXDeserialize
,这看起来是一个 xml 一样的解析:
这里就不装模作样的分析了,直接找到最重要的标签:
1 | coldfusion.wddx.StructHandler |
首先看 getClassBySignature
函数,这个函数获取 Class
对象 ,然后返回回去进行实例化:
然后再看上面有调用 setBeanProperties
函数:
这里就能获取 WriteMethod
然后调用 setter
,比较经典的就是利用 JdbcRowSetImpl
进行 jndi
了。
修复方法
有很多同名类啊,这里找到正确的 jar
文件:chf20230007.jar
在做 wddx
解码的时候会先到这里:
1 | coldfusion.wddx.DeserializerWorker#startElement |
如果是 struct
标签的话就进入验证,调用栈如下:
1 | coldfusion.wddx.DeserializerWorker#validateWddxFilter |
这里进行了白名单验证,不在白名单返回 UNDECIDED
,然后返回回来以后报错了:
这里看着好像就过滤了 struct
标签,不知道其他标签是否有过滤,有机会可以看看