从某cmsV9.9四个漏洞看程序开发安全

2019-08-12 约 152 字 预计阅读 1 分钟

声明:本文 【从某cmsV9.9四个漏洞看程序开发安全】 由作者 熊本熊本熊 于 2019-08-12 07:36:00 首发 先知社区 曾经 浏览数 237 次

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

前言

近日,对某cmsV9.9版本进行代码审计,发现了4处漏洞。

这4处漏洞漏洞比较基础,也很经典。从这4处漏洞,可以反应了在程序开发过程中一些容易忽略的问题,下面分享下本次审计过程。

审计之旅

在开发程序时,如果没有正确的过滤单引号(')、双引号(")、反斜杠(\)等特殊字符,往往会产生代码/sql注入漏洞。

在针对这些特殊字符,开发者经常使用如下方式进行过滤:

  1. 使用addslashes进行过滤
  2. 使用str_replace对单引号等进行替换操作
  3. 使用is_numeric等方法对数字类型的输入进行判断与过滤

审计此cms时发现,以上3种方式,在此程序的开发过程中,都有使用。但是,不严谨的使用,使得注入漏洞仍然存在

首先分析下此cms,来看下\include\common.php文件

如上图,在common.php文件中require filter.inc.php

在filter.inc.php文件中,存在如下图代码

此cms使用伪全局变量的模式,使用foreach从’_GET','_POST','_COOKIE’中遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值过滤后作为变量的值

跟进_FilterAll

可见,程序在此处使用addslashes对键值进行过滤

这样一来,我们可以通过’_GET','_POST','_COOKIE’为程序中的任意参数传入值,但是传入的值会被addslashes过滤

例如 http://www.testcms.com/index.php?grq=1'23

程序接收此url后,程序中的grq变量会为:$grq="1\'23"

开发者对这样的处理方式仍然不放心,于是,在\include\common.php文件中require_once(sea_INC."/filter.inc.php")进行过滤后,再次从’_GET','_POST','_COOKIE’中取键值对进行伪全局变量赋值与过滤

跟进_RunMagicQuotes方法

_RunMagicQuotes方法中对键值使用addslashes进行过滤与赋值变量

以上两段代码依次执行,对比下这两处代码
filter.inc.php文件中的过滤与赋值代码

common.php文件中的过滤与赋值代码

filter.inc.php文件中赋值的${$k}被后续common.php文件中的${$k}覆盖了,filter.inc.php文件中的过滤部分代码白写了

虽说filter.inc.php过滤部分代码在做无用功,但是仍然可以看出开发者对特殊字符的防范意识很高

在了解完该程序之后,接下来漏洞:

1.未对拼接参数使用单引号闭合而导致的sql注入漏洞


位于上图143行处

经过上文对程序伪全局变量赋值方式的分析可知,这里$leftSelect 可由GET方法传递的来。当使用GET传入$leftSelect时,程序会使用addslashes对参数进行过滤

但是如上图143行拼接的sql语句来看,并未对$leftSelect变量使用单引号进行闭合,导致虽然使用addslashes函数进行过滤,但仍然存在sql注入漏洞
构造payload
&leftSelect=1 or updatexml(1,concat(0x7,user(),0x7e),1)

最终执行的sql语句是:

UPDATE sea_data SET tid= 1 where tid= 1 or updatexml(1,concat(0x7,user(),0x7e),1)

同样,在另一处文件中admin_tempvideo.php, 也存在相同的漏洞


如上图可见,$ids变量被拼接到sql语句中,并在上图25行被执行

$ids变量由$e_id通过implode方法拼接而来,而$e_id变量可以通过GET方法直接传入,$e_id变量可控,由此造成sql注入漏洞

构造的payload如下

&e_id[0]=1)%20or%20extractvalue(1,concat(0x7e,(SELECT%20CONCAT_WS(0x23,name,%20password)%20FROM%20sea_admin%20limit%200,1)))--%20&type=1 or extractvalue(1,concat(0x7e,(SELECT CONCAT_WS(0x23,name, password) FROM sea_admin limit 0,1)))-- &type=1)

2.对键值进行过滤,忘记对键名进行处理

漏洞文件: admin_config.php

如上图,看到将$configstr变量写入文件中去

查看下写入文件的具体位置

该位置固定,即为/data/config.cache.inc.php

config.cache.inc.php

跟踪下$configstr变量

$configstr变量由$k与$v拼接而来,

在下图红框中所示,$$k的值经过str_replace方法过滤

在程序入口处,通过伪全局变量的方式,其实已经对$_POST中的$k进行变量赋值,所以$$k的值即为通过POST传入的变量的经过过滤的键值

例如POST中

&edit___grq=te’st

那么,此时的$k=“&editgrq”,$&editgrq=”te\’st”,$$k=” te\’st”

值得注意的是,上图中仅仅对$$k 进行str_replace处理,而$k并没有经过任何过滤,直接拼接到$configstr变量中,也就是说,可以通过POST提交的KEY值传递构造好的payload,该payload将会被写入文件中去,造成远程代码执行

回头看一下config.cache.inc.php文件

开发者在写过滤代码时,考虑到程序在处理配置文件经常会出现漏洞:即配置文件中变量值注入的问题

在以往的此类漏洞中,往往是未对配置文件中变量值进行合理的过滤,导致单引号等特殊字符被写入值部分,从而构造闭合结果导致注入的产生。

所以,开发者吸取了以往的经验,对写入配置文件中的值部分进行str_replace处理,对”’”与”\”进行转义。但是,由于这里的变量名同样可控,而且未对变量名进行任何过滤,因此,str_replace处理形同虚设

使用如下payload,直接注入

&edit___a;phpinfo();//=1

3.经过严格的过滤,报错日志文件中却存在利用点

漏洞触发点位于\comment\api\index.php

由于seacms采用伪全局变量的形式,$page $id等变量可以从GET请求参数中传递进来

程序使用is_numeric对$page进行限制,使得$page必须是数字

上图最下面一行,$h = ReadData($id,$page);

可见将GET请求传入的$id,$page 传递进ReadDate方法中

跟入ReadDate方法

可见GET请求传入的$id,$page 传递进Readmlist方法中

跟进Readmlist方法

在Readmlist方法中的88行,可见存在一处sql语句

可以看到,该sql语句中拼接了$page变量,而$page变量是由GET请求接收而来,可控

当我们通过GET请求传递一个负数值的page时(例如-1),此时执行的sql语句为
SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=1 AND v_id=666 ORDER BY id DESC limit -20,10

该sql语句会导致sql语法错误而报错,如下图

到此为止,程序仍然是安全的,并不存在sql注入或是代码执行漏洞。但是此cms对报错日志的处理方式,却很有意思:

当sql语法出现错误时,程序会将报错日志会被写入\data\mysqli_error_trace.php

跟进mysqli_error_trace.php文件,错误日志的格式如上图:

错误日志会被<?php ?>包裹

第一行(第一个红框)为触发错误的url

第二行(第二个红框)为sql语法错误信息

因此,当构造payload如下时

comment/api/index.php?page=-1&gid=666&payload=/phpinfo();/

执行成功后,可见成功写入mysqli_error_trace.php,如下图:

访问/data/mysqli_error_trace.php

即可执行phpinfo

结束语

从本次代码审计的结果来看,程序在使用addslashes等过滤方式对输入进行过滤后,仍然产生了两处代码执行,两处sql注入。因此使用addslashes等过滤方式在程序入口处对输入进行过滤并不能代表程序固若金汤。配合程序自身的逻辑,使用恰当的方式进行参数过滤才是最优解。

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


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