整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

「ThinkPHP5开发连载十三」页面跳转

「ThinkPHP5开发连载十三」页面跳转

一篇文章讲解“空操作+空控制器”,本篇文章讲解“页面跳转”。


在应用开发中,经常会遇到一些带有提示信息的跳转页面,例如操作成功或者操作错误页面,并且自动跳转到另外一个目标页面。系统的\think\Controller类内置了两个跳转方法success和error,用于页面跳转提示。


1. 使用

使用方法较为简单,不具体举例,直接进行测试使用。

浏览器访问:

将$flg的值设为0,程序走else错误提示,浏览器重新访问:

注意:

1. 跳转地址是可选的,success方法的默认跳转地址是$_SERVER["HTTP_REFERER"],error方法的默认跳转地址是javascript:history.back(-1);。

2. 默认的等待时间都是3秒。

3. 当不继承控制器类使用success或error方法时,需要导入跳转类的命名空间“use traits\controller\Jump”。


2. 跳转模板

1)跳转模板位置

success和error方法都可以对应的模板,默认的设置是两个方法对应的模板都是:

这是官方给的跳转模板,可以修改此模板,但一般不做修改。如果需要重新定义跳转模板,可以自定义。

2)自定义跳转模板

①配置项

②修改配置项

修改跳转模板的配置项,设置为项目内的模板。

注意:

1. 完整路径为:

'dispatch_success_tmpl'=> APP_PATH . 'index' . DS .'view/public/success.html',

2. 写完整路径,可定位到任何位置。

③新建success与error模板

④浏览器访问

模板文件可以使用模板标签,并且可以使用下面的模板变量:


3. 小版本错误

对于success与error,官方给出了一项注意点:

error方法会自动判断当前请求是否属于Ajax请求,如果属于Ajax请求则会自动转换为default_ajax_return配置的格式返回信息。success在Ajax请求下不返回信息,需要开发者自行处理。

针对以上的注意,我们测试一下是否正确,此时使用的ThinkPHP版本为5.0.12。ThinkPHP版本号在thinkphp/base.php中。

测试步骤:

①在Index控制器中新建testBug方法,主要用来展示html页面。

②新建testbug.html模板,模板中要有ajax。

模板位置:application/index/view/index/testbug.html

③在Index控制器中新建fanHui方法,此方法进行success和error的返回。

④浏览器访问testBug方法,点击“调用”按钮。

调整if判断的年龄,让其走else的error。

注意:

1. 经测试5.0.12版本,ajax请求时,success与error方法均返回信息,返回数据格式与default_ajax_return配置项设定相同。

2. 官方给出success在ajax请求时不返回信息,是个bug。

ThinkPHP5连载为卓象程序员原创,转载请联系卓象程序员

关注卓象程序员,定期发布技术文章

下一篇讲解“重定向”

洞简述

尽管ThinkPHP 5.0.x框架采用了参数化查询方式,来操作数据库,但是在 insert 和 update 方法中,传入的参数可控,且无严格过滤,最终导致本次SQL注入漏洞发生。

ThinkPHP基础知识

在进行漏洞分析之前,我们需要了解一下ThinkPHP基础知识,这里仅介绍对本次漏洞分析有帮助的部分。

ThinkPHP5.0的 目录结构

thinkphp 应用部署目录

├─application 应用目录(可设置)

│ ├─common 公共模块目录(可更改)

│ ├─index 模块目录(可更改)

│ │ ├─config.php 模块配置文件

│ │ ├─common.php 模块函数文件

│ │ ├─controller 控制器目录

│ │ ├─model 模型目录

│ │ ├─view 视图目录

│ │ └─ ... 更多类库目录

│ ├─command.php 命令行工具配置文件

│ ├─common.php 应用公共(函数)文件

│ ├─config.php 应用(公共)配置文件

│ ├─database.php 数据库配置文件

│ ├─tags.php 应用行为扩展定义文件

│ └─route.php 路由配置文件

├─extend 扩展类库目录(可定义)

├─public WEB 部署目录(对外访问目录)

│ ├─static 静态资源存放目录(css,js,image)

│ ├─index.php 应用入口文件

│ ├─router.php 快速测试文件

│ └─.htaccess 用于 apache 的重写

├─runtime 应用的运行时目录(可写,可设置)

├─vendor 第三方类库目录(Composer)

├─thinkphp 框架系统目录

│ ├─lang 语言包目录

│ ├─library 框架核心类库目录

│ │ ├─think Think 类库包目录

│ │ └─traits 系统 Traits 目录

│ ├─tpl 系统模板目录

│ ├─.htaccess 用于 apache 的重写

│ ├─.travis.yml CI 定义文件

│ ├─base.php 基础定义文件

│ ├─composer.json composer 定义文件

│ ├─console.php 控制台入口文件

│ ├─convention.php 惯例配置文件

│ ├─helper.php 助手函数文件(可选)

│ ├─LICENSE.txt 授权说明文件

│ ├─phpunit.xml 单元测试配置文件

│ ├─README.md README 文件

│ └─start.php 框架引导文件

