flag在 fl4g.php
想到了正则表达式绕过, 但是就卡在这了.后面也没想到绕过正则后构造什么payload
这恰好是这题的两个考察点
"O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}"
----> "O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}"
+号绕过
这里利用了 unserializer 的一个特性
具体可参考:
https://www.phpbug.cn/archives/32.html
https://www.guildhab.top/?p=990
参考:
CVE-2016-7124 https://bugs.php.net/bug.php?id=72663
创建对象之后 , 对对象的属性检查 , 若属性检查通过 , 就调用 __wakeup() 方法
若对象属性检查不通过 , 则会跳出 object_common2() 函数 , 不再调用 __wakeup() 函数 . 由于对象及其属性在 object_common1() 中已经被创建 , 因此这里对象将会被销毁 , 从而触发析构函数__destruct() .
因此这里我们仅需要破坏对象属性检查就可以绕过 __wakeup() 函数 , 最简单的方法就是增大对象属性的个数 , 使其饭序列化异常 .
PHP 7 中这部分代码被修改 ,无法再用该方式绕过 __wakeup() 方法
使反序列化的属性值改成大于真实值即可
如正常情况下: O:4:“Demo”:1:{s:10:" Demo file";s:8:“fl4g.php”;}
改为 O:4:“Demo”:999:{s:10:" Demo file";s:8:“fl4g.php”;}
参考: https://www.cnblogs.com/webu/archive/2013/01/28/2879383.html 或者 https://blog.csdn.net/a5816138/article/details/53303299
对象的序列化对象(object)通常被序列化为:
O:<length>:"<class name>":<n>:{<field name 1><field value 1><field name 2><field value 2>...<field name n><field value n>}
其中<length> 表示对象的类名<class name> 的字符串长度。<n> 表示对象中的字段1个数。 这些字段包括在对象所在类及其祖先类中用var、public、protected 和private 声明的字段,但是不包括static 和const 声明的静态字段。也就是说只有实例(instance)字段。 <filed name 1>、<filed name 2>……<filed name n>表示每个字段的字段名,而<filed value 1>,<filed value 2>……<filed value n> 则表示与字段名所对应的字段值。 字段名是字符串型,序列化后格式与字符串型数据序列化后的格式相同。 字段值可以是任意类型,其序列化后的格式与其所对应的类型序列化后的格式相同。 但字段名的序列化与它们声明的可见性是有关的,下面重点讨论一下关于字段名的序列化。 对象字段名的序列化 var 和 public 声明的字段都是公共字段,因此它们的字段名的序列化格式是相同的。公共字段的字段名按照声明时的字段名进行序列化,但序列化后的字段名中不包括声明时的变量前缀符号$。 protected 声明的字段为保护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不可见。因 此保护字段的字段名在序列化时,字段名前面会加上 \0*\0 的前缀。这里的 \0 表示 ASCII 码为 0 的字符,而不是 \0 组合。 private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,字段名前面会加上 \0<declared class name>\0 的前缀。 这里 <declared class name> 表示的是声明该私有字段的类的类名,而不是被序列化的对象的类名。因为声明该私有字段的类不一定是被序列化的对象的类,而有可能是它的祖先类。 字段名被作为字符串序列化时,字符串值中包括根据其可见性所加的前缀。字符串长度也包括所加前缀的长度。其中\0 字符也是计算长度的。做题时复制序列化的东西会出错,应该和\0有关 , 00截断了