从某cmsV4.1.0 sql注入漏洞看程序开发安全隐患

2019-09-11 约 2845 字 预计阅读 6 分钟

声明:本文 【从某cmsV4.1.0 sql注入漏洞看程序开发安全隐患】 由作者 熊本熊本熊 于 2019-09-10 08:54:34 首发 先知社区 曾经 浏览数 1570 次

感谢 熊本熊本熊 的辛苦付出!

为了大致了解此cms,首先来看看这个cms为了防止sql注入,都做了哪些防护

一、程序入口处定义了过滤方法

首先,程序通过set_globals方法,将get与post传入的参数,赋值到$GLOBALS数组中:

在赋值过程中,使用gpc_stripslashes来处理传入的键值

gpc_stripslashes方法的作用是,当MAGIC_QUOTES_GPC开启时,去除MAGIC_QUOTES_GPC所添加的转义符

这里的操作很奇特,在一般的cms中,在进行这样为伪全局变量赋值时,往往会判断MAGIC_QUOTES_GPC是否开启,当MAGIC_QUOTES_GPC为off时,程序会履行MAGIC_QUOTES_GPC的功能,为伪全局变量进行转义过滤。

如下图,另一款cms中的操作:

但是在本文中分析的cms中,正好反向操作,如果MAGIC_QUOTES_GPC开启,则去除其转义效果,这个cms为什么要这样做呢?接着往下看。

可见该cms存在input方法,该方法对$GLOBALS数组中的值通过sql_replace方法进行sql过滤

分析一下sql_replace方法

可见是使用str_replace方法,对传入参数中的特殊字符进行置空处理,防止sql注入攻击

此外,还存在一处safe_htm方法

对输入中的html特殊字符进行转义,方式xss攻击

开发者的意图,在这里猜测一下,应该是:

将GET\POST的传入键值对,原封不动的传递给$GLOBALS数组,若数据需要入库,使用sql_replace方法对数据进行过滤;若数据需要前端页面展示,使用safe_htm方法进行转义

通过我对开发者意图的猜测可知,之所以在将GET\POST的传入键值对传递给$GLOBALS期间使用stripslashes去掉MAGIC_QUOTES_GPC可能添加的反斜杠,是为了防止后续sql_replace等操作时出问题

例如在MAGIC_QUOTES_GPC开启时,GET中传入 grq=tes’t

此时系统会自动在单引号前加反斜线进行转义,$_GET[‘grq’]=”tes\’t”

若不使用stripslashes处理,直接赋值给$GLOBALS,则$GLOBALS[‘grq’]= ”tes\’t”

若使用sql_replace方法对$GLOBALS进行sql注入过滤,则会变成$GLOBALS[‘grq’]= ”tes\t”,多出一个反斜线,显然,这造成了极大的隐患。

那使用sql_replace方法对数据进行过滤是否安全呢?显然,单纯的将特殊字符置空,仍然有安全隐患

如果传入的值为%2%277,在经过str_replace置空后,变为%27,当程序中存在sql语句拼接执行前先解码(urldecode)的操作时,则会将%27解码为单引号,从而造成sql注入。但是这个cms中,并未存在类似 urldecode(sql_replace($grq));这样的操作,因此先不考虑sql_replace方法的绕过。

二、数据库操作类内部定义过滤方法

以该cms中封装的insert方法和update方法举例


insert方法

Update方法

可见,在该cms在使用封装的数据库操作类时,这些类内部的方法,也会对传入的数据新型过滤处理

以上两类便是该cms框架层面上对sql注入的防护,下面看看在这些防护下,是否还存在sql注入隐患

第一类安全隐患

第一类安全隐患,是由于开发者在框架中定义了安全的接收用户输入的方法(input方法),在开发过程中却忘记使用或记错这个方法的功能所导致的。

回归漏洞正文,经过我们的分析,这个cms的防护虽然繁琐,且存在绕过的风险,但只要正确使用input方法对入库前的数据进行处理,且处理后不要进行urldecode操作,那就能大概率规避sql注入问题,但是在漏洞挖掘的过程中,发现的问题却令人张目结舌

漏洞文件: \api\sms_check.php 中:

位于上图13行,可见$code变量的值由$GLOBALS[‘param’]中的值经过strip_tags方法处理后得来

接着,位于16行处,code变量被拼接到sql语句的where部分,进行执行

由上文分析下$GLOBALS[‘param’]是从GET\POST中原封不动的传来

这样一来,GLOBALS的值我们可以通过GET/POST传递。$GLOBALS['param']的值可控,进而控制$code值,随后,$code变量被拼接到sql语句中执行

难道不应该使用input方法获取GET/POST传入的参数吗?使用类似如下的代码

$code = strip_tags(input('param'));

而不是程序中使用的

$code = strip_tags($GLOBALS['param']);

显然,开发者在这里忘了之前定义的用来接收用户输入并安全过滤的”input”方法,很明显这是开发时候的失误导致的。

那是不是由于开发者的疏忽,程序中只有很少几处存在这样的问题呢?

我们全局搜索一下input方法

在系统中,仅仅有四处使用了input来接收并过滤用户的输入

跟入其中一处,如下图

可见username通过input方法,从GET/POST请求中读取username值

input方法会调用sql_replace方法进行sql注入过滤,如下图

但是,位于上图第二个红框处,又使用了一次sql_replace对输入进行过滤。在这里我猜测,可能开发者忘记了input的功能了

构造如下payload:

http://127.0.0.1/www/api/sms_check.php?param=1%27%20and%20updatexml(1,concat(0x7e,(SELECT%20@@version),0x7e),1)--%20

Sql注入成功

同理,这种类型的漏洞在此cms中大量出现

第二类安全隐患

第二类安全隐患,是由于封装的数据库操作类内部的方法,只对传入数组的键值进行过滤,而忽略了键名仍有传入payload的风险

漏洞文件: \coreframe\app\content\admin\category.php 中的add方法:

由于$formdata = $GLOBALS['form'],因此$formdata可由GET/POST传入,可控。上图87行处, $formdata被传入db->insert方法进行sql语句执行

跟进db->insert方法:

上图位于109行至116行,此处代码段对传入$data的值($values)部分通过escape_string进行过滤,但是并未对$data数组的键($field)部分进行过滤,因此可以将payload传入key部分,绕过escape_string过滤,造成sql注入

回到注入点,如下图

问题出在上图73行处,直接将GET\POST传入的值赋值给$formdata,导致可以从请求中传入数组,进而控制$formdata数组的键名

Payload为

&form[seo_description`)values(updatexml(1,concat(0x7e,version(),0x7e),1))%23]=666

最终注入结果如下图:

注入成功

同理,这种类型的漏洞在此cms中大量出现

结束语

从本次代码审计的结果来看,程序虽然在框架入口以及封装的数据库操作类中进行了过滤,但由于对过滤方法的错误使用以及过滤点不全面,导致了大量的注入产生。

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now