网络安全学习-17

36 阅读5分钟

ThinkPHP框架基础

  1. 目录结构
thinkphp/
├── application/          # 应用目录(业务代码)
│   ├── index/            # 模块目录
│   │   ├── controller/   # 控制器 ⚠️ 审计重点
│   │   ├── model/        # 模型
│   │   └── view/         # 视图
│   ├── common.php        # 公共函数 ⚠️ 审计重点
│   ├── config.php        # 配置文件 ⚠️ 审计重点
│   └── route.php         # 路由配置
├── thinkphp/             # 框架核心目录
│   ├── library/          # 核心类库
│   │   └── think/        # Think命名空间
│   ├── start.php         # 启动文件
│   └── base.php          # 基础定义
├── public/               # Web根目录
│   └── index.php         # 入口文件 ⚠️ 审计起点
└── vendor/               # Composer依赖

2. 请求流程

    1. 入口文件 public/index.php
require __DIR__ . '/../thinkphp/base.php';
  1. 2. 启动流程
用户请求
    ↓
入口文件  // public/index.php
    ↓
框架初始化  
    ↓
Route::check()  // 路由解析 
    ↓
Controller::exec()  // 控制器调度 
    ↓
Model::query()  // 数据库操作 
    ↓
View::fetch()  // 模板渲染 

3. 配置文件

// 应用状态(生产环境必须设为true)
'app_debug'          => false,

// 禁止自动生成控制器
'auto_search'        => false,

// 输入数据过滤
'default_filter'     => 'htmlspecialchars',

// URL模式
'url_common_param'   => false,

4. URL设计

  • 普通模式
http://domain.com/index.php?s=/模块/控制器/操作/参数名/参数值
  • 默认模式
http://domain.com/index.php/模块/控制器/操作/参数名/参数值
  • 兼容模式
http://domain.com/index.php?s=/模块/控制器/操作
  • 示例
http://www.example.com/index.php/index/user/login/id/10

模块:			index
控制器:		User
操作:			login
参数:			id=10

5. MVC模式

  • MVC=Model(模型)+View(视图)+Controller(控制器)
  • 请求流程
┌──────────────────────────────────────────┐
│                用户请求                   |
└─────────────────┬────────────────────────┘
                  ↓
          ┌───────────────┐
          │  Controller   │ ← 处理业务逻辑
          │   (控制器)     |
          └───────┬───────┘
                  │
         ┌────────┴────────┐
         ↓                 ↓
   ┌─────────┐       ┌─────────┐
   │  Model  │       │  View   │
   │ (模型)   │←─────→│ (视图)  │
   └─────────┘       └─────────┘
   数据交互            页面展示
  • 目录结构
project/
├── app/                      # 模块
│   ├── controller/           # 控制器目录 (C)
│   │   ├── Index.php
│   │   └── User.php
│   │
│   ├── model/                # 模型目录 (M)
│   │   ├── User.php
│   │   └── Article.php
│   │
│   ├── view/                 # 视图目录 (V)
│   │   ├── index/
│   │   │   └── index.html
│   │   └── user/
│   │       ├── login.html
│   │       └── profile.html
│   │
│   ├── middleware/           # 中间件
│   ├── validate/             # 验证器
│   └── common.php            # 公共函数
│
├── config/                   # 配置目录
├── route/                    # 路由定义
├── public/                   # 入口目录
│   └── index.php
└── vendor/                   # Composer依赖
  • MVC
    • Controller(控制器)
      • 作用:接受用户请求;调用模型处理数据;加载视图返回响应。
      • 示例
public function index()
    {
        // 1. 获取请求参数
        $page = input('page', 1);
        
        // 2. 调用模型获取数据
        $userModel = new UserModel();
        $users = $userModel->paginate(10);
        
        
        // 3. 渲染视图
        return View::fetch('index');
    }
    • Model(模型)
      • 作用:封装数据库操作、定义数据关心、实现业务逻辑
    • View(视图)
      • 作用:模板渲染,前端界面输出
  • 获取输入
    • 助手函数
// 获取所有请求参数
$data = input();

// 获取指定参数
$name = input('name');

// 获取参数并设置默认值
$page = input('page', 1);

// 获取参数并指定类型
$id = input('id/d');      		// 整数
$price = input('price/f'); 		// 浮点数
$name = input('name/s');   		// 字符串
    • 变量修饰符
// 类型转换
input('id/d');        // 整数 (digit)
input('price/f');     // 浮点数 (float)
input('name/s');      // 字符串 (string)
input('flag/b');      // 布尔值 (boolean)
input('ids/a');       // 数组 (array)

// 多个修饰符组合
input('email/s');     // 字符串并过滤
input('content/s');   // 获取字符串内容
    • 使用Request获取
变量类型方法('变量名/变量修饰符','默认值','过滤方法')

// 助手函数
$request = request();
$name = $request->param('name');
  • 数据库
    • 基本查询

// 查询所有数据
$users = Db::table('user')->select();

// 查询单条数据
$user = Db::table('user')->where('id', 1)->find();

// 查询某个字段的值
$username = Db::table('user')->where('id', 1)->value('username');

