一、漏洞概述

简介:Subrion是一款国外的开源CMS,支持多种建站类型。

环境:PHP5.4+/MySQL5.0+

漏洞编号:CVE-2017-11444

漏洞名称:Subrion CMS注入漏洞

漏洞等级:高

官方描述:

Subrion CMS before 4.1.5.10 has a SQL injection vulnerability in /front/search.php via the $_GET array.

影响范围:before 4.1.5.10

二、漏洞分析

漏洞发生在搜索功能上,这里的搜索包含两种方式,一个常规的字符串搜索,一个是json形式的搜索。

搜索时会调用\front\search.php,里面有两个主要的判断,一个是

另一个

漏洞发生在json形式的搜索,这里主要看第一个if$iaView->getRequestType()是对URL格式的获取,要满足第一个判断,需要搜索的URL为这种形式(最后的部分.json结尾):

返回的搜索结果也是json形式。然后是第二个if,判断传参形式(POST或GET),漏洞发生在GET形式上,略过POST的if块。

59行$itemName获取的是搜索时请求的json文件名,比如上面那个截图,$itemName值则为test。这里的xxx.json任意写入也都会有返回,只是不在设定的范围内的话返回的json就一直是空的。第61行就开始判断json文件名是不是在设定的范围内,跟进$iaItem->getItems()

再跟进

跟进

最后返回给$iaItem->getItems()的值为

也就是说使用json形式的搜索时文件名只能设置为memberstransactions,然后又是一个HTTP_REFERER的判断,因为漏洞要在下面的语句触发,所以直接在http头中去掉HTTP_REFERER,绕过判断进入下面的语句。$_GET既是查询的参数。

doAjaxItemSearch函数在\includes\classes\ia.front.search.php 110行

一系列处理后,首先是一个if判断,这里是判断$itemName是否为members

所以json搜索时要使用members.json;然后是一个参数检索函数_processParams,将$params数组中的一些空值和不符合查询条件的值去掉,再将查询数组赋值给$this->_params。再回到doAjaxItemSearch函数,下一步进入_callInstanceMethod函数。跟进

使用call_user_func_array动态调用ia.core.user.php中的coreSearch函数,因为fieldsSearch=true,那么参数就是_getQueryStmtByParams的执行结果。跟进_getQueryStmtByParams函数,其作用是将查询数组转换为键值对的字符串形式。

中间有一个转义函数,连续跟进后发现其作用是对参数的值进行转义处理(问题出现在了这,先往下看)


在入口文件index.php中对GPC可能添加的反斜杠也提前做了处理

接下来返回到_getQueryStmtByParams函数中,中间有一段switch语句并不执行,然后将查询的参数名和值放到$statements数组中,并加入了'col' => $column'cond' => $condition两个字段,然后在下一步的处理中去掉'col' => $column,将$statements这个二维数组,将其变成了一维数组,其值为键值对的查询参数

最后一句再将一维数组拼接成字符串,然后返回。

比如若一开始输入的查询字符串为?id=1,到这一步返回的字符串为(id= '1'),然后接下来进入到ia.core.user.php中的coreSearch函数。

首先判断会员功能是否启用,默认开启,跟进$stmt的处理,经过844行的处理多加了一个and条件,然后进入\includes\classes\ia.core.mysql.php中的all函数

一个简单的判断再进入同文件的_get函数

$condition变量就是我们输入的查询参数,string类型,直接拼接sql语句。接着往后跟,type=all,所以之后进入getAll函数

执行sql

那么注入怎么产生的呢,先做几个输出测试,火狐的话要在查看源码的状态下,不然会提示json错误不显示数据。先输入一个id=520

如果输入这么一个字符串

由于条件永真,所以输出了所有的数据。我们前面也提到的漏洞形成的原因,就是因为程序只对对的值做了检测,而没有考虑,导致如果在id这个键名上加`就不会有处理,另外程序也缺乏恶意字符串的检测,导致注入语句的构造相对容易,然后就可以获取数据

/subrion/search/members.json?id`%3D520)%2f**%2funion%2f**%2fselect%2f**%2f1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2Cuser()%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%2C24%2C25%2C26%2C27%2C28%2C29%2C30%2C31%2C32%23sqli=1

以上是对CVE-2017-11444的分析,但是仔细想想,问题发生在过滤键值对的问题上,程序中只要是通过$_GET$_POST或其他直接获取参数数组的地方应该都有问题,于是又看了看别的地方,比如在常规的搜索上

如果我们不传入搜索参数q,那么最终还是直接获取$_GET数组参数,URL构造上还是要加上members以绕过115行的if判断,所以构造如下的URL即可:

/subrion/search/members/?id`%3D520)%2f**%2funion%2f**%2fselect%2f**%2f1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2Cuser()%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%2C24%2C25%2C26%2C27%2C28%2C29%2C30%2C31%2C32%23sqli=1

三、补丁分析

最新版已修复此漏洞,在程序逻辑和过滤上都做了修复。逻辑上的修复比较猥琐,将\includes\classes\ia.core.user.php中的变量$_itemName由members改为member

这就导致在执行\includes\classes\ia.front.search.php中的doAjaxItemSearch函数时其中一步的if判断过不去,注入也就无法成功了。

然后在\includes\classes\ia.front.search.php中的_processParams函数(参数检索函数,将$params数组中的一些空值和不符合查询条件的值去掉,再将查询数组赋值给$this->_params)中引入了一个新函数,对键名做了过滤

跟进去

此函数的作用是将数字、字母和下划线之外的字符都删掉,所以即使第一步的逻辑处理绕过去我们输入的数据也会变成这样

所以升级最新版即可修复漏洞,github链接:https://github.com/intelliants/subrion

源链接

Hacking more

...