[漏洞复现]thinkphp3.2_find_select_delete
作者:互联网
个人博客地址
http://www.darkerbox.com
欢迎大家学习交流
参考网址:
https://xz.aliyun.com/t/2629#toc-3
环境:
链接:https://pan.baidu.com/s/1DyHy1Z-IPhPFzQC_mEIZeQ
提取码:8vxn
漏洞概述
如何搭建环境我就不细说了,可以参照参考网址里的步骤搭建。
还需要phpstorm配合xdebug调试,网上教程很多,不多介绍了。
漏洞利用
搭建好环境后,直接上payload,测试是否正常。我本地搭建到了8083端口
http://127.0.0.1:8083/index.php?m=Home&c=Index&a=test&id[table]=users%20where%201%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
测试成功!!
当然没那么简单,看看到底是如何成功的。。
首先我们需要知道参数是怎么传进去的。
看到url,就可以知道参数传给了index.php
但是index.php只有短短的20几行代码,只有一个地方包含了一个名为ThinkPHP/ThinkPHP.php的文件,找到这个文件。
thinkphp文件有100行了,但大多数行都是定义常量。只有两行比较重要
加载了一个核心类文件。
加载完这个类文件后,直接调用了这个类的静态方法start()
。
这个方法也是加载了一些配置文件,定义了类的自动加载等
核心还是在App::run();
这一行,运行应用。
但是这个文件没有包含其他文件,这个App类怎么来的呢?上面刚说过定义了类的自动加载,不了解php的类的自动加载先去了解一下再回来接着看,不过影响不大。
通过下断点或者通过看类的自动加载函数都可以找到App这个类文件。
Think类和App类都在thinkphp3.2.3\ThinkPHP\Library\Think
目录下,名字叫think.class.php和app.class.php。
找到App类后,再找到App的静态方法:run()
,这个方法也是执行了一些初始化工作。此时我打开了调试器。
我先跟进了App:init()函数,在第app.class.php的38行继续跟进dispatch方法,
到了dispatcher.class.php文件中的地24行
这里调用了一个C函数。跟进一下发现该函数在functions.php中,$_config应该保存了些全局变量,因为$_config里有121个元素
依次执行完,我发现$varModule,$varController,$varAction
和我们的url传的参数一一对应,但现在还不确定就是一样的。
继续往下走,到了第140行,获取模块名称,看到后面的self::getModule($varModule)
跟进这个静态方法。发现这里$_GET[$var],即$_GET[‘m’]获取了参数m的值。即Home。
然后define('MODULE_NAME', defined('BIND_MODULE')? BIND_MODULE : self::getModule($varModule));
将获取到的m的参数值定义为常量。
之后检测这个模块是否存在。不存在则会报错。
之后到了第239和240行,可以看到,这里将$_GET['c']和$_GET['a']
分别定义为常量CONTROLLER_NAME,ACTION_NAME
到这里,已经获取到了三个参数的值,分别为m,c,a。并且都赋值给了常量。
然后执行到返回,跳出这个方法,后面是全局安全过滤。
至此App:init()也执行完了。
在App.class.php的第208行执行了exec方法。主方法
跟进这个方法
刚进去就安全检测参数CONTROLLER_NAME
了,因为没检测到,所以直接跳转到后面的else语句,创建控制器实例,传了了两个参数,第一个是控制器名字,即c参数的值,即index。第二个参数是空。这个index其实就是IndexController.class.php
中的的index。他会自动找到这个文件。
在110行调用了invokeAction
方法,并传了一个module,这个变量是一个对象,即上图中的控制器实例,也就是‘IndexController.class.php中的IndexController对象‘。action即我们的a参数的值,跟进。
在127行实例化了ReflectionMethod
对象,这个是php的类,具体作用我也解释不清楚。
继续来到177行,这里的$method即ReflectionMethod
对象,moudle是‘IndexController‘对象,action即参数a的值,即test。这行代码的作用就是调用了$moudle的test方法。跟进test方法
就是我们自己定义的test方法。
函数i在functions.php中,作用是自动获取参数值。作用即$_GET[‘id’],因为我们传入的id是一个数组,所以这里的$id也是一个数组。第十一行的users其实是表名,M(‘users’)会返回一个实例化后的model,保存的有数据库连接信息,可以查询数据。
接着又调用了find方法。漏洞在这,可以看到$options是我们的$id,即$options是可控的,传一个数组,绕过了第一个判断,至于为什么要绕过这个判断,后面会说。主要是为了绕过\$options['where'] = $where;
(个人理解)。
在第730行,获取表的主键,只要这个表的主键是一个,则$pk是字符串,如果是两个,则$pk是数组,如果主键是一个,则也会绕过第二个if的判断,因为is_array($pk)
是false。
之后进入了第751行的_parseOptions
方法
因为$options中没有where元素(上面已经绕过了),所以绕过了这个判断,之后返回。
此时的$options如下图
接着来到762行,跟进select函数
到了这里也就接近尾声了。
public function select($options=array()) {
$this->model = $options['model'];//获取model,其实就是表名
$this->parseBind(!empty($options['bind'])?$options['bind']:array());//参数绑定
$sql = $this->buildSelectSql($options);//构造sql语句
$result = $this->query($sql,!empty($options['fetch_sql']) ? true : false);//执行查询,返回结果,这里就已经将报错输出了。
return $result;
}
不具体分析了,文中可能不对的地方有点多,刚学习,望见谅,如果哪里不对,可以到评论区评论,我会及时改正,谢谢
欢迎大家一起学习交流,共同进步,欢迎加入信息安全小白群
onVict0r 发布了38 篇原创文章 · 获赞 8 · 访问量 2051 私信 关注标签:php,App,thinkphp3.2,options,class,参数,IndexController,find,select 来源: https://blog.csdn.net/qq_41918771/article/details/103992000