unserialize

unserialize

PHP序列化和反序列化

  • 序列化:是将变量或对象转换成字符串的过程( 序列化只作用于对象,不序列化方法),用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构。

  • 反序列化是:将字符串转换成变量对象的过程,反序列化的结果(即对象)的输出要用print_r()var_dump()

    PHP反序列化漏洞:是一种允许攻击者通过将恶意数据反序列化为PHP对象来执行任意代码的漏洞。

PHP序列化结果:

Example:

1
O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}

1.对象序列化

  • Public(公有):类的外部、子部、内部可用

  • Protected(受保护):类的子部、内部可用

  • Private(私有):类的内部可用

    1. Public(公有):被序列化时属性值为:属性名
    2. Protected(受保护):被序列化时属性值为:\x00*\x00属性名
    3. 3.Private(私有):被序列化时属性值为:\x00类名\x00属性名

2.数组序列化

1
2
3
4
5
6
7
8
<?php
$a=array("ll",123,true);
echo serialize($a);
?>

//输出
a:3:{i:0;s:2:"ll";i:1;i:123;i:2;b:1;}
//a表示这是一个数组的序列化,成员属性名为数组的下标,格式 {i:数组下标;类型:长度:“值”; 以此类推}

pop链反序列化

面向属性编程POP( Property Oriented Programming)

魔术方法:

魔术方法是一个预定好的、在特定情况下自动触发的行为方法。

触发前提:魔术方法所在的类被调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
__construct()       //类的构造函数,创建对象时触发
__destruct() //类的析构函数,对象被销毁时触发
__call() //调用对象不可访问、不存在的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //调用不可访问、不存在的对象成员属性时触发
__set() //在给不可访问、不存在的对象成员属性赋值时触发
__isset() //当对不可访问属性调用isset()或empty()时触发
__unset() //在不可访问的属性上使用unset()时触发
__invoke() //把对象当做函数调用时触发
__sleep() //执行serialize()时,先会调用这个方法
__wakeup() //执行unserialize()时,先会调用这个方法
__toString() //把对象当成字符串调用时触发
__clone() //使用clone关键字拷贝完一个对象后触发
__autoload() //尝试加载未定义的类
__set_state() //调用var_export()导出类时,此静态方法会被调用。
... ...

php反序列化绕过

__wakeup()函数漏洞:漏洞原理:(反序列化漏洞CVE-2016-7124)

1
2
3
1.如果存在wakeup方法,调用 unserilize() 方法前则先调用wakeup方法,
但是序列化字符串中表示对象属性个数的值大于 真实的属性个数时会跳过__wakeup的执行
2.正则匹配大写字母O后不能跟数字时,可在数字前加+号绕过
1
2
3
如果函数有两个属性:
正常:?p=O:6:"HaHaHa":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}
绕过:?p=O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}

序列化的数据格式:

数据类型 序列化数据结构
对象 O:length:class name:attribute number:{attr1;value1;attr2;value2;}
字符串 s:length:value;
整数 i:value;
布尔 b:value;
空值 N;
浮点数 d:value

反序列化题目做题步骤

  1. 复制源代码到本地
  2. 注释掉和属性无关的内容
  3. 根据题目需要,给属性赋值(这是关键)
    • 寻找POP链:
      • 起点:unserialize 的参数可控的地方
      • 终点:执行代码或者可以任意读取文件的地方
      • 连接起点和终点:研究属性和方法(特别是魔术方法)
  4. 生成序列化的数据,通常需要 urlencode
  5. 传递数据到服务器(攻击目标)

Example:

1
2
3
4
5
6
7
8
9
payload:
<?php
class demo{
public $func="evil";
public $arg="phpinfo();";
}
$b = new demo();
echo urlencode(serialize($b));
?>

数组的特性

当一个数组被当做函数触发时,如果数组第一个元素是对象,第二个元素是方法的名字那么就会调用该对象下的该方法

例如:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
class A{
public $name;
public function test(){
echo "数组的特性\n";
}
}
$a=new A();
// $a->test(); //对象调用函数
$arr=[$a,"test"]; //对象和函数都在一个数组中
$arr();
?>

属性赋值:

  1. 直接赋值:优点是方便,缺点是只能赋值字符串。例如:public $var=”test”;
  2. 外部赋值:优点是可以赋值任意类型的值,缺点是只能操作public属性。例如:
    $s = new show();
    $s->var = new read();
  3. 构造方法赋值(万能方法):优点是解决了上述的全部缺点,缺点是有点麻烦。
    例如:在类中定义一个函数:
1
2
3
4
5
6
<?php
function __construct(){
$this->var = "var";
$this->var = new read();
}
?>

create_function函数

create_function(string $args,sting $code);

作用:创建函数的简单方式:
例如:

1
2
3
4
5
6
7
8
9
10
<?php
//第一个参数要使用单引号,双引号会解析不能使用;第二个参数结尾记得加分号
$f = create_function('$a,$b', 'echo($a+$b);');
$f(1,2); //输出3
//方法二
function f2($a,$b){ //两种表示方式一样
echo($a+$b);
}
f2(2,3); //输出5
?>

waf绕过总结

https://blog.csdn.net/yjh20041010/article/details/144316284