前言
一般我们在做题时,看到代码中有serialize函数或者unserialize函数,我们肯定会想到php反序列化,那如果代码中没有这两个函数,它0是不是也能进行反序列化?
来自Secarma的安全研究员Sam Thomas发现了一种新的漏洞利用方式—phar反序列化。不用serialize函数就能进行序列化操作,这其实就跟phar://伪协议和phar
文件的打包机制有关。
什么是phar
它就是一种php程序的一种打包文件,类似与java中的jar文件,无需解压,直接通过phar://伪协议读取内容.
一个phar文件一般有四个部分:
1.stub:它是phar文件的文件头,格式为xxxxx<?php xxx; __HALT_COMPILER();?>,这种格式是固定的。前面的可以不管,但必须以__HALT_COMPILER();?>结尾。
生成文件的后缀名为phar。这种格式就相当于gif图片中的GIF89a一样。没有这个格式就不会识别这是一个phar文件。
2.a manifest describing the contents:phar文件中被压缩的文件的一些信息,以及一些权限信息。其中Meta-data部分的信息会进行序列化并储存,这就是phar反序列化的精髓。我们可以把exp放在Meta-data内。
3.the file contents:这里放的是压缩文件的内容,这里的内容可以随便写
4.a signature for verifying Phar integrity 这是一个签名,在这里不用管。(签名就是对全文进行加密,为了防止文件内容丢失或者修改,如果签名进行解密与全文不匹配,就会拒绝解析。)
phar伪协议
因为phar就是将多个文档压缩到一个文件当中,phar文件中的Mata-data会进行序列化,在我们访问phar文件中的文档时,我们不需要对它进行解压。可以通过phar://为协议对文件进行读取。当phar文件被解析时,Meta-data中的数据就会被反序列化。
构造phar文件
在本地生成一个phar文件,并想使用phar类里面的方法,就必须将php.ini配置文件中的phar.readonly改为0或者off(前面分号时注释,删掉)
这个phar压缩文件并不是右键点击一键生成的,而是通过写脚本来生成这个phar文件的。
接下来在本地实验生成phar文件。
<?php
class XiLitter{
public $str = "this is pig";
}
$a = new XiLitter();
$phar = new phar('a.phar');//对phar对象进行实例化,以便后续操作。
$phar -> startBuffering();//缓冲phar写操作(不用特别注意)
$phar -> setStub("<?php __HALT_COMPILER(); ?>");//设置stub,为固定格式
$phar -> setMetadata($a);//把我们的对象写进Metadata中
$phar -> addFromString("test.txt","helloworld!!");//写压缩文件的内容,这里没利用点,可以随便写
$phar -> stopBuffering();//停止缓冲
?>
写完后运行,发现同目录下生成了一个a.phar文件。
可以很清楚的发现,自己定义的类被序列化了。这就可以说明这里完全可以利用反序列化漏洞了。
现在我们来验证一下用phar伪协议是否能自动进行反序列化。
1 <?php
2 class XiLitter{
3 function __destruct()//对象在反序列化时自动触发
4 {
5 echo $this->str;//检验是否进行了反序列化
6 }
7 }
8 $filename = "phar://a.phar/test.txt";
9 echo(file_get_contents($filename));
10 ?>
运行可以看出Meta-data中的数据确实被反序列化了。
在上传场景中,我们可以将phar伪造成其他格式的文件。识别phar文件只需添加<?php __HALT_COMPILER(); ?>这个文件头就可以了。那我们就可以添加别的文件头
进行伪造了。例如$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");添加gif的文件头绕过上传机制。当然,我总结的只是简单的,只是认识了什么是phar反序列化。后续对再对phar有更深入理解时,继续补充。