编程语言
首页 > 编程语言> > [漏洞复现]thinkphp3.2_find_select_delete

[漏洞复现]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方法,并传了一个moduleIndexController.class.phpIndexControllermodule,这个变量是一个对象,即上图中的控制器实例,也就是`IndexController.class.php中的IndexController对象`。module,这个变量是一个对象,即上图中的控制器实例,也就是‘IndexController.class.php中的IndexController对象‘。action即我们的a参数的值,跟进。
在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

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

在这里插入图片描述

onVict0r 发布了38 篇原创文章 · 获赞 8 · 访问量 2051 私信 关注

标签:php,App,thinkphp3.2,options,class,参数,IndexController,find,select
来源: https://blog.csdn.net/qq_41918771/article/details/103992000