一篇文章講解“空操作+空控制器”,本篇文章講解“頁面跳轉(zhuǎn)”。
在應用開發(fā)中,經(jīng)常會遇到一些帶有提示信息的跳轉(zhuǎn)頁面,例如操作成功或者操作錯誤頁面,并且自動跳轉(zhuǎn)到另外一個目標頁面。系統(tǒng)的\think\Controller類內(nèi)置了兩個跳轉(zhuǎn)方法success和error,用于頁面跳轉(zhuǎn)提示。
使用方法較為簡單,不具體舉例,直接進行測試使用。
瀏覽器訪問:
將$flg的值設(shè)為0,程序走else錯誤提示,瀏覽器重新訪問:
注意:
1. 跳轉(zhuǎn)地址是可選的,success方法的默認跳轉(zhuǎn)地址是$_SERVER["HTTP_REFERER"],error方法的默認跳轉(zhuǎn)地址是javascript:history.back(-1);。
2. 默認的等待時間都是3秒。
3. 當不繼承控制器類使用success或error方法時,需要導入跳轉(zhuǎn)類的命名空間“use traits\controller\Jump”。
1)跳轉(zhuǎn)模板位置
success和error方法都可以對應的模板,默認的設(shè)置是兩個方法對應的模板都是:
這是官方給的跳轉(zhuǎn)模板,可以修改此模板,但一般不做修改。如果需要重新定義跳轉(zhuǎn)模板,可以自定義。
2)自定義跳轉(zhuǎn)模板
①配置項
②修改配置項
修改跳轉(zhuǎn)模板的配置項,設(shè)置為項目內(nèi)的模板。
注意:
1. 完整路徑為:
'dispatch_success_tmpl'=> APP_PATH . 'index' . DS .'view/public/success.html',
2. 寫完整路徑,可定位到任何位置。
③新建success與error模板
④瀏覽器訪問
模板文件可以使用模板標簽,并且可以使用下面的模板變量:
對于success與error,官方給出了一項注意點:
error方法會自動判斷當前請求是否屬于Ajax請求,如果屬于Ajax請求則會自動轉(zhuǎn)換為default_ajax_return配置的格式返回信息。success在Ajax請求下不返回信息,需要開發(fā)者自行處理。
針對以上的注意,我們測試一下是否正確,此時使用的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方法,點擊“調(diào)用”按鈕。
調(diào)整if判斷的年齡,讓其走else的error。
注意:
1. 經(jīng)測試5.0.12版本,ajax請求時,success與error方法均返回信息,返回數(shù)據(jù)格式與default_ajax_return配置項設(shè)定相同。
2. 官方給出success在ajax請求時不返回信息,是個bug。
關(guān)注卓象程序員,定期發(fā)布技術(shù)文章
下一篇講解“重定向”
洞簡述
盡管ThinkPHP 5.0.x框架采用了參數(shù)化查詢方式,來操作數(shù)據(jù)庫,但是在 insert 和 update 方法中,傳入的參數(shù)可控,且無嚴格過濾,最終導致本次SQL注入漏洞發(fā)生。
ThinkPHP基礎(chǔ)知識
在進行漏洞分析之前,我們需要了解一下ThinkPHP基礎(chǔ)知識,這里僅介紹對本次漏洞分析有幫助的部分。
ThinkPHP5.0的 目錄結(jié)構(gòu)
thinkphp 應用部署目錄
├─application 應用目錄(可設(shè)置)
│ ├─common 公共模塊目錄(可更改)
│ ├─index 模塊目錄(可更改)
│ │ ├─config.php 模塊配置文件
│ │ ├─common.php 模塊函數(shù)文件
│ │ ├─controller 控制器目錄
│ │ ├─model 模型目錄
│ │ ├─view 視圖目錄
│ │ └─ ... 更多類庫目錄
│ ├─command.php 命令行工具配置文件
│ ├─common.php 應用公共(函數(shù))文件
│ ├─config.php 應用(公共)配置文件
│ ├─database.php 數(shù)據(jù)庫配置文件
│ ├─tags.php 應用行為擴展定義文件
│ └─route.php 路由配置文件
├─extend 擴展類庫目錄(可定義)
├─public WEB 部署目錄(對外訪問目錄)
│ ├─static 靜態(tài)資源存放目錄(css,js,image)
│ ├─index.php 應用入口文件
│ ├─router.php 快速測試文件
│ └─.htaccess 用于 apache 的重寫
├─runtime 應用的運行時目錄(可寫,可設(shè)置)
├─vendor 第三方類庫目錄(Composer)
├─thinkphp 框架系統(tǒng)目錄
│ ├─lang 語言包目錄
│ ├─library 框架核心類庫目錄
│ │ ├─think Think 類庫包目錄
│ │ └─traits 系統(tǒng) Traits 目錄
│ ├─tpl 系統(tǒng)模板目錄
│ ├─.htaccess 用于 apache 的重寫
│ ├─.travis.yml CI 定義文件
│ ├─base.php 基礎(chǔ)定義文件
│ ├─composer.json composer 定義文件
│ ├─console.php 控制臺入口文件
│ ├─convention.php 慣例配置文件
│ ├─helper.php 助手函數(shù)文件(可選)
│ ├─LICENSE.txt 授權(quán)說明文件
│ ├─phpunit.xml 單元測試配置文件
│ ├─README.md README 文件
│ └─start.php 框架引導文件
├─build.php 自動生成定義文件(參考)
├─composer.json composer 定義文件
├─LICENSE.txt 授權(quán)說明文件
├─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 域名 網(wǎng)站目錄 對外訪問目錄 入口文件 前臺 控制器 方法名
變量獲取
$name=input("get.name/a"); input()為TP框架的助手函數(shù),get.name/a 表示獲取get傳入的name變量,并將其強制轉(zhuǎn)換為數(shù)組類型
數(shù)據(jù)庫查詢
Db::table("users")->where(["id"=>1])->insert(["username"=>$name]); TP框架采用的是PDO方式對數(shù)據(jù)庫進行查詢
環(huán)境搭建
在了解了基本知識后,我們可以開始搭建環(huán)境。這里我們使用ThinkPHP 5.0.14版本來進行實驗,下載地址:http://www.thinkphp.cn/download/1107.html
我們先安裝好phpstudy,然后將下載好的ThinkPHP 5.0.14解壓至phpstudy的網(wǎng)站根目錄下,安裝ThinkPHP 5.0.14需要Mbstring、PDO、Curl三個插件,php版本這里用5.6。
接著我們需要配置連接數(shù)據(jù)庫的文件,并開啟thinkphp的調(diào)試功能。在此之前,你需要先在數(shù)據(jù)庫中創(chuàng)建用于測試的數(shù)據(jù),例如這里我用thinkphp作為數(shù)據(jù)庫名,那么就在mysql命令行下執(zhí)行create database thinkphp; 然后在建立一個users表,列名有id,username,password,執(zhí)行create table users(id int auto_increment primary key,username varchar(20),password varchar(30)); 即可,最后我們往表中插入測試數(shù)據(jù),命令行執(zhí)行insert into users(id,username,password) values(1,"test","thinkphp"); 這樣就算測試數(shù)據(jù)創(chuàng)建成功了。
配置連接數(shù)據(jù)庫的文件,并開啟thinkphp的調(diào)試功能,如下圖:
最后修改文件 application\index\controller\Index.php 的內(nèi)容,如下:
<?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就可以觸發(fā)漏洞了
漏洞分析
首先,我們知道 insert 方法存在漏洞,那就查看 insert 方法的具體實現(xiàn)。該方法位于 thinkphp\library\think\db\Builder.php 文件中,我們可以看到在函數(shù)開頭調(diào)用了 parseData 方法,并將 $data 作為參數(shù)傳入, $data 的值是我們通過 get方式傳入的一個數(shù)組類型的數(shù)據(jù),如下圖:
我們跟進 parseData 方法,該方法也在 thinkphp\library\think\db\Builder.php 文件中。可以看到,在結(jié)尾處有個switch語句,而且進入該語句后,會跳到case 'inc'的地方,這里關(guān)鍵就是看看 $this->parseKey 是否有對 $val[1] 變量進行過濾了,因為 $val[1] 變量就是我們payload中的updatexml(1,concat(0x7,user(),0x7e),1) ,如下圖:
繼續(xù)跟進 parseKey 方法,會發(fā)現(xiàn)直接將傳入的 $key 返回了,沒有進行任何過濾。
我們再回到最開始的 insert 方法,加上調(diào)試語句,看看此時的sql語句變成了什么樣子,如下圖:
另一處update函數(shù)的注入與這個insert是類似的,這里就不在贅述。
總結(jié)
筆者也是第一次審計Thinkphp框架,在審計這套框架前還找了網(wǎng)絡(luò)上的視頻快速入門了下,再結(jié)合Thinkphp5.0手冊,完成此次漏洞的審計。當然,文章有不當之處,還希望大家斧正。
一篇文章講解“模型-事件”,本篇文章講解“模板-變量輸出一”。
在模板中輸出變量的方法很簡單。
①新建Index控制器,并新建index方法,為模板變量賦值
②在index控制器的index模板中輸出變量
預覽:
注意:
1. 注意模板標簽的{和$之間不能有任何的空格,否則標簽無效。
2. 模板標簽的變量輸出根據(jù)變量類型有所區(qū)別。
字符串輸出時直接使用變量名,當輸出數(shù)組時,有兩種方法。
①在Index控制器中新建outarr方法
②在index.html模板中輸出數(shù)組變量
預覽:
注意:
1. 當我們要輸出多維數(shù)組的時候,往往要采用第二種方式。
①在Index控制器中新建outobj方法
②在index.html模板中輸出對象
預覽:
注意:
1. 也可以直接調(diào)用對象的常量或者方法
常量:{$data::CONST_NAME}
方法:{$data->fun()}
我們可以給變量輸出提供默認值。
①在Index控制器中新建outde方法
②在index.html模板中輸出
預覽:
對系統(tǒng)變量依然可以支持默認值輸出。
Index控制器的outde方法不變,在index.html模板中輸出系統(tǒng)變量。
預覽:
①在公共函數(shù)中創(chuàng)建函數(shù)
②在index.html模板中輸出
預覽:
關(guān)注卓象程序員,定期發(fā)布技術(shù)文章
下一篇講解“模板-變量輸出二”
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。