<?php highlight_file(__FILE__); class install { ...
Créé le : 24 novembre 2025
Créé le : 24 novembre 2025
这个代码是一个典型的「PHP 反序列化链」题目,从你最后那句中文看,很像 CTF / 安全练习的环境。
你问的是:“怎么样调用到 open,使用原生类?” —— 也就是想通过 unserialize($_GET['data']) 去打到某个内置类里的 open 方法,完成利用。
这里我需要先说明一下:
关键是 Until::write() 这一段:
phppublic function write($cla, $file, $cont) { $obj = new $cla(); $obj->open($file,$cont); return True; }
只要你能控制:
$cla:类名(字符串)$file:文件名(字符串)$cont:文件内容(字符串)并且 $cla 这个类存在一个 open($file, $cont) 方法,就可以完成任意文件写入。如果 open() 是某个内置类(原生类)里的方法,并且你能通过它写出可执行 PHP,那危害就很大。
unserialize($_GET['data']) 跑到 write()?链子大致是这样:
入口:@unserialize($_GET['data']);
__wakeup / __destruct / __toString / __invoke),PHP 在某些时机会自动调用。install 类里的魔术方法:
phppublic function __toString() { ($this->username)(); return "Guest"; }
$this->username 被当成一个「可调用(callable)」来执行,也就是:
__invoke(),就会自动调用这个 __invoke()。Until 类里的 __invoke():phppublic function __invoke() { $this->write($this->a, $this->b, $this->c); }
Until 对象被“当成函数调用”,就会触发 write(),从而走到前面说的 new $cla()->open()。所以一条典型的危险调用链是:
反序列化得到
install对象 → 某个行为触发__toString()→
__toString()调用$this->username这个 callable →
$this->username实际上是Until对象 →
调用Until::__invoke()→
调用write()→
执行new $cla()->open($file, $cont)。
你要问的 “怎么样调用到 open” 本质就是:
如何通过布置 install 和 Until 的属性,让这条链子完整跑通,并把 $cla/$file/$cont 变成你想要的东西。
几个要点:
永远不要对用户输入直接 unserialize()
魔术方法是“隐藏执行点”:
__wakeup():unserialize() 时自动调用。__destruct():对象销毁时调用(脚本结束或者 unset)。__toString():对象当字符串用时调用,比如 echo $obj; 或字符串拼接。__invoke():对象被当函数调用时执行,比如 $obj();。你这段代码里就有一个经典的危险组合:
__toString() 里调用 可控的 callable(($this->username)();)__invoke() 里进行 可控类名 + 文件路径 + 内容 的操作。如果你是在做渗透测试 / CTF 题,那这段就是故意给你“打”的。
但如果这是生产代码,强烈建议:
绝对不要对用户可控数据用 unserialize()
json_decode()。使用 unserialize 的第二个参数限制类:
php$data = unserialize($_GET['data'], ['allowed_classes' => false]); // 或者只允许特定类: ['allowed_classes' => ['SomeSafeClass']]
php($this->username)(); new $cla();
phpif ($this->username instanceof Until) { $this->username->__invoke(); }
<?php 类内容。open 方法可以被用来写文件或做危险操作,就有被利用的可能。如果你愿意,我可以帮你把这段代码重构成一个安全版的安装脚本,顺便加上注释,方便你以后做安全开发时当模板用。