// 查询某一列的值
$usernames = Db::table('user')->column('username');
    • 原生查询
      • query方法
$result = Db::query("SELECT * FROM user WHERE status = 1");
      • execute方法
$rows = Db::execute("INSERT INTO user (name, age) VALUES (?, ?)", ['李四', 25]);

复习ThinkPHP框架漏洞

ThinkPHP常见漏洞

sql注入漏洞

insert

  • 影响版本
    • 5.0.13<=ThinkPHP<=5.0.15 、 5.1.0<=ThinkPHP<=5.1.5
  • 原理:Builder 类的 parseData ⽅法中。由于程序没有对数据进⾏很好的过滤,将数据拼接进 SQL 语句,导致 SQL注⼊漏洞 的产⽣

update

  • 影响版本
    • 5.1.6<=ThinkPHP<=5.1.7 (⾮最新的 5.1.8 版本也可利⽤)
  • 原理:Mysql 类的 parseArrayData ⽅法中由于程序没有对数据进⾏很好的过滤,将数据拼接进 SQL 语句,导致 SQL注⼊漏洞 的产⽣

select

  • 影响版本:ThinkPHP=5.0.10
  • 原理:Mysql 类的 parseWhereItem ⽅法中。由于程序没有对数据进⾏很好的过滤,直接将数据拼接进 SQL语句。再⼀个, Request 类的 filterValue ⽅法漏过滤 NOT LIKE 关键字,最终导致 SQL注漏洞的产⽣。

orderby

  • 影响版本:5.1.16<=ThinkPHP5<=5.1.22
  • 原理:Builder 类的 parseOrder ⽅法中。由于程序没有对数据进⾏很好的过滤,直接将数据拼接进 SQL语句,最终导致 SQL注⼊漏洞 的产⽣

聚合函数

  • 影响版本:5.0.0<=ThinkPHP<=5.0.21 、 5.1.3<=ThinkPHP5<=5.1.25
  • 原理:本次漏洞存在于所有 Mysql 聚合函数相关⽅法。由于程序没有对数据进⾏很好的过滤,直接将数据拼接进 SQL 语句,最终导致 SQL注⼊漏洞 的产⽣

代码执行漏洞

  • 影响版本:5.0.0<=ThinkPHP5<=5.0.23 、5.1.0<=ThinkPHP<=5.1.30
    • 原理:ThinkPHP 底层没有对控制器名进⾏很好的合法性校验,导致在未开启强制路由的情况下,⽤户可以调⽤任意类的任意⽅法,最终导致 远程代码执⾏漏洞 的产⽣

  • 版本5.0.7<=ThinkPHP5<=5.0.22 、5.1.0<=ThinkPHP<=5.1.30
    • 原理:本次漏洞存在于 ThinkPHP 底层没有对控制器名进⾏很好的合法性校验,导致在未开启强制路由的情况 下,⽤户可以调⽤任意类的任意⽅法,最终导致 远程代码执⾏漏洞 的产⽣

文件上传漏洞

  • 影响版本:5.0.0<=ThinkPHP5<=5.0.18 、5.1.0<=ThinkPHP<=5.1.10
  • 原理:本次漏洞存在于 ThinkPHP 模板引擎中,在加载模版解析变量时存在变量覆盖问题,⽽且程序没有对数据进⾏很好的过滤,最终导致 ⽂件包含漏洞 的产⽣

自动化扫描

搭建部署脱单交友平台并审计复现任意文件写入漏洞

环境搭建

上传并解压文件 创建网站,注意根目录是public创建数据库,并修改配置

配置伪静态 登录测试

任意文件上传漏洞复现

上述代码中,漏洞位于 upload() 方法及其调用的辅助函数 base64Image() 中,没有对文件类型进行过滤。

将代码进行Base64编码后上传

phar反序列化漏洞原理及利用技巧

原理

  • Phar反序列化是一种极其隐蔽且威力巨大的攻击方式。它打破了传统反序列化必须依赖unserialize()函数的限制。
  • 原理:Phar (PHP Archive) 是PHP的一种打包格式。其核心漏洞点在于:Phar文件的元数据(Metadata)是以序列化形式存储的。 当PHP通过 phar:// 伪协议解析一个Phar文件时,底层代码会自动对该文件的元数据进行反序化操作。
  • 几乎所有文件操作函数(如 file_exists(), is_dir(), file_get_contents(), include 等)在处理 phar:// 开头的路径时,都会触发反序列化。
  • 要在ThinkPHP环境(或其他PHP环境)中实现Phar反序列化,必须满足以下条件:
    1. 生成恶意的phar文件。
    2. 上传恶意的phar文件。
    3. 调用恶意的phar文件。

利用技巧

  • 由于PHP只检查Phar文件的签名(Stub),不检查文件后缀。你可以将Phar文件伪装成JPG
  • 绕过关键字phar://
compress.bzip://phar:///test.phar/test.txt
compress.bzip2://phar:///test.phar/test.txt
compress.zlib://phar:///home/sx/test.phar/test.txt
php://filter/resource=phar:///test.phar/test.txt
php://filter/read=convert.base64-encode/resource=phar://phar.phar