索贝融媒体 /sobey-mchEditor/mch/Jzt/statistics/countJztArticleGroupByChannel2 SQL注入漏洞


漏洞简介

索贝产品中的 /sobey-mchEditor/mch/Jzt/statistics/countJztArticleGroupByChannel2 接口存在SQL注入漏洞,攻击者可以通过构造恶意的SQL语句,获取数据库中的敏感信息,甚至可能导致数据库被完全控制。

影响版本

fofa语法

icon_hash="689611853"||app="SOBEY-融媒体" || body="You need to enable JavaScript to run this app" && header="Sobey"

漏洞分析

根据漏洞信息看下mch/Jzt/statistics/countJztArticleGroupByChannel2的实现逻辑

@RequestMapping(
    value = {"countJztArticleGroupByChannel2"},
    method = {RequestMethod.GET}
)
public Response countArticleGroupByChannel2(@RequestParam("token") String token, @RequestParam("siteCode") String siteCode, @RequestParam(value = "startTime",required = false) Long startTime, @RequestParam(value = "endTime",required = false) Long endTime, @RequestParam(value = "channelId",required = false) String channelId, @RequestParam(value = "ID",required = false) String ID) {
    List args = new ArrayList();
    StringBuffer sqlBuffer = new StringBuffer("select a.num,a.channelName,a.cname from ");
    sqlBuffer.append(" (SELECT SUM(h.num) as num,h.channelName as channelName,'合计' as cname from  ");
    sqlBuffer.append(" (SELECT count(DISTINCT id) AS num,channelName,cname FROM(");
    sqlBuffer.append(" select zcnarticle.id ");
    sqlBuffer.append(" , (SELECT zcchannel.channelname FROM zcchannel INNER JOIN zccatalog ON zccatalog.prop3 = zcchannel.ChannelID ");
    sqlBuffer.append(" WHERE zccatalog.ID = zcnarticle.catalogID ) AS channelName ");
    sqlBuffer.append(" ,(SELECT zccatalog.Name FROM zccatalog INNER JOIN zcchannel ON zccatalog.prop3 = zcchannel.ChannelID WHERE zccatalog.ID = zcnarticle.catalogID ) AS cname  ");
    sqlBuffer.append("  from zcnarticle  ");
    sqlBuffer.append(" , (SELECT DISTINCT zcnarticle.id articleid FROM zcnarticle where 1=1 ");
    SchemaSQLUtil.appendInCondition(sqlBuffer, "zcnarticle.status", ARTICLE_PUBLISH_STATUS_LIST);
    SchemaSQLUtil.appendTimeConditionSQL(startTime, endTime, sqlBuffer, args, "zcnarticle.publishDate");
    sqlBuffer.append(" UNION SELECT zcnwxarticlerela.articleid FROM zcnwxarticle INNER JOIN zcnwxarticlerela ON zcnwxarticlerela.wxarticleId = zcnwxarticle.id ");
    sqlBuffer.append("  where 1=1 ");
    sqlBuffer.append(" and zcnwxarticle.ifval = '1' ");
    SchemaSQLUtil.appendInCondition(sqlBuffer, "zcnwxarticle.status", ARTICLE_PUBLISH_STATUS_LIST);
    SchemaSQLUtil.appendTimeConditionSQL(startTime, endTime, sqlBuffer, args, "zcnwxarticle.publishDate");
    sqlBuffer.append(" ) zcnarticleids ");
    sqlBuffer.append(" where zcnarticleids.articleid =zcnarticle.id ");
    sqlBuffer.append(" and zcnarticle.ifval = '1' ");
    SchemaSQLUtil.appendTimeConditionSQL(startTime, endTime, sqlBuffer, args, "zcnarticle.publishDate");
    sqlBuffer.append(" AND EXISTS ( SELECT channelname FROM zcchannel INNER JOIN zccatalog ON zccatalog.prop3 = zcchannel.ChannelID WHERE zccatalog.ID = zcnarticle.catalogID LIMIT 1)");
    if (channelId != null && ID == null) {
        sqlBuffer.append("and  catalogID in  (select distinct ID from  zccatalog where  1 = 1 ");
        sqlBuffer.append(String.format(" and prop3  in (%s) ", channelId));
        sqlBuffer.append(" ) ");
    }

    if (ID != null) {
        sqlBuffer.append(String.format(" and  catalogID  in (%s) ", ID));
    }

    sqlBuffer.append(")tmp  where  1= 1 ");
    sqlBuffer.append("  group by cname) h GROUP BY channelName UNION ");
    sqlBuffer.append("(SELECT count(DISTINCT id) AS num,channelName,cname FROM(");
    sqlBuffer.append(" select zcnarticle.id ");
    sqlBuffer.append(" , (SELECT zcchannel.channelname FROM zcchannel INNER JOIN zccatalog ON zccatalog.prop3 = zcchannel.ChannelID ");
    sqlBuffer.append(" WHERE zccatalog.ID = zcnarticle.catalogID ) AS channelName ");
    sqlBuffer.append(" ,(SELECT zccatalog.Name FROM zccatalog INNER JOIN zcchannel ON zccatalog.prop3 = zcchannel.ChannelID WHERE zccatalog.ID = zcnarticle.catalogID ) AS cname  ");
    sqlBuffer.append("  from zcnarticle  ");
    sqlBuffer.append(" , (SELECT DISTINCT zcnarticle.id articleid FROM zcnarticle where 1=1 ");
    SchemaSQLUtil.appendInCondition(sqlBuffer, "zcnarticle.status", ARTICLE_PUBLISH_STATUS_LIST);
    SchemaSQLUtil.appendTimeConditionSQL(startTime, endTime, sqlBuffer, args, "zcnarticle.publishDate");
    sqlBuffer.append(" UNION SELECT zcnwxarticlerela.articleid FROM zcnwxarticle INNER JOIN zcnwxarticlerela ON zcnwxarticlerela.wxarticleId = zcnwxarticle.id ");
    sqlBuffer.append("  where 1=1 ");
    sqlBuffer.append(" and zcnwxarticle.ifval = '1' ");
    SchemaSQLUtil.appendInCondition(sqlBuffer, "zcnwxarticle.status", ARTICLE_PUBLISH_STATUS_LIST);
    SchemaSQLUtil.appendTimeConditionSQL(startTime, endTime, sqlBuffer, args, "zcnwxarticle.publishDate");
    sqlBuffer.append(" ) zcnarticleids ");
    sqlBuffer.append(" where zcnarticleids.articleid =zcnarticle.id ");
    sqlBuffer.append(" and zcnarticle.ifval = '1' ");
    SchemaSQLUtil.appendTimeConditionSQL(startTime, endTime, sqlBuffer, args, "zcnarticle.publishDate");
    sqlBuffer.append(" AND EXISTS ( SELECT channelname FROM zcchannel INNER JOIN zccatalog ON zccatalog.prop3 = zcchannel.ChannelID WHERE zccatalog.ID = zcnarticle.catalogID LIMIT 1)");
    if (channelId != null && ID == null) {
        sqlBuffer.append("and  catalogID in  (select distinct ID from  zccatalog where  1 = 1 ");
        sqlBuffer.append(String.format(" and prop3  in (%s) ", channelId));
        sqlBuffer.append(" ) ");
    }

    if (ID != null) {
        sqlBuffer.append(String.format(" and  catalogID  in (%s) ", ID));
    }

    sqlBuffer.append(")tmp  where  1= 1 ");
    sqlBuffer.append("GROUP BY cname))as a ORDER BY a.channelName,a.cname DESC");
    QueryBuilder queryBuilder = new QueryBuilder("" + sqlBuffer, args.toArray());
    List<Map<String, Object>> data = queryBuilder.executeListMap();
    return Response.success(data);
}

代码一看就很明了了,channelId和ID无任何过滤或校验,被直接拼接在in子语句中,从而造成了SQL注入漏洞。

如果没有String.format,就不存在,因为默认的append方法底层是参数化查询。

漏洞复现

GET /sobey-mchEditor/js/..;/mch/Jzt/statistics/countJztArticleGroupByChannel2?siteCode=&token=&userCode=admin&channelId=1&catalogid=1&channelId=SQLI_POC HTTP/1.1
Host: sobey.mrxn.net

成功利用报错注入在响应回显当前数据用户


手机扫码阅读

孚盟云CRM AjaxAttachment.ashx SQL注入漏洞

疑似GFW超500GB代码、数据泄露曝光

评 论