ThinkPHP 5.1.x SQL注入漏洞分析 – 互联网安全新媒体平台

一、背景先容

ThinkPHP 是一个快速、简单的基于 MVC 和面向工具的轻量级 PHP 开拓框架,遵照 Apache2 开源协议宣布。ThinkPHP从出生以来不停秉承简洁实用的设计原则,在维持出色的机能和至简的代码的同时,也重视开拓体验和易用性,为 WEB 利用和 API 开拓供给了强有力的支持。

在近期,ThinkPHP 框架被曝出存在SQL注入破绽。因为SQL注入破绽的迫害性以及该框架利用十分广泛。 对此,天融信阿尔法实验室以静态和动态两种要领对该破绽进行了深入阐发。

1.1 破绽描述

在ThinkPHP5.1.23之前的版本中存在SQL注入破绽,该破绽是因为法度榜样在处置惩罚order by 后的参数时,未精确过滤处置惩罚数组的key值所造成。假如该参数用户可控,且当通报的数据为数组时,会导致破绽的孕育发生。

1.2 受影响的系统版本

ThinkPHP 1.3 破绽编号

CVE-2018-16385

二、情况搭建

1.下载安装thinkphp5.1.x

对付thinkphp5.1.x完备版,今朝官方没有直接下载的链接。Github上只是放出核心版。该版本必要以Composer或Git要领进行安装。

这里以Composer安装要领阐明。

在 Linux 和 Mac OS X 中可以运行如下敕令:

curl -sS https://getcomposer.org/installer | php

mv composer.phar/usr/local/bin/composer

在 Windows 中,你必要下载并运行 Composer-Setup.exe 。

安装好之后,切换路径到WEB目录下运行:

composercreate-project topthink/think=5.1.1 tp5.1 –prefer-dist

然后会天生一个名为tp5.1的文件夹。到此think5.1.1下载成功。

2.然后在浏览器中造访

假如呈现该页面,则证实安装成功。

假如呈现该页面,则证实安装成功。

3.Demo示例

编写Demo文件,并将文件命名为Test.php,然后放在/tp5.1/application/index/controller/目录下。

编写Demo文件,并将文件命名为Test.php,然后放在/tp5.1/application/index/controller/目录下。

4.数据库

与Demo文件匹配,必要创建一个user表,然后设一个字段(id)。

三、破绽细节

在/thinkphp/library/think/db/Builder.php parseOrder()的函数中:

经由过程Demo传入order参数内容,当传入的$order是一个数组时,foreach函数将$order数组分为key和value形式。

根据破绽修复补丁,知道破绽发生在parseOrderField()函数中。

当$val为数组时,会进入parseOrderField()函数。

跟踪parseOrderField()函数

getOptions()函数是获取了当前要查询的参数,getFieldsBind()函数是获取数据表绑定信息,foreach轮回是对$val值进行了处置惩罚,这里着实不是重点,就提一下。$val值是什么不用管,由于注入点在$key上,而$val 拼接在$key后面,可以在构造$key加#注释掉落$val。

重点是parseKey()函数,跟踪parseKey()函数。

这里对传入的$key进行多重判断以及处置惩罚。

1. is_numeric判断,假如是数字,则返回,不是的话继承向下履行。

2. 判断$key是否属于Expression类。

3. strpos($key, ‘->’) && false ===strpos($key, ‘(‘) 。

4. (‘*’ != $key && ($strict ||!preg_match(‘/[,\’\”\*\(\)`.\s]/’, $key)))。

由于$key是我们的sql注入语句,以是1.2.3肯定不满意,而4满意。

以是此时的$key会在阁下两侧加个 ` 号。

$table不存在,不会对$key改动,以是加 ` 号后会返回$key,然后和$val以及field字符串进行拼接,再然后return赋值给array变量,紧接着,array与order by 字符串进行拼接形成order by查询语句,终极系统调用query()函数进行数据库查询,触发破绽。

着重阐明一下,这里因为field函数,破绽使用有两个关键点:

首先解释下field()函数:MySQL中的field()函数感化是对SQL中查询结果集进行指定顺序排序。一样平常与order by 一路应用。

关键点1:

field()函数必须指定大年夜于即是两个字段才可以正常运行,否则就会报错。

当表中只有一个字段时,我们可以随意指定一个数字或字符串的参数。

关键点2:

当field中的参数不是字符串或数字时,指定的参数必须是精确的表字段,否则法度榜样就会报错。这里因为法度榜样会在第一个字段中加 “ 限定 ,以是必须指定精确的字段名称。第二个字段没有限定,可以指定字符串或数字。

以是,我们要使用该破绽,第一我们至少必要知道表中的一个字段名称,第二向field()函数中中传入两个字段。第二个字段不必要知道字段名,用数字或字符串绕过即可。

Payload构造

根据以上阐发,构造payload必要满意以下前提:

1.传入的$order必如果一个数组。

2.$val 必须也是数组。

3.至少知道数据库表中的一个字段名称,并且传入两个参数。

4.闭合 ` 。

终极Payload构造如下:

http://127.0.0.1/tp5.1/public/index/test/index?order[id`,111)|updatexml(1,concat(0x3a,user()),1)%23][]=1

http://127.0.0.1/tp5.1/public/index/test/index?order[id`,’aaa’)| updatexml(1,concat(0x3a,user()),1)%23][]=1

四、动态调试阐发

无意偶尔候单单静态阐发,很难知道某些函数做了些什么,而对付法度榜样运行历程,也很难理解透彻。而使用动态阐发,一步一步debug,就很轻易理解清楚。

这里我们使用上面构造的payload进行debug。

首先下断点:

$val是个数组,进入parseOrderField()函数。F7下一步(我这里用的是phpstorm,F7是单步调试的意思)。

foreach轮回后,可以看到只是处置惩罚了$val,并没有涉及$key(我们的关注点在$key)。$val 的值是在$key的根基上加了个:data__前缀,后面加了个0。

继承F7,进入了parseKey()函数。

到这里,看到$key满意if前提,然后两边加了个 ` 号。

着末返回的$key。着实便是两边加了个 ` 号 。

着末,返回给array变量的值为file字符串和$key以及$val的拼接。

继承F7,看看接下来法度榜样怎么走。

进行了limit阐发,union阐发等多个阐发处置惩罚,终极来到了removeoption()函数。

可以看到这里的$sql,已经可以触发注入破绽。

然后颠最后中心的几个历程,比较上图,并没有改变sql语句内容。着末sql语句,进入query()函数履行了SQL语句,成功触发注入破绽。

五、修复建议官方补丁

今朝官方已经更新补丁,请受影响的用户尽快进级到ThinkPHP5.1.24版本。

手工修复

根据官方给出的规划进行代码改动。

https://github.com/top-think/framework/commit/f0f9fc71b8b3716bd2abdf9518bcdf1897bb776

*本文作者:alphalab,转载请注明来自.COM

赞(0) 打赏
分享到: 更多 (0)
免责申明:本站所有资料均来自于网络,版权归原创者所有!本站不提供任何保证,不保证真实性,并不承担任何法律责任

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

阿里云优惠网 更专业 更优惠

阿里云优惠券阿里云大礼包