├─build.php 自动生成定义文件(参考)

├─composer.json composer 定义文件

├─LICENSE.txt 授权说明文件

├─README.md README 文件

├─think 命令行入口文件

我们本次的 payload 为:http://localhost/thinkphp/public/index.php/index/index/index?name[0]=inc&name[1]=updatexml(1,concat(0x7,user(),0x7e),1)&name[2]=1 ,解释如下:

http://localhost/thinkphp/ public/ index.php/ index/ index/ index 域名 网站目录 对外访问目录 入口文件 前台 控制器 方法名

变量获取

	$name=input("get.name/a");
input()为TP框架的助手函数,get.name/a 表示获取get传入的name变量,并将其强制转换为数组类型

数据库查询

	Db::table("users")->where(["id"=>1])->insert(["username"=>$name]);
TP框架采用的是PDO方式对数据库进行查询

环境搭建

在了解了基本知识后,我们可以开始搭建环境。这里我们使用ThinkPHP 5.0.14版本来进行实验,下载地址:http://www.thinkphp.cn/download/1107.html

我们先安装好phpstudy,然后将下载好的ThinkPHP 5.0.14解压至phpstudy的网站根目录下,安装ThinkPHP 5.0.14需要Mbstring、PDO、Curl三个插件,php版本这里用5.6。

接着我们需要配置连接数据库的文件,并开启thinkphp的调试功能。在此之前,你需要先在数据库中创建用于测试的数据,例如这里我用thinkphp作为数据库名,那么就在mysql命令行下执行create database thinkphp; 然后在建立一个users表,列名有id,username,password,执行create table users(id int auto_increment primary key,username varchar(20),password varchar(30)); 即可,最后我们往表中插入测试数据,命令行执行insert into users(id,username,password) values(1,"test","thinkphp"); 这样就算测试数据创建成功了。

配置连接数据库的文件,并开启thinkphp的调试功能,如下图:

最后修改文件 application\index\controller\Index.php 的内容,如下:

<?php
namespace app\index\controller;
use think\Db;
class Index
{
 public function index()
 {
 $name=input("get.name/a");
 Db::table("users")->where(["id"=>1])->insert(["username"=>$name]);
 return "ThinkPHP SQL Test.";
 }
}

修改好后,访问我们的payload就可以触发漏洞了

漏洞分析

首先,我们知道 insert 方法存在漏洞,那就查看 insert 方法的具体实现。该方法位于 thinkphp\library\think\db\Builder.php 文件中,我们可以看到在函数开头调用了 parseData 方法,并将 $data 作为参数传入, $data 的值是我们通过 get方式传入的一个数组类型的数据,如下图:

我们跟进 parseData 方法,该方法也在 thinkphp\library\think\db\Builder.php 文件中。可以看到,在结尾处有个switch语句,而且进入该语句后,会跳到case 'inc'的地方,这里关键就是看看 $this->parseKey 是否有对 $val[1] 变量进行过滤了,因为 $val[1] 变量就是我们payload中的updatexml(1,concat(0x7,user(),0x7e),1) ,如下图:

继续跟进 parseKey 方法,会发现直接将传入的 $key 返回了,没有进行任何过滤。

我们再回到最开始的 insert 方法,加上调试语句,看看此时的sql语句变成了什么样子,如下图:

另一处update函数的注入与这个insert是类似的,这里就不在赘述。

总结

笔者也是第一次审计Thinkphp框架,在审计这套框架前还找了网络上的视频快速入门了下,再结合Thinkphp5.0手册,完成此次漏洞的审计。当然,文章有不当之处,还希望大家斧正。

一篇文章讲解“模型-事件”,本篇文章讲解“模板-变量输出一”。


变量输出

在模板中输出变量的方法很简单。

1. 变量输出的基本用法

①新建Index控制器,并新建index方法,为模板变量赋值

②在index控制器的index模板中输出变量

预览:

注意:

1. 注意模板标签的{和$之间不能有任何的空格,否则标签无效。

2. 模板标签的变量输出根据变量类型有所区别。


2. 输出数组

字符串输出时直接使用变量名,当输出数组时,有两种方法。

①在Index控制器中新建outarr方法

②在index.html模板中输出数组变量

预览:

注意:

1. 当我们要输出多维数组的时候,往往要采用第二种方式。


3. 输出对象

①在Index控制器中新建outobj方法

②在index.html模板中输出对象

预览:

注意:

1. 也可以直接调用对象的常量或者方法

常量:{$data::CONST_NAME}

方法:{$data->fun()}


使用默认值

1. 变量输出使用默认值

我们可以给变量输出提供默认值。

①在Index控制器中新建outde方法

②在index.html模板中输出

预览:


2. 系统变量使用默认值

对系统变量依然可以支持默认值输出。

Index控制器的outde方法不变,在index.html模板中输出系统变量。

预览:


3. 默认值和函数同时使用

①在公共函数中创建函数

②在index.html模板中输出

预览:

ThinkPHP5连载为卓象程序员原创,转载请联系卓象程序员

关注卓象程序员,定期发布技术文章

下一篇讲解“模板-变量输出二”