简介: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
形式的搜索时文件名只能设置为members
或transactions
,然后又是一个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