【Web方向】 3-0 PHP反序列化基础语法知识(续更中…)

一、简介

序列化其实就是将数据转化成一种可逆的数据结构,自然,逆向的过程就叫做反序列化。
序列化的目的是方便数据的传输和存储,在PHP中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。
serialize() 将对象或数组格式化成有序的字符串,保存对象的值方便之后的传递和使用,但同时也方便了黑客进攻
unserialize() 将字符串还原成原来的对象,变回php值


二、PHP语法

1、基本符号

学习一门语言,掌握其基本符号是必要的,下面是PHP基本符号汇总。

  • 注释

// 单行注解
/* */ 多行注解

  • 引号

’ ’ 单引号,没有任何意义,不经任何处理直接拿过来;
" "双引号,php动态处理然后输出,一般用于变量.
\ " 双引号

  • 常用符号

\ \ 反斜线
\n 换行
\r 送出
\t 跳位(TAB)

  • 运算符

+加法运算 - 减法运算
*乘法运算 / 除法运算
% 取余数 ++ 累加
. 把字段相加
– 累减1
++累加1
= 把右边的值赋给左边
+= 把右边的值加到左边
-= 把右边的值减到左边
*= 把左边的值乘以右边
/= 把左边的值除以右边
.= 把右边的字串加到左边

  • 位运算

& 与,两个位都为1时,结果才为1
| 或 ,两个位都为0时,结果才为0
^ 异或(xor) ,两个位相同为0,相异为1
~ 取1的补数,0变1,1变0
<<向左移位 ,各二进位全部左移若干位,高位丢弃,低位补0
.>>向右移位 ,各二进位全部右移若干位,对无符号数,高位补0

  • 逻辑运算

< 小于
大于
<= 小于等于
= 大于等于
!= 不等于
&& 而且
|| 或者
! 不

  • 访问修饰符
  1. private 用于限制修饰成员的可访问性,表示私有的,只有本类中可以访问,语法为“class 类名{private 属性或方法定义}”;
  2. public 表示全局,类内部或外部都可以访问;
  3. protected 用于控制修饰成员的可访问性,表示受保护的,只有本类或子类或父类中可以访问;
  • 其他运算符

$ 变量符号
& 变量的指标(加在变量前)
@ 不显示错误信息(加在函数前)
-> 对象的方法或者属性,作用类似汉字 “
=> 数组的元素值
? : 三元运算子

. 是一个点,变量和字符串之间的点是连接字符串用的,无论变量值是数字或者字符串,连接后都变成字符串。
如: a = 1 ; a=1; a=1;b=‘a’;echo a . " , " . a.",". a."".b;
//输出结果是:“1,a”

2、PHP函数

  • 错误报告函数
    PHP 有诸多错误级别,error_reporting() 函数规定应该报告何种 PHP 错误,如果没有设置可选参数 level,error_reporting() 仅会返回当前的错误报告级别。
<?php
 // 关闭错误报告
 error_reporting(0);

 // 报告 runtime 错误
 error_reporting(E_ERROR | E_WARNING | E_PARSE);

 // 报告所有错误
 error_reporting(E_ALL);

 // 等同 error_reporting(E_ALL);
 ini_set("error_reporting", E_ALL);

 // 报告 E_NOTICE 之外的所有错误
 error_reporting(E_ALL & ~E_NOTICE);
?> 
  • global
    在function中,声明这个函数内用的那个变量不是局部的,而是全局可用的,在函数体内定义的global变量,函数体外可以使用,在函数体外定义的global变量不能在函数体内使用
$a=123;
global $a; //函数体外定义的global变量
function f()
{
  echo $a;   //错误,函数体内不可使用
}
 function f()
{
   global $a; //函数体内定义的global变量
   $a=123;
}

f();
echo $a;  //正确,函数体外可以使用
  • file_get_contents()file()
    file_get_contents() 函数和file()函数都可以把整个文件读入一个字符串中,不同的是 file_get_contents() 把文件读入一个字符串,file() 将文件作为一个数组返回
//file_get_contents()语法格式
file_get_contents(path,include_path,context,start,max_length)
//file()语法格式
file(path,include_path,context)

在这里插入图片描述

//实例
<?php
echo file_get_contents("test.txt");
?>
//输出:This is a test file with test text.
//实例
<?php
print_r(file("test.txt"));
?>
/*输出:
Array
(
[0] => Hello World. Testing testing!
[1] => Another day, another line.
[2] => If the array picks up this line,
[3] => then is it a pickup line?
)

3、

三、反序列化漏洞的利用

  • 这里举例解释序列化与反序列化

这是数组的序列化:

<?php
$test=array('bu','kan','jian'); #初始化数组
$test=serialize($test); #序列化
echo($test.PHP_EOL); #这里PHP_EOL为换行符
print_r(unserialize($test)); #反序列化

运行结果

a:3:{i:0;s:2:"bu";i:1;s:3:"kan";i:2;s:4:"jian";}
Array
(
    [0] => bu    
    [1] => kan    
    [2] => jian
)

a:3:{i:0;s:2:“bu”;i:1;s:3:“kan”;i:2;s:4:“jian”;}
a代表array数组
3代表3个元素
i表示数据类型为int整型
0表示数组下标为0
s表示数据类型为字符串
2表示字符串长度为2


这是对象的序列化:
在这里插入图片描述
运行结果:

string(67)"O:3:"man":3:{s:4:"name";s:3:"age";i:5;s:6:"height";i:20;}"
<对象类型>:<长度>:“类名”:<类中变量个数>:{<类型>:<长度>:“值”;<类型>:<长度>:“值”;……}

再反序列化回来就是下面
在这里插入图片描述

  • 拿到序列化的值后,如果在反序列化中的内容出现了漏洞,就可以反序列化来操作。

  • 反序列化漏洞
    我们了解了序列化和反序列化,那么反序列化漏洞又是什么呢?以下主要介绍两种反序列化漏洞:

  1. unserialize()函数的参数可控,可执行恶意代码
  2. php中有可以利用的类并且类中有可触发的魔幻函数

1.unserialize()可控参数的利用

  • 先构造一个恶意语句,下面是一个弹窗
    在这里插入图片描述
<?php

class S
{
    var $test = "<script>alert('Hacking')</script>";
}

$hack = new S();

echo serialize($hack);

?>
  • 恶意语句不能直接使用,先序列化为字符串O:1:"S":1:{s:4:"test";s:33:"<script>alert('Hacking')</script>";}

  • 扔到靶机测试
    在这里插入图片描述

  • 提交运行后字符串反序列化,就会运行字符串中包含的恶意语句,构造一个弹窗。同理,通过对可控参数的运用,我们还可以对靶机进行更多的操作……
    在这里插入图片描述

2.魔幻函数的运用

  • 这里可以先了解一下可利用的常见魔幻函数
__wakeup()        //执行unserialize()之前,先检查是否存在一个__wakeup()函数,如果存在,则先调用这个函数
__sleep()        //执行serialize()之前,先先检查是否存在一个__sleep()函数,如果存在,则先调用这个函数
__construct()        //创建对象时触发
__destruct()        //对象销毁时触发
__call()        //调用对象中不可访问或不存在的方法时触发
__callStatic()        //在静态中调用不可访问的方法时触发
__get()        //用于从不可访问的属性读取数据
__set()        //用于将数据写入不可访问的属性
__isset()        //在不可访问的属性上调用isset()或empty()触发
__set_state()        //调用var_export()导出类时,此静态方法会被调用
__unset()        //在不可访问的属性上使用unset()时触发
__invoke()        //当尝试将对象调用为函数时触发
__toString()        //对象被当作字符串时,调用这个函数,echo,print
__clone()        //当对象被用clone函数复制时调用
  • __wakeup()
    绕过方法:当成员属性数目大于实际数目时可绕过wakeup方法
<?php
class Name{
	private $username = 'admin';
	private $password = 100;
}
$a = new Name();
echo serialize($a);
?> 
//序列化输出:O:4:"Name":2:{s:14:" Name username";s:5:"admin";s:14:" Name password";i:100;} 
  • 可以看到这里是有两个类的,修改成大于2个即可绕过__wakeup
    O:4:"Name":3:{s:14:" Name username";s:5:"admin";s:14:" Name password";i:100;}

  • __sleep()

  • __construct()

  • __destruct()

  • __call()

格式:

__call(<参数1>,<参数2>)
<?php
class person
{
	function say()
	{
		echo "hello world!".PHP_EOL;
	}
	function __call($s1,$s2)
	{
	echo "参数1:".$s1.PHP_EOL."参数2:";
    print_r($s2);
	}
}
$person=new person();
$person->eat("apple");
?>

运行结果:

参数1:eat
参数2:Array
(
    [0] => apple
)

在函数内部,参数1是所调用的不存在的方法名,参数2是所调用方法中的参数,为数组格式

  • __callStatic()
  • __get()
  • __set()
  • __isset()

格式:

__isset(<参数>) //有且仅有一个参数

当在类外部用isset()来测定对象里面的私有成员是否被设定时,就会自动调用类里面的__isset()函数,私有成员不一定要为函数的参数

  • __set_state()
  • __unset()
  • __invoke()
  • __toString()

对象被用echo,print等方式以字符串的形势使用时触发

  • __clone()

格式:

__clone() //不能带参数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值