Некоторые считают Perl «проблемным» языком. На мой взгляд, проблемы с безопасностью в Perl-проектах частично возникают из-за ложных предположений, которые делают разработчики. Одним из таких ложных предположений является распространенное предположение, что хэши и массивы (нескалярные типы данных) являются «безопасными», часто пропуская их проверки безопасности. Это можно увидеть на следующем примере:

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

В этом сообщении в блоге я попытаюсь опровергнуть это предположение, используя ошибку безопасности в ядре Bugzilla. Для получения дополнительной информации о проблемной природе Perl вы можете посмотреть мой недавний доклад 32C3 — The Perl Jam 2: The Camel Strikes Back.

Ошибка (зилла)

Bugzilla, как и многие другие Perl-проекты, активно использует ключевое слово «ref». Ключевое слово «ref» отвечает за возврат типа переменной, и Bugzilla широко использует его, особенно в своих функциях инициализации объектов.

Такой функцией является ‘_load_from_db()’, которую можно увидеть здесь:

Легко заметить, что функция действует совершенно по-разному в зависимости от типа данных $param. Если «$param» является скаляром, он преобразуется в целое число путем удаления из него всех нечисловых символов. С другой стороны, если это хеш, из него извлекаются определенные ключи и используются внутри SQL-запроса без дальнейшей проверки. Причина такого различного поведения заключается в том, что хэши часто считаются безопасными, поскольку предполагается, что они не могут быть сгенерированы из стандартного пользовательского ввода и, следовательно, не нуждаются в экранировании. Как вы увидите, это серьезное ложное предположение, сделанное разработчиками.

Это означает, что если мы будем контролировать значение ‘$param’ и, конечно же, его тип данных, мы сможем использовать атаку SQL Injection в системе. Несмотря на то, что управлять значением $param легко, управлять его типом данных будет довольно сложно. Если подумать, это кажется невозможным — как вообще можно управлять типом данных входного параметра?

Ну, ответ заключается в том, как анализируется ввод. Bugzilla использует модуль «CGI.pm», который свободно позволяет устанавливать списки в качестве входных данных (чем злоумышленник может злоупотреблять), но ограничивает использование любых других типов данных. На самом деле с помощью этого модуля нельзя создавать ни хэши, ни массивы. Однако, к счастью для злоумышленника, «CGI.pm» — не единственный модуль, анализирующий пользовательский ввод. Другим модулем, назначенным для этой задачи, является модуль XMLRPC.

В Bugzilla реализовано несколько методов удаленного взаимодействия с системным API: использование REST API, JSONRPC и нашего XMLRPC. Когда пользователь отправляет запрос XMLRPC, сервер анализирует его с использованием стандарта XMLRPC, который позволяет использовать массивы и словари в качестве типов ввода. Из-за этого Bugzilla также позволяет использовать эти нестандартные типы данных в качестве параметров в своих функциях RPC. Важно отметить, что такое поведение не является проблемой. Разрешение хэшей и массивов в RPC — удобная функция, используемая во многих проектах.

Проблема в том, что в этом RPC несколько раз отсутствует проверка типа входных данных. Один из таких случаев можно увидеть в функции «get()» внутри модуля веб-службы «bug»:

Так как мы контролируем $params, мы контролируем $ids, а поскольку входные данные поступают из модуля RPC, мы не ограничены только скалярными значениями в качестве входных данных и можем также использовать массивы и хэши.

Таким образом, мы можем вставить хэш в «Bug-›check()» и вызвать SQLI, если мы вставим хэш в «_load_from_db()», но нам все еще нужно сопоставить их.

Эта корреляция, на самом деле, очень очевидна. Поскольку «check()» отвечает за извлечение конкретной ошибки из базы данных, для этого используется функция «_load_from_db()». Поскольку «check()» предполагает, что хеш-аргументы полностью контролируются системой и не представляют опасности, она передает их как есть в «_load_from_db()». И это настоящая проблема. Именно здесь ложное предположение о «безопасных» типах данных позволяет нам свободно использовать SQLI без каких-либо специальных разрешений.

Эта ошибка безопасности позволяет злоумышленнику, не прошедшему проверку подлинности, выполнить атаку SQL Injection на платформе Bugzilla, что в некоторых случаях позволяет полностью скомпрометировать сервер.

В случае с Bugzilla включение Perl «Taint Mode» ограничило бы нашу инъекцию. Taint Mode — это, по сути, «безопасный режим» для приложений Perl, который гарантирует, что входные данные проверяются до их использования в опасных функциях, таких как «open()», «eval()», или даже в функциях БД, таких как «selectrow()». '. Как и в случае любого встроенного механизма безопасности, зависящего от языка, на «режим заражения» нельзя полагаться исключительно, главным образом потому, что он может быть отключен, удален или изменен сторонними организациями.

Без «Taint Mode» серьезность этой уязвимости была бы огромной, фактически раскрывая всю базу данных для любого злоумышленника на любой установке Bugzilla по всему миру.

Выводы

В любом языке легко сделать ложные предположения, будь то C, Java или Python. Проблема начинается, когда эти ложные предположения становятся частью общей языковой практики.

Если вы все еще используете Perl в среде CGI, лучший совет, который я могу вам дать, — это либо переключиться на PSGI, либо на совершенно другой язык, потому что CGI и CGI.pm устарели (в Perl) и не должны использоваться. .

Но самый главный урок — НЕ предполагайте. Не предполагайте, что ваш ввод относится к какому-либо конкретному типу данных, не предполагайте, что хэши безопасны, просто не предполагайте, так как в большинстве случаев вы будете неправы.

Первоначально опубликовано на www.perimeterx.com.