[漏洞复现]thinkphp3.2

编程入门 行业动态 更新时间:2024-10-27 15:25:55

个人博客地址

darkerbox.

欢迎大家学习交流

参考网址:

xz.aliyun./t/2629#toc-3

环境:

链接:pan.baidu./s/1DyHy1Z-IPhPFzQC_mEIZeQ 
提取码:8vxn 

漏洞概述

如何搭建环境我就不细说了,可以参照参考网址里的步骤搭建。
还需要phpstorm配合xdebug调试,网上教程很多,不多介绍了。

漏洞利用

搭建好环境后,直接上payload,测试是否正常。我本地搭建到了8083端口

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对象‘。module,这个变量是一个对象,即上图中的控制器实例,也就是`IndexController.class.php中的IndexController对象`。module,这个变量是一个对象,即上图中的控制器实例,也就是‘IndexController.class.php中的IndexController对象‘。action即我们的a参数的值,跟进。


在127行实例化了ReflectionMethod对象,这个是php的类,具体作用我也解释不清楚。

继续来到177行,这里的$method即ReflectionMethod对象,moudle是‘IndexController‘对象,moudle是`IndexController`对象,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;}

不具体分析了,文中可能不对的地方有点多,刚学习,望见谅,如果哪里不对,可以到评论区评论,我会及时改正,谢谢

欢迎大家一起学习交流,共同进步,欢迎加入信息安全小白群

更多推荐

漏洞

本文发布于:2023-05-25 10:58:39,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/226669.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:漏洞

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!