网鼎杯2020-小知识点
前言
在网鼎杯中遇见了许多令人迷惑的问题、以及不知道的知识,故在此记录。
php反序列化中对象属性问题
在这次的一道php反序列化的一道题中。我们要利用的属性被设置为了protected
,这意味着我们的序列化字符串中将会出现%00
这个不可见字符,但题目中ban掉了所有不可见字符,需要进行绕过。
我正当想着怎么绕过,突然有师傅说不必理会那个%00
,利用的属性直接按照public
得到的序列化字符串也可以被利用。
当时的我:???????我之前的一道ctf中,因为没有注意到某一个属性的可见性是private
导致痛失一题。
故在这里尝试不同版本php的反序列化处理
尝试以下代码
<?php
echo phpversion().'<br>';
class test
{
public $a;
private $b;
protected $c;
public function __construct()
{
$this->a = 1;
$this->b = 2;
$this->c = 3;
}
private function outputAll()
{
echo 'a:'.$this->a.'<br>';
echo 'b:'.$this->b.'<br>';
echo 'c:'.$this->c;
}
public function __destruct()
{
$this->outputAll();
}
}
if(isset($_GET['str']))
$obj = unserialize($_GET['str']);
else
{
$obj = new test;
echo serialize($obj);
}
环境为linux加apache2
设置get参数为str=O:4:"test":3:{s:1:"a";i:1;s:1:"b";i:2;s:1:"c";i:3;}
分别获得以下输出
php:7.4-apache:
7.4.5<br>a:1<br>b:2<br>c:3
php:7.3-apache:
7.3.17<br>a:1<br>b:2<br>c:3
php:7.2-apache:
7.2.30<br>a:1<br>b:2<br>c:3
php:7.1-apache:
7.1.33<br>a:1<br>b:<br>c:
php:7.0-apache:
7.0.33<br>a:1<br>b:<br>c:
php:5.6-apache:
5.6.40<br>a:1<br>b:<br>c:
可以看到,在7.2以后的版本(包括7.2)php在进行反序列化处理时并没有对属性的可见性进行检验
这便是矛盾的来源,之后在进行反序列化时,一定要注意php的版本,这上述的情况可能会带来意想不到的漏洞。
php反序列化中的S类型
在一个对象被序列化后的字符串中的字符有特殊的含意O:4:"test":3:{s:1:"a";i:1;s:1:"b";i:2;s:1:"c";i:3;}
在上面的字符串中,O为对象、s为字符串、i为数字…
这里要讲一种S类型,S类型指的是是已经被转义的字符串
在一个private
或protected
的对象属性中,序列化后,会有特殊的字符
以上面的代码为例(PS:%00为hex值为00的字符)
序列化b为:s:7:"%00test%00b";i:2;
序列化c为:s:4:"%00*%00c";i:3;
可以看到,当在浏览器这么输入后,会向服务器发送不可见字符。
但对于S类型则没有必要了,将s替换为S后:
序列化b为:S:7:"\00test\00b";i:2;
序列化c为:S:4:"\00*\00c";i:3;
这样传入的是3个字符组成的字符串\00
而不是00
这个不可见字符
这么做的目的其实在这次的CTF便可以见得。有时候,服务器会BAN掉不可见的字符,防止这些字符导致系统错误。但对于php的反序列化字符串来说,S类型恰好绕过了这个限制。
后言
目前就学到这么多(,之后靠复现来学习吧。
当时java的xxe试了半天没有出网,还以为payload的锅,结果复现发现一模一样的payload,buuoj可以出网(指靶机内网)。不知道为什么脑壳痛(
还有就是吐槽一下那个/web
那个目录有点坑(以后先尝试去读一下httpd.conf
PS:php真是博大精深(((