# /usr/bin/torunar

Проблемы сериализации при атаке «Звезды смерти»

Оказался я пару дней назад в весьма неприятной ситуации. Есть огромный SQL-дамп базы проекта, который работал на сервере под управлением 64-битной ОС. Некоторые поля записей содержат данные, обработанные функцией serialize().

После разворачивания дампа БД на сервере с 32-битной ОС проект оказался частично нерабочим: попытки десериализации некоторых данных заканчивались неудачей. Я бы махнул на это рукой, но требования к работоспособности были достаточно четкие: «шоб везде».

Разберемся для начала, откуда вообще растут ноги проблемы.

Многие со школы помнят следующую формулу:

Imax = 2n – 1 – 1,

где:

  • n — разрядность системы,
  • Imax — максимальное значение знакового целого числа, возможного в данной разрядности.

Так, для 32-битной системы, Imax равно 2147483647), а для 64-битной — 9223372036854775807.

Результаты сериализации чисел, значение которых превышает выше упомянутое 2147483647, для разных ОС также будут различными. Рассмотрим на примере 4294967296:

vagrant@trusty64:~ $ php -r 'var_dump(serialize(4294967296));'
string(13) "i:4294967296;"

vagrant@trusty32:~ $ php -r 'var_dump(serialize(4294967296));'
string(13) "d:4294967296;"

Как видно, на 64-битной системе число было сериализовано с типом i, integer (целое число), а на 32-битной — c типом d, double precision (число двойной точности).

Соответственно, при попытке десериализации i:4294967296; на 32-битной ОС будет предпринята попытка поместить в целое число значение превышающее максильно допустимое, что приведет к возникновению ошибки.

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

vagrant@trusty64:~ $ sed -i.bak -E -e 's/i:([0-9]+)\;/d:\1\;/g' dump.sql

Однако это не обеспечило работоспособности приложения, напротив, породило только большее количество ошибок. Вместо этого я решил положиться на утиную типизацию в PHP и заменил все числовые значения на строки: так, i:4294967296; стало s:10:"4294967296";.

В процессе я накидал простой скрипт facepalm.php: он проходится по скормленному ему файлу и заменяет все представления целых чисел строками. Этим скриптом я прошерстил дамп проекта, что позволило завести его как в 32-, так и в 64-битной ОС.