Easy Hack: XSS с помощью SVG

Первые несколько атак этого выпуска Easy Hack будут завязаны на формат SVG. Причем хочется взглянуть даже не на сами атаки, а на потенциальные возможности формата.

Итак, SVG — это Scalable Vector Graphics, язык разметки масштабируемой векторной графики, он входит в подмножество расширяемого языка разметки XML и предназначен для описания двумерной векторной и смешанной векторно-растровой графики в формате XML. То есть мы имеем возможность описать в XML то, что должно быть на рисунке, а также добавить динамику.

Вот так, к примеру, можно нарисовать красный круг.

<svg height="100" width="100">
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>

Кроме того, SVG поддерживает CSS. Добавим после тега <svg> стиль и получим синий круг:

<style>
  circle {fill: blue}
</style>

А еще SVG поддерживает JavaScript — с его помощью делается анимация. Для этого можно использовать все тот же стандартный тег <script>:

<svg height="100" width="100">
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
  
</svg>

SVG поддерживает и XLink (создание ссылок между документами XML), что дает возможность подгружать ресурсы из сторонних файлов. Тот же alert() можно подгрузить из файла:

Причем в некоторых браузерах можно подгружать ресурсы и со сторонних хостов.

Интересно, что в SVG можно встраивать код на HTML (тег foreignObject) и картинки (<image>). При этом SVG в той или иной мере поддерживается всеми основными браузерами.

Как видишь, хоть SVG и картинка, но из нее можно без проблем запускать код на JavaScript. Таким образом, если есть какой-то сайт, куда можно загружать картинки в SVG, то можно попытаться получить на этом сайте хранимую XSS’ку. Для этого нужно знать еще несколько тонкостей, связанных с тем, как браузер открывает SVG. Есть несколько вариантов вставить SVG:

  • как картинку — через тег <img> или свойство CSS background-image. Но в этом случае во всех современных браузерах JavaScript выполняться не будет;
  • как сторонний объект — с помощью тегов <object>, <embed>, <iframe>. JS в этом случае работает, но требуется помнить про то, что работают и стандартные Same Origin Policy;
  • встроить в саму страницу (inline). Примеры выше как раз такие, и JavaScript работает;
  • с помощью тега canvas. По идее, JS в этом случае работать не должен, но подтверждения этому я не нашел.

Если мы загрузим на сервер-жертву файл SVG, то, возможно, он отобразится, но в нем не будет работать JavaScript — как раз из-за того, что он подгружается с помощью тега <img>. Но мы спокойно можем воспользоваться вторым или третьим методом и использовать прямую ссылку на наш SVG на атакуемом сервере.

Интересный момент: к SVG применяются не все правила парсинга XML. Возможно, это связано лишь с известной гибкостью браузерных парсеров. Например, для корректного XML необходимо, чтобы значения атрибутов элементов были обрамлены двойными кавычками (см. пример выше). Но в SVG мы можем избавиться от них.

<circle cx=50 cy=50 r=40 stroke=black stroke-width=3 fill=red />

Кроме того, если где-то будет незакрытая кавычка, то в случае с XML документ не будет считаться корректным, а в SVG такие атрибуты просто пропускаются. То же самое относится и к тегам. Это дает дополнительное пространство для атак.

Еще одну лазейку открывает то, что в SVG можно встраивать другие документы или даже тот же самый документ. Это может быть использовано для обхода Content Security Policy — примеры можно увидеть в презентации с Black Hat 2014, один из них я разберу подробнее.

Ну и последнее, что нужно знать об SVG, — он является «официальным» XML и потому глубоко связан с остальным семейством форматов. SVG поддерживает Document Type Definition (DOCTYPE) с сущностями (entity), а потому есть потенциальная возможность для эксплуатации XXE. Также он поддерживает технологию XSLT. Можно, например, сделать такой файл SVG, который при открытии с помощью тега <img> будет показывать картинку, а при открытии в <iframe> будет с помощью XSLT-преобразования превращаться в HTML (должно работать в IE и FF).

<?xml version="1.0"?>
<?xml-stylesheet type="text/xml" href="#stylesheet"?>
<!DOCTYPE doc [ <!ATTLIST xsl:stylesheet id ID #REQUIRED>]>
<svg xmlns="http://www.w3.org/2000/svg">
  <xsl:stylesheet id="stylesheet" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
      <iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:alert(1)"></iframe>
    </xsl:template>
  </xsl:stylesheet>
  <circle fill="red" r="40"></circle>
</svg>

Возможности SVG очень широки, а вот методы их применения для атак еще далеко не полностью изучены, так что можно ждать новостей на этом фронте или экспериментировать самостоятельно.

Алексей GreenDog Тюрин: Security Researcher
Похожие материалы