ThinkCMFX2.2.2多处SQL注⼊漏洞分析
1. 漏洞描述
ThinkCMF是⼀款基于ThinkPHP+MySQL开发的中⽂内容管理框架,其中X系列基于ThinkPHP 3.2.3开发,最后更新到2.2.2版本。最近刚好在渗透测试项⽬中遇到这个CMS,便审了下源码发现多处SQL注⼊漏洞,在Github给项⽬⽅提issues后,提交到CVE官⽅后很快就拿到了分配的多个编号:CVE-2018-19894、CVE-2018-19895、CVE-2018-19896、CVE-2018-19897、CVE-2018-19898。
2. 影响版本
3. 漏洞分析
3.1 CommentadminController.class.php check、delete⽅法SQL注⼊(CVE-2018-19894)
漏洞位于/application/Comment/Controller/CommentadminController.class.php的check、delete⽅法,以62⾏为例,$_POST['ids']参数通过join后,传递到where语句中,但并没有使⽤where语句的in⽅法,⽽是直接拼接到SQL语句中,导致SQL注⼊。
测试Pyload为
POST: ids[]=1&ids[]=2 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
3.2 NavController.class.php中edit_post⽅法SQL注⼊(CVE-2018-19895)
跟进`application/Admin/Controller/NavController.class.php`,在⽂件的173⾏。`$parentid`直接由`$_POST['parentid']`传递进来,随后被直接拼接到where语句中。
测试Payload为
POST: parentid=1 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
3.3 SlideController.class.php delete⽅法SQL注⼊(CVE-2018-19896)
在application/Admin/Controller/SlideController.class.php的93⾏,delete⽅法中,$_POST['ids']通过implode⽅法变成字符串,随后直接拼接进⼊where语句的in⼦句中。
测试payload:
POST: ids[]=1&ids[]=0 and updatexml(1, concat(0x7e,user(),0x7e),1)
3.4 AdminbaseController.class.php中_listorders⽅法存在SQL注⼊(CVE-2018-19897)
_listorders⽅法⽤于排序,在很多地⽅被调⽤。这⾥以LinkController.class.php中的listorders()为例进⾏分析,这⾥主要⽤做友情链接的排序。我们以phpstorm+phpstudy+ xdebug打下断点,⼀步步追踪。测试payload为:
POST: listorders[key][0]=exp&listorders[key][1]=0 and updatexml(1, concat(0x7e,user(),0),1)xpath注入和xml注入
⾸先进⼊application/Admin/Controller/LinkController.class.php 70⾏的listorders⽅法,71⾏调⽤⽗类的_listorders()⽅法。
跟到application/Admin/Controller/LinkController.class.php 166⾏的_listorders()⽅法,$_POST['listorders']为⼆维数组传递给$ids,经
过foreach循环,输⼊的payload进⼊$data中,仍然为⼆维数组,⽽$data则进⼊save⽅法。
跟进到simplewind/Core/Library/Think/Model.class.php 396⾏的save⽅法,该⽅法为thinkphp的核⼼函数。由于$data不为空,跳过之前的很多判断直接到452⾏,$data和$options进⼊update⽅法,$data仍然为⼆维数组不变。
跟进到simplewind/Core/Library/Think/Db/Driver.class.php 893⾏的update()⽅法,$data经过parseSet⽅法后拼接到$sql中。跟
到371⾏parseSet⽅法的定义,$data经过foreach循环后,$val变为⼀维数组,$key为键值。⽽当$val为数组并且数组的第⼀个元素
为exp时,$val[1]会和$key直接⽤等号拼接传递到$set,387⾏数组$set被逗号implode后拼接到SET⼦句中。
返回到update⽅法,SET⼦句被拼接到$sql中,最终执⾏的sql语句为
UPDATE `cmf_links` SET `listorder`=0 and updatexml(1, concat(0x7e,user(),0),1) WHERE `link_id` = 'key'
3.5 ArticleController.class.php edit_post⽅法SQL注⼊(CVE-2018-19898)
ThinkCMF X2.2.2是基于ThinkPHP 3.2.3开发的,ThinkPHP 3.x版本之前被爆出存在bind注⼊,这个漏洞就是ThinkPHP3.x注⼊的典型案例。漏洞位于前台⽂章编辑处,测试payload如下:
POST: post[id][0]=bind&post[id][1]=0 and updatexml(1, concat(0x7e,user(),0x7e),1)-- -
在application/Portal/Controller/ArticleController.class.php 182⾏,输⼊的参数通过I("post.post")传递到$article;跟进
到/simplewind/Core/Common/functions.php的I⽅法定义,在428⾏,会调⽤think_filter⽅法对参数进⾏过滤。
由于正则字符中没有匹配bind,所以导致了后⾯的注⼊漏洞,ThinkPHP官⽅的修复措施就是在此处匹配时加上了bind。接下来进⼊典型的数据库更新操作了,$articles为多维数组包含payload。
我们F7继续跟进,会进⼊simplewind/Core/Library/Think/Model.class.php的where⽅法,给$this->options['where']赋值后,返回当前对象。随后进⼊simplewind/Core/Library/Think/Model.class.php的save⽅法,随后执⾏到update⽅法
继续往下,进⼊到parseSet⽅法,可以看到传递的参数在进⾏参数绑定操作,其中时间字符串被赋于占位符0,此处会进⾏循环操作,将所有的参数进⾏绑定。
随后进⼊parseWhere函数
分析parseWhere后,发现会执⾏ parseWhereItem⽅法,当$exp=='bind'的时候即$val[0]=='bind',会对$val[1]进⾏拼接,仔细看这⾥会多⼀个`:`,表⽰为参数绑定时的占位符。
这⾥也就理解为什么第⼆个数组构造的时候需要添加⼀个数字0,这是由于parseSet⽅法以及赋值了⼀个占位符:0,⽤来替代时间字符串,在随后的SQL语句执⾏阶段可被⽤来赋值,否则占位符没被赋值会
因语法问题产⽣报错。
随后可以看到bindValue将:0绑定为时间字符串,实际上这⾥有三个参数需要绑定,因此第⼆个数组的⾸位值可以为0、1、2。
执⾏时产⽣XPATH异常报错,得到我们想要的数据。
4. 修复建议
由于ThinkCMF X系列在2.2.2版本后已经不再更新,建议⽤户及时升级到Think CMF5。
欢迎关注,有问题⼀起学习欢迎留⾔、评论
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论