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 < 5.1.23

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 | phpmv 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.然后在阅读器中拜访  

image.png假如呈现该页面,则证明装置成功。

3.Demo示例

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

4.数据库

与Demo文件婚配,需求创立一个user表,然后设一个字段(id)。

image.png

三、破绽细节

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

image.png

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

依据破绽修复补丁,晓得破绽发作在parseOrderField()函数中。

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

跟踪parseOrderField()函数

image.png

getOptions()函数是获取了以后要查询的参数,getFieldsBind()函数是获取数据表绑定信息,foreach循环是对$val值停止了处置,这里其实不是重点,就提一下。$val值是什麼不必管,由于注入点在$key上,而$val 拼接在$key前面,可以在结构$key加#正文掉$val。

image.png

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

image.png

这里对传入的$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()函数停止数据库查询,触发破绽。BT天堂

image.png

着重阐明一下,这里由于field函数,破绽应用有两个关键点:

首先解释下field()函数:MySQL中的field()函数作用是对SQL中查询后果集停止指定顺序排序。普通与order by 一同运用。

关键点1:

field()函数必需指定大于等于两个字段才可以正常运转,否则就会报错。

image.png

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

image.png

关键点2:

当field中的参数不是字符串或数字时,指定的参数必需是正确的表字段,否则顺序就会报错。这里由于顺序会在第一个字段中加 “ 限制 ,所以必需指定正确的字段称号。第二个字段没无限制,可以指定字符串或数字。 

image.png

所以,我们要应用该破绽,第一我们至多需求晓得表中的一个字段称号,第二向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

image.png

四、静态调试剖析

 有时分单单静态剖析,很难晓得某些函数做了些什麼,而关于顺序运转进程,也很难了解透彻。而应用静态剖析,一步一步debug,就很容易了解清楚。

这里我们应用下面结构的payload停止debug。

首先下断点:

image.png

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

image.png

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

持续F7,进入了parseKey()函数。

image.png

到这里,看到$key满足if条件,然后两边加了个 ` 号。

image.png

最初前往的$key。其实就是两边加了个 ` 号 。

image.png

最初,前往给array变量的值为file字符串和$key以及$val的拼接。

持续F7,看看接上去顺序怎样走。

image.png

image.png

停止了limit剖析,union剖析等多个剖析处置,最终离开了removeoption()函数。

image.png

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

image.png

然后经过了两头的几个进程,比照上图,并没有改动sql语句内容。最初sql语句,进入query()函数执行了SQL语句,成功触发注入破绽。

五、修复建议

官方补丁

目前官方曾经更新补丁,请受影响的用户尽快晋级到ThinkPHP5.1.24版本。

手工修复

依据官方给出的方案停止代码修正。

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

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

猜你喜欢

转载自blog.csdn.net/caidaome/article/details/82998067
今日推荐