Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)

admin 2023年12月14日13:40:49评论11 views字数 3767阅读12分33秒阅读模式

0x01 前言

前天在公众号看到石大神发的一篇审计thinkphp的文章,就想写一个分析流程,delay到了今天。昨天在先知也看到了chybeta发的一篇分析文章感觉也不错。分析过程,我也会做thinkphp部分功能的解析。
废话不多说,开始吧!

0x02 环境搭建和漏洞复现

程序下载地址:http://www.thinkphp.cn/down/1126.html
PHPstudy:Apache+php5.6+MySQL
工具:PHPstorm

  1. 首先建立一个数据库名为:thinkphp
  2. 建立一个表名为:user
  3. 添加三个字段:id,name,password

  1. 在thinkphp的数据库文件填上刚才我们建立的数据库信息:
    文件位置:\thinkphp\application\database.php
  2. 打开thinkphp的调试模式:
    文件位置:\thinkphp\application\config.php
  3. 简单写一个update功能,石大神用到了模型,这里就简单写一个例子就行了。
    文件位置:\thinkphp\application\index\controller\Index.php
<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        $password = input('get.password/a');
        db('user')->where(['id'=> 1])->update(['password'=>$password]);
    }
}

这里用到了thinkphp的助手函数input(),是专用来接收get,post等的值。具体可以看:https://www.kancloud.cn/manual/thinkphp5/118044

还有就是thinkphp的数据库操作,框架本身写好了我们调用就比较方便。所以为什么那么多人用框架去开发程序,快捷而且安全,不过也会有安全问题,就像今天这个sql漏洞,不过如果是新手的话总比自己写的好对吧哈。
具体可以看链接:https://www.kancloud.cn/manual/thinkphp5/135178
Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)
7. 现在就可以访问我们的payload了:

http://thinkphp.test/thinkphp/public/index.php?password[0]=inc&password[1]=updatexml(2,concat(0x7e,user()),0)&password[2]=1

0x03 漏洞分析

  1. 这里用phpstorm+debug来动态分析,有不懂配置的可以访问我写一篇配置文章:利用phpstorm+xdebug进行断点调试
    我们在主函数下一断点:

然后访问我们payload,它会跳到入口文件,我们只要分析的是sql执行的地方,所以我们直接F8跳到执行sql地方:

Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)
2. 我们继续跟进到loader.php它会包含thinkphp的Db.php文件,
Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)
接下还会包\thinkphp\library\think\db\connector\Mysql.php文件,主要是连接数据库的操作,这里就直接跳过了。别分析分析把自己绕进去了,我只是在这里讲诉下过程,我们还是直接分析sql执行的部分吧。
3. 我们跳到update执行的部分,文件位置:\thinkphp\library\think\db\Query.php
Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)
继续往下看,这句是执行我们sql的地方:
Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)
4. 我们F7跟进去,跳到文件位置\thinkphp\library\think\db\Builder.php
parseTable函数直接F8往下执行了,这函数是处理table分析的,主要还是parseData函数,我们继续F7跟进
Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)
5. 我们继续往下跟进
Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)
我们看到了这里如果传入的值为数组形式的话,并且第一个参数为inc就执行switch所对应的的语句。

可以看到这里函数对我们传入的值没有做任何处理,返回内容仍然是我们的语句:

跟到后面返回的执行sql语句:

执行完,我们跟进到报错的地方,说明我的语句执行成功:
Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)
6.到这里就差不多结束了,有人问,为什么要这样给数组三个字段?
我们可以看到我们刚才传入数组的地方,分别有三个数组
Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)
到后面返回$result的时候就组合在一起了:

下面是parseData的代码:

 protected function parseData($data, $options)
    {
        if (empty($data)) {
            return [];
        }

        // 获取绑定信息
        $bind = $this->query->getFieldsBind($options['table']);
        if ('*' == $options['field']) {
            $fields = array_keys($bind);
        } else {
            $fields = $options['field'];
        }

        $result = [];
        foreach ($data as $key => $val) {
            $item = $this->parseKey($key, $options);
            if (is_object($val) && method_exists($val, '__toString')) {
                // 对象数据写入
                $val = $val->__toString();
            }
            if (false === strpos($key, '.') && !in_array($key, $fields, true)) {
                if ($options['strict']) {
                    throw new Exception('fields not exists:[' . $key . ']');
                }
            } elseif (is_null($val)) {
                $result[$item] = 'NULL';
            } elseif (is_array($val) && !empty($val)) {
                switch ($val[0]) {
                    case 'exp':
                        $result[$item] = $val[1];
                        break;
                    case 'inc':
                        $result[$item] = $this->parseKey($val[1]) . '+' . floatval($val[2]);
                        break;
                    case 'dec':
                        $result[$item] = $this->parseKey($val[1]) . '-' . floatval($val[2]);
                        break;
                }
            } elseif (is_scalar($val)) {
                // 过滤非标量数据
                if (0 === strpos($val, ':') && $this->query->isBind(substr($val, 1))) {
                    $result[$item] = $val;
                } else {
                    $key = str_replace('.', '_', $key);
                    $this->query->bind('data__' . $key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR);
                    $result[$item] = ':data__' . $key;
                }
            }
        }
        return $result;
    }

0x04 结束

如果看不懂的,可以先去了解一下thinkphp这个框架,其他框架大同小异。如果里面一些PHP代码看不懂的话,可以去复习下PHP。

0x05 参考

https://www.kancloud.cn/manual/thinkphp5/

https://mp.weixin.qq.com/s?__biz=MzU2NzE3MTU0Mw==&mid=2247483720&idx=1&sn=973bd7daa287a9e9c0171e852db6cb6b&chksm=fca001f0cbd788e6ed3119de5d3c4bfc3325205c5dd7f296e55a2ba313f73b3808525d1022e6&mpshare=1&scene=23&srcid=04104vXPMKRNVfrVzzzg7HXg

https://chybeta.github.io/2018/04/10/Thinkphp%E6%A1%86%E6%9E%B6-5-0-16-sql%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/


  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月14日13:40:49
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Thinkphp框架 < 5.0.16 sql注入漏洞分析(每日一洞)http://cn-sec.com/archives/2298250.html

发表评论

匿名网友 填写信息