Потенциальная опасность при использовании jsonp в движке

Безопасность LiveStreet CMS
Некоторое время назад мной была найдена небольшая неточность, которая при определенном стечении обстоятельств может дать серьезную проблему связанную с безопасностью. А именно — недостаточная фильтрация колбека для jsonp ответа вьюера.

Рассмотрим для начала участок кода для вывода jsonp ответа метода DisplayAjax вьюера:

if ($this->bResponseSpecificHeader and !headers_sent()) {
  header('Content-type: application/json');
}
echo getRequest('jsonpCallback','callback').'('.json_encode($this->aVarsAjax).');';

Примечание: этот тип ответа — публичный и он не требует ключа безопасности — это уже удобно.

Суть ситуации

При определенной подстановке специального значения в имени колбека — можно модифицировать ответ сервера на jsonp-запрос таким образом, что реальные данные будут отброшены (не актуальны) и клиенту будет возвращен небезопасный сторонний код. А именно, если в колбек послать код:
<html><body><script>(function(){ alert('Test'); })()</script></body></html><!--

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

<html><body><script>(function(){ alert('Test'); })()</script></body></html><!--({"some_json_data":"Тут весь ответ", ...});


Так просто это не работает

Но в связи с тем, что движок принудительно указывает заголовок ответа как json формат (application/json), то браузер разбирать такой ответ как хтмл код не будет и атака не удается.

Условия атаки

Как видно по примеру кода, перед самым выводом ответа существует условие проверки были ли ранее отправлены заголовки:

if ($this->bResponseSpecificHeader and !headers_sent()) {
  header('Content-type: application/json');
}

и если они не отправлялись то только лишь в этом случае они устанавливаются в json формат ответа.

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

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

В такой ситуации весь ответ от сервера будет трактоваться браузерами по-умолчанию — как «html/text», что приведет к его выполнению.

А это опасно

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

Непосредственный прием

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

Ингредиенты

Что необходимо для осуществления атаки:

  1. Сторонний плагин, предоставляющий отправку данных через формат jsonp
  2. Ошибка безопасности низкого уровня типа «раскрытие директории» или если плагин отключает вывод заголовков вручную при установке типа ответа «jsonp» через параметр $bResponseSpecificHeader — это вообще как подарок для атакующего
  3. Разрешение на вставку ифреймов с домена сайта

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

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

Итоги

Данный подход показывает как несколько относительно простых (по уровню угрозы) проблем в безопасности при объединении вместе могут составить серьезную проблему, которая может свестись к критической ситуации получения полного доступа к сайту. А именно:

  • казалось бы безобидное раскрытие директории (любые ошибки в скриптах)
  • разрешение вставки в ифрейм данных с текущего домена
  • и плагина, реализующего интерфейс публичного доступа к данным через jsonp

Но по-умолчанию из коробки, как и большинство плагинов, данный тип ответа не используют. Он нужен для связки АПИ третьей стороны с сайтом. Поэтому можно особо не волноваться, но как и было вначале статьи сказано — «при стечении обстоятельств».

P.S. Ошибка с колбеком jsonp исправлена в разрабатываемой версии лс.
2 комментария
lifecom
Дайте pls ссылку на исправление
Serge Pustovit
Исправления для лс 1.0.3 нет.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.