1、php面向对象相关知识
什么是面向过程
以事件为中心,按照步骤或着操作一步一步完成的,面向过程重点在于处理数据和操作
什么是面向对象
以对象为中心,先把要完成的功能封装成一个一个的对象,通过调用对象的属性和方法来完成功能
类的访问修饰符
访问符 | 类内部 | 类外部 | 子类 |
public | ✅ | ✅ | ✅ |
private | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ❌ |
2、序列化相关知识
什么是序列化
序列化是指将数据结构或对象转换为一串字节流的过程,使其可以在存储、传输或缓存时进行持久化。
序列化作用
序列化的作用是可以将数据转换为可传输和存储的格式,从而实现数据持久化、跨平台交互和分布式通信等功能,常用serialize()函数进行转换
序列化表达式
private属性序列化属性名称格式是0x00类名0x00成员名
protected属性序列化属性名称是0x000x2A0x00
空字符 null--->N; 整数 1234--->i:1234; 浮点型 123.4 --->d:123.4; 布尔型 true---> b:1; false --->b:0; 字符串 "nihao" ---> s:5:"nihao";
对象序列化
<?php
class Person {
public $name;
public $age;
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}
}
// 创建一个 Person 对象
$person = new Person('Alice', 30);
// 对象序列化为字符串
$serialized_person = serialize($person);
// 输出序列化后的字符串
echo $serialized_person;
?>
运行结果:O:6:"Person":2:{s:4:"name";s:5:"Alice";s:3:"age";i:30;}
解析:
O:6:"Person":2:
:这部分表示一个对象 (Object),其类名为 Person,它有 2 个属性。
s:4:"name";s:5:"Alice";
:这部分表示对象的第一个属性 name。s:4:"name" 表示属性名是 4 个字符的字符串,即 "name";s:5:"Alice" 表示属性值是 5 个字符的字符串,即 "Alice"。
s:3:"age";i:30;
:这部分表示对象的第二个属性 age。s:3:"age" 表示属性名是 3 个字符的字符串,即 "age";i:30; 表示属性值是一个整数 (i),即 30。
数组序列化
// 定义一个数组
$array = array(
"name" => "Alice",
"age" => 30,
"city" => "shanghai"
);
// 数组序列化为字符串
$serialized_array = serialize($array);
// 输出序列化后的字符串
echo $serialized_array;
结果:a:3:{s:4:"name";s:5:"Alice";s:3:"age";i:30;s:4:"city";s:8:"shanghai";}
解析:
a:3:{...}
这部分表示一个数组 (a),其中包含 3 个元素。
s:4:"name";s:5:"Alice";
这部分表示数组的第一个元素,键为 "name",值为 "Alice"。
s:3:"age";i:30;
这部分表示数组的第二个元素,键为 "age",值为 30。
3、反序列化相关知识
什么是反序列化
反序列化是将数据从序列化的形式转换回其原始的数据结构或对象的过程。
反序列化作用
反序列化的作用是在不同系统、平台或应用程序之间实现数据交换、传输和存储,同时保持数据的结构和状态不变。常用unserialize()函数进行反序列化。
4、PHP魔术方法相关知识
什么是php魔术方法
在PHP中,魔术方法(Magic Methods)是一组预定义的特殊方法,它们以双下划线(__)开头和结尾。这些方法会在对象的特定时刻自动调用,从而允许程序员在对象生命周期的不同阶段执行自定义操作。魔术方法使得在类中实现某些行为变得更加灵活和便捷。
常见的魔术方法函数
1、__construct()和__destruct()
__construct()
触发时机:构造函数创建对象时自动被调用
功能:在对象创建之后对其进行初始化操作,如初始化属性、建立与数据库的连接、加载必要的资源等。
参数:根据实际需求来定义
返回值:无要求
__destruct()
触发时机:对象被销毁时(php垃圾回收机制:脚本结束自动销毁对象)
功能:在对象生命周期结束之前执行一些必要的清理操作,如释放资源、关闭数据库连接、保存对象状态等
参数:不可设置
返回值:无
2、__call()和__callStatic()
__ call()
触发时机:调用一个不存在或不可访问的方法时
功能:处理对象中不存在的方法的调用
参数:$method :被调用的方法名(字符串类型)
$arguments:传递给该方法的参数列表(数组类型)
返回值:自由定义返回值
__callStatic()
触发时机:调用一个不存在或不可访问的静态方法时
功能:在调用一个不存在的静态方法时提供一个统一的处理逻辑使其不会导致错误
参数:$method :被调用的静态方法名(字符串类型)
$arguments:传递给该方法的参数列表(数组类型)
返回值:自由定义返回值
3、__get()和__isset()
__get()
触发时机:访问一个对象的不存在或不可访问的属性时
功能:在访问一个对象的不存在或不可访问的属性时提供一个统一的处理逻辑使其不会导致错误
参数:$name:被访问的属性的名称
返回值:自由定义返回值
__isset()
触发时机:检查一个对象的不存在或不可访问的属性时
功能: 检查一个对象的不存在或不可访问的属性时提供一个统一的处理逻辑使其不会导致错误
参数:$name :属性名称
返回值:通常返回一个布尔值(true/false)
4、 __set()和__unset()
__set()
触发时机:设置一个对象的不存在或不可设置的属性时
功能:在设置一个对象的不存在或不可设置的属性时提供一个统一的处理逻辑使其不会导致错误
参数:$name :属性名称
$value:设置属性的值
返回值:通常无返回值
__unset()
触发时机:unset()函数尝试删除对象不存在或不可访问属性时自动触发
功能:销毁对象中未定义的属性时执行自定义的操作
参数:$name:被销毁属性名称
返回值:无
5、__sleep()和__wakeup()
__sleep()
触发时机:在对象被序列化之前
功能:用于指定哪些对象属性需要在序列化时被保存
参数:无
返回值:返回需要被序列化的属性名的数组
__wakeup()
触发时机:反序列化之后
功能:用于指定在对象反序列化时需要执行的操作
参数:无
返回值:无
6、__toString()和__invoke()
__toString()
触发时机:对象被隐式地转换为字符串时自动触发
功能:用于指定在对象反被当作字符串调用时需要执行的操作
参数:不接受传递参数
返回值:必须返回一个字符串
__invoke()
触发时机:被作为函数调用时自动触发
功能:在一个对象被作为函数调用时执行相关的操作
参数:任意参数
返回值:任何类型
7、__set__state()和__clone()
__set__state()
触发时机:eval()函数将对象字符串转化为原始对象后
功能:用于指定对象从字符串形式恢复为php代码时的行为,被用与var_export()函数所产生的字符串输出的反序列化操作
参数: $data:对象的属性数组
返回值:最好返回一个对象的实例
__clone()
触发时机:使用clone关键字对一个对象进行克隆操作时
功能:在对象被克隆时提供一个修改克隆副本的机会
参数:无
返回值:不需要
8、__autoload()和__debuginfo()
__autoload()
触发时机:尝试使用一个未定义的类时
功能:PHP引擎尝试实例化一个未定义的类时,动态加载类文件
参数:$name:类名
返回值:不需要
__debuginfo()
触发时机:可以控制对象在使用var_dump()函数或调试时打印的信息
功能:自定义对象在被调试时的输出,可以控制对象在使用var_dump()函数时打印的信息
参数:无
返回值:返回一个数组,其中需要包含在调试输出中显示的属性和其对应的值
5、pop链相关知识
什么是pop链
pop链就是利用了PHP中对象的自动调用魔术方法特性,将多个类和方法串联起来,形成一个链式调用。当PHP反序列化时,会自动调用这些方法,触发代码执行
pop链构造技巧
1、简单浏览:找出可能存在的漏洞点
需要重点关注eval()、include()这种易引发漏洞的函数
2、根据漏洞点反推:看逻辑是否可行(参数、魔术方法、条件)
一般先找到注入点,判断注入需要的参数,然后再找到包含执行注入的函数(一般为魔术方法),再找执行此函数的条件a,判断条件a是否可以满足,然后再找执行条件a需要满足的条件b,依次找下去直到不需要再找需要满足的条件即可。
3、最后验证poc验证 ( 最好从后往前构造)
找到正确触发魔术方法的究竟是谁($this指的是谁)
pop链例题解析
<?php
class test {
private $index;
function __construct() {
$this->index = new index();
}
function __destruct() {
$this->index->hello(); // Call hello method of index object
}
}
class index {
public function hello() {
echo "你好呀"; // Added a semicolon here
}
}
class execute {
public $test;
function hello() {
eval($this->test);
}
}
unserialize($_GET['test']);
?>
先分析一下:
1、要让hello()的函数执行起来,需要先借助eval()函数。首先,通过system()函数执行系统命令,将其结果赋值给变量$test
2、确保hello()函数执行时,满足__destruct()方法被触发(在反序列化test对象后自动执行),并且将 $index 设置为 new execute()。
3、最后确保将$index设置为execute的实例时,满足__construct方法不会触发(即在反序列化test对象时不会触发)。
开始构造pop链
// pop链构造
class test{
private $index;
function __destruct()
{
$this->index = new execute();
}
}
class execute{
public $test =" system('dir');";
}
$a = new test();
echo urlencode(serialize($a));
输出结果:O%3A4%3A%22test%22%3A1%3A%7Bs%3A11%3A%22%00test%00index%22%3BN%3B%7D
完整url:/demo.php?test=O%3A4%3A%22test%22%3A1%3A%7Bs%3A11%3A%22%00test%00index%22%3BN%3B%7D
6、常见的绕过操作
1、输出类的原有属性
当序列化字符串不包含原先属性且语法正确的情况下,反序列化会输出类中原有的其他属性
2、序列化同属性值覆盖
序列化字符串出现重复的属性和值,后者会覆盖原先的值。当序列化字符串不包含原先属性且语法正确的情况下,反序列化会输出类中原有的其他属性
3、绕过__wakeup
漏洞产生原因:如果存在__wakeup()方法,调用unserilize()方法前则先调用__wakeup方法,但是当序列化字符串中表示对象属性个数的值大于真实属性个数时,会跳过__wakeup()执行
4、__destruct的强制触发
5、绕过特定的正则
利用加号绕过(在url里传参时➕要编码为%2B)
利用数组对象绕过(如serialize(array($a)); a为要反序列化的对象)
利用引用实现严格等于
引用a属性的地址值, 使得$b和$a 地址相同,进而使得值相等
6、16进制绕过简单字符的过滤
7、字符串逃逸相关知识
什么是字符串逃逸
开发者一般先将对象序列化,然后将序列化后的敏感字符进行过滤或替换,最后再进行反序列化。这个时候就有可能会产生字符逃逸的漏洞
php序列化字符串的结束特性
以:作为字段的分隔,以} 作为结尾
字符串增多逃逸
O:6:"Person":2:{s:4:"name";s:5:"admin";s:3:"age";i:30;} ---->O:6:"Person":2:{s:4:"name";s:5:"hacker";s:3:"age";i:30;}
字符串减少逃逸
O:6:"Person":2:{s:4:"name";s:5:"admin";s:3:"age";i:30;} ---->O:6:"Person":2:{s:4:"name";s:5:"hack";s:3:"age";i:30;}
1、吞单字符情况
8、sesssion反序列化漏洞相关知识
什么是cookie
cookie一般用来保存用户信息,存储在客户端,服务器端通过cookie中携带的数据区分不同户
cookie也会存在一些问题,比如存储数据少,存放与客户端导致安全性低等
什么是session
session是基于cookie实现的,存储在服务器端中,服务器端根据name为JSESSIONID的cookie的value,去查询session对象,从而区分不同用户
php中的session机制
核心函数:session_start()
作用:打开session,会随机生成一个32位的session_id,session的机制就是基于这个session_id,服务器就是通过这个唯一的session_id来区分出这是哪个用户访问的
存储格式
php ---------> 键名+竖线+经过serialize()函数序列化处理的值
php_binary ----------> 键名长度对应的ASCII字符 + 键名 + 经过serialize()函数序列化处理的值
php_serialize ----------> 经过serialize()函数序列化处理的数组
session反序列化漏洞成因
当网站序列化并存储session,与反序列化并读取session的方式不同,就可能导致session反序列化漏洞的产生
9、phar反序列化漏洞相关知识
什么是phar
PHAR是PHP里类似于JAR的一种打包文件,专门用于PHP应用程序的打包和分发
phar组成
Phar file stub(头部标识)
Phar manifest file entry definition(内容清单)<--- 漏洞利用点
the file contents(压缩文件内容)
a signature for veryifying Phar integrity(文件签名)
phar反序列化漏洞原理
1、Phar 文件在被处理时,其中的元数据会被反序列化为 PHP 对象。如果应用程序对 Phar 文件中的元数据执行了反序列化操作而没有进行充分的验证,攻击者可以构造恶意的元数据,其中包含恶意的 PHP 代码。
2、当应用程序反序列化恶意的 Phar 元数据时,其中的恶意代码会被执行,从而导致安全漏洞。
phar使用前提条件
1、phar文件要能够合理上传至服务器端
2、要有可用的魔术方法作为"跳板"
3、要有文件操作函数。如file_exists()、fopen()、file_get_contents()
4、并且文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