Следующая новость
Предыдущая новость

Документный червь. Эксплуатируем необычную XSS и обходим CSP на примере CodiMD

27.04.2019 1:53
Документный червь. Эксплуатируем необычную XSS и обходим CSP на примере CodiMD

Содержание статьи

  • Стенд
  • Детали уязвимости
  • Демонстрация уязвимости (видео)
  • Выводы

Есть такой сервис для совместного редактирования текста — HackMD. Штука сама по себе полезная, но нас сегодня интересует ее реализация для установки на свой сервер — CodiMD. В ней нашли баг, позволяющий сделать код, который будет передаваться от пользователя к пользователю. Отличный случай, чтобы разобрать эксплуатацию неочевидных XSS и обсудить обход Content Security Policy (CSP).

INFO

Эту уязвимость нашел китайский исследователь Оранж Цай (Orange Tsai).

Стенд

Официальная документация предлагает на выбор несколько вариантов разворачивания CodiMD. Один из них — Docker, его и будем использовать.

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

$ git clone https://github.com/hackmdio/docker-hackmd.git $ cd docker-hackmd 

Теперь необходимо, чтобы при сборке устанавливалась нужная версия приложения. Уязвимы все версии до принятия пул-реквеста номер 1112 в основную ветку, то есть выпущенные до 29 декабря 2018 года. На момент написания статьи в файле конфигурации docker-compose значится версия 1.2.0.

docker-compose.yml
app:     ...     image: hackmdio/hackmd:1.2.0 
Документный червь. Эксплуатируем необычную XSS и обходим CSP на примере CodiMD
Уязвимая версия HackMD в дефолтном конфиге docker-compose

Эта версия вышла 27 сентября 2018 года, что меня вполне устраивает.

Документный червь. Эксплуатируем необычную XSS и обходим CSP на примере CodiMD
Дата выхода контейнера HackMD версии 1.2.0

Остается просто поднять окружение при помощи docker-compose.

$ docker-compose up 

И через несколько мгновений перед нами готовый стенд.

Документный червь. Эксплуатируем необычную XSS и обходим CSP на примере CodiMD
Готовый стенд с уязвимой версией CodiMD

К слову, версия 1.2.1 тоже уязвима, поэтому можно использовать и ее.

Детали уязвимости

Одна из особенностей HackMD — риалтаймовое обновление превью. То есть разметка Markdown рендерится в HTML, который выводится в окно слева от исходного кода.

Документный червь. Эксплуатируем необычную XSS и обходим CSP на примере CodiMD
Обновление документа на лету

Так как страница клиента изменяется на лету и рендерит введенные пользователем данные, то защита от XSS становится очень актуальной задачей. Ведь Markdown — это надстройка над HTML, соответственно, помимо разметки Markdown, в документе можно использовать и другие теги. А скрипты — это, в свою очередь, валидный HTML.

HackMD написан с использованием Node.js и для этих целей привлекает библиотеку XSS, первая версия которой вышла аж семь лет назад и с тех пор стабильно обновляется. Давай посмотрим, как она применяется при рендеринге пользовательского содержимого. Для этого заглянем в файл render.js.

/codimd-1.2.0/public/js/render.js
11: var whiteList = filterXSS.whiteList ... 35: var filterXSSOptions = { 36:   allowCommentTag: true, 37:   whiteList: whiteList, 38:   escapeHtml: function (html) { 39:     // Allow HTML comment in multiple lines 40:     return html.replace(/<(?!!--)/g, '&lt;').replace(/-->/g, '__HTML_COMMENT_END__').replace(/>/g, '&gt;').replace(/__HTML_COMMENT_END__/g, '-->') ... 68: function preventXSS (html) { 69:   return filterXSS(html, filterXSSOptions) 70: } 71: window.preventXSS = preventXSS 72: 73: module.exports = { 74:   preventXSS: preventXSS 75: } 

Библиотека XSS предоставляет разработчикам возможность гибкой настройки фильтрации. Это делается при помощи таких опций, как, например, allowCommentTag или whiteList, и колбэков — onTagAttr и onIgnoreTagAttr. Здесь особый интерес представляет onIgnoreTag.

/codimd-1.2.0/public/js/render.js
42:   onIgnoreTag: function (tag, html, options) { 43:     // Allow comment tag 44:     if (tag === '!--') { 45:             // Do not filter its attributes 46:       return html 47:     } 48:   }, 

Как видишь, все комментарии переносятся из исходного кода в отрендеренную страницу без какой-либо фильтрации.

<!-- comment, aga --> 
Документный червь. Эксплуатируем необычную XSS и обходим CSP на примере CodiMD
Комментарии переносятся в отрендеренную страницу без фильтрации

Это полезно, если нужно сохранить полную структуру документа. Однако так ли это безопасно?

По большому счету конструкция <!-- — это тоже тег, и у него могут быть атрибуты. Поэтому попробуем классическую атаку с внедрением HTML-кода в них, ведь они не фильтруются (// Do not filter its attributes). 😉

<!-- attr="value--> <b>Oops</b>" --> 
Документный червь. Эксплуатируем необычную XSS и обходим CSP на примере CodiMD
Внедрение HTML-тегов с помощью указания атрибутов к тегу комментария

Вот уж действительно «Упс!».

Логично предположить, что у нас имеется полноценная XSS, достаточно протянуть к ней script, и вот оно, исполнение кода на клиенте, у нас в руках. Но это не так, ведь тут в дело вступают политики CSP, которые разрешают выполнение кода на JavaScript только из доверенных источников.

Продолжение доступно только подписчикам

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

Подпишись на «Хакер» по выгодной цене!

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

1 год

5240 р.

Экономия 1400 рублей!

1 месяц

720 р.

25-30 статей в месяц

Уже подписан?

Источник

Последние новости