前言
前不久参加了一个CTF比赛,有一道题是PHP代码审计,采用框架进行开发,因为从没有接触过框架学习,故找到了漏洞代码也不知道怎么构造利用,悲惨之极,现在恶补下。
PHP框架
在PHP中,目前主流的框架有:
Zend Framework:重量级框架,由PHP官方出品,因为功能较全面,导致启动慢比较臃肿。
YII:重量级框架,由美国华人薛强开发
Symfony:重量级框架,一款国外框架。
Laravel:轻量级框架,一款国外框架。
Codelgniter:轻量级框架,简称CI框架,一款国外框架。
ThinkPHP:由国人开发,有中文官网和社区,在国内使用比较普遍。
MVC
说到框架,那么不得不说MVC设计模式了,它是强制将用户的输入、逻辑、输出相分离,将整个项目分为三个部分:控制器、模型、视图。
编程阶段:
第一阶段:混合编程-将PHP代码和前端代码写在一个文件中。
第二阶段:模板引擎-典型的如smarty。将后端代码和前端代码分离开。
第三阶段:框架-将用户的输入、逻辑、输出相分离,维护性提高很多。
ThinkPHP框架
目前最新的是V5版,但目前使用最多的是3.2.3版本。
软件版本的修饰词:
- Alpha版本:内测版本,内部测试
- Beta版本:公测版本,面向用户,由用户找BUG
- RC版本:候选版本,软件在这个阶段就已经不会有太多的功能性调整,主要是排错。
- R版本:release版本,发行版本,稳定的版本
目录解释
- Application:应用目录
- Public:资源文件,存放图片、CSS、JS等静态文件
- ThinkPHP:框架核心目录
- .htaccess:分布式配置文件
- composer.json:给composer管理软件使用的说明文
- index.php:项目的入口文件
- README.md:说明文件
核心框架目录:
- Common:系统函数库目录,存放了functions.php
- Conf:系统配置文件目录
- Lang:语言包目录
- Library:thinkphp核心目录
- Mode:模式,一般用不着
- Tpl:系统模板目录,里面包含了系统所用的模板
- ThinkPHP.php:项目接口文件,在后期开发的时候被项目入口文件所引入
自动生成
在首次运行index.php入口文件时会自动生成相应的目录结构:
开始只需要这两个文件即可:
访问入口文件会自动生成Application目录
应用目录名字取决于在index.php中定义的常量APP_PATH:
目录安全文件:
在自动生成的目录中都有一个空白的html文件,这是为了防止开发者忘记在Apache配置文件中配置了options+indexes,防止目录遍历攻击。防止列出站点文件结构。
默认访问:
默认访问可看到一个笑脸,这是为啥呢?
默认配置在系统配置convention.php文件中:
默认分组/平台:Home
默认控制器:Index
默认方法:index
ThinkPHP中控制器
命名规范:控制名(英文首字母大写)+Controller关键词+.class.php
如:GoodController.class.php
控制器代码结构:
1、声明当前控制器(类)的命名空间:namespace Home\Controller
2、引入父类控制器:Think\Controller
3、声明控制器(类)并且继承父类:class IndexController extends Controller
自己写一个控制器:
#自己建立一个控制器:UserController.class.php
<?php
namespace Home\Controller;
use Think\Controller;
class UserController extends Controller{
public function test(){
echo "hello world";
}
}
那么怎么构造访问呢?http://127.0.0.1/thinkphp/index.php?m=Home&c=User&a=test
m为平台/分组,默认为Home,C为控制器,a为方法
路由形式
路由:是指访问项目具体某个方法的URL地址,在ThinkPHP中系统提供了4种路由形式:
- 普通形式路由(GET形式路由)
- Pathinfo形式路由
- Rewrite形式路由
- 兼容形式路由
普通形式路由:
路由形式:http://网址/入库文件?m=分组名&c=控制器名&a=方法名&参数名=参数值
例如:访问Home分组下的User控制器中的test方法,并且传递一个参数,id=1
http://127.0.0.1/index.php?m=Home&c=User&a=test&id=1
问题:既不安全也不好看
Pathinfo形式路由:thinkphp默认路由
路由形式:http://网址/入口文件/分组名/控制器/方法/参数名1/参数值1/参数名/2参数值2
例如:访问Home分组下的User控制器中的test方法,并且传递一个参数,id=1
http://127.0.0.1/thinkphp/index.php/Home/User/test/id/1
Rewrite形式路由:
路由形式:http://网址/分组名/控制器/方法/参数名1/参数值1/参数名/2参数值2
http://127.0.0.1/thinkphp/Home/User/test/id/1
注意:该路由需要配置才能使用。此路由形式很少使用。
兼容形式路由:
路由形式:http://网址/入口文件?s=/分组名/控制器/方法/参数名1/参数值1/参数名/2参数值2
http://127.0.0.1/thinkphp/index.php?s=/Home/User/test/id/1
thinkphp路由的配置:在thinkphp系统配置文件convention.php中,默认为Pathinfo形式路由,这里配置不影响我们在地址栏输入的形式,而是影响的是thinkphp系统封装的URL组装函数。
分组
一般的项目都会根据某个功能来区分代码,这时候放到一起就形成了分组文件夹,分组就是指的是平台(前台、后台)。
默认thinkphp创建了一个Home分组,后期需要更多的分组,需要自己创建。
如何创建分组:参考Home分组的文件结构
自己创建一个分组:
在Home分组同级目录中创建一个Admin分组,里面的结构参考Home分组结构
在Admin分组中创建一个控制器:TestController.class.php,并创建一个测试方法Test
<?php
namespace Admin\Controller;
use Think\Controller;
class TestController extends Controller {
public function test(){
phpinfo();
}
}
访问创建的分组:http://127.0.0.1/thinkphp/index.php/Admin/test/Test
控制器中的跳转
URL组装:
URL组装就是根据某个规则,来组成一个URL地址,这个功能就叫做url组装。
在Thinkphp中,系统提供了一个封装函数来处理URL的组装,这个方法叫做U方法。
U方法是系统提供的快速方法,除了U方法还有其它的快速方法:A、B、C等这些方法都定义在系统函数库中functions.php。
测试U方法组装:
<?php
namespace Admin\Controller;
use Think\Controller;
class TestController extends Controller {
public function test(){
echo U('admin');
}
}
这里admin后面是.html,这是伪静态,为了优化。
用法:U('[分组名/控制器名]方法名',array('参数名1'=>参数值1,'参数名2'=>参数值2))
示例:echo U('Admin/Test/Test',array('id'=>1));
系统跳转方法:
在Thinkphp中系统有2个跳转方法:成功跳转和失败跳转。
成功:
$this->success(跳转提示,跳转地址,等待时间);
失败:
$this->error(跳转提示,跳转地址,等待时间);
跳转参数必须要有,后面的地址和时间可以没有,若没有地址则跳转到上一页。
测试跳转:
<?php
namespace Admin\Controller;
use Think\Controller;
class TestController extends Controller {
public function test(){
echo "hello world";
}
public function test1(){
echo "good id";
}
public function jmp1(){
$this->success("跳转成功",U("test"),10);
}
public function jmp2(){
$this->error("跳转失败",U("test1"),10);
}
}
视图
什么是视图:是MVC三大组成部分之一,主要负责信息的输出和展示。
视图的创建:
创建的位置需要在分组目录下的View目录中,一般来说,一个控制器对应着一个视图目录 (同名),控制器中的方法对应着视图目录里的一个html文件。
示例:Test控制器中的login方法,需要有一个模板,则该模板文件login.html需要放在View/Test/login.html。
视图的展示:
在Thinkphp中展示视图是通过:$this->display();展示当前控制器下与当前请求方法名称一致的模板文件。
测试模板:
Test控制下有一个test1方法:
public function test1(){
$this->display();
}
在View\Test\创建一个test1.html模板文件,访问即可展示test1.html。
变量的分配:
在Thinkphp中系统已封装好了一个变量的分配方法:$this->assign('模板中变量名','php中变量名');
而在模板中通过{$模板变量名}来展示变量数据。
测试:
public function test1(){
$date=date('Y-m-d H:i:s',time());
$this->assign('date',$date);
$this->display();
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
现在时间是:{$date}
</body>
</html>