Expression Language injection (ELI)

Protect your applications against Expression Language injection

Java

Expression Language injection: the basics

What is Expression Language injection?

Expression Language injection (ELI) is a server-side code injection type of bug. ELI vulnerabilities occur when user input is not properly escaped before dynamically evaluating it using an expression language interpreter. Many languages and frameworks support expression language, giving developers an easy way to communicate with the application logic from within the presentation layer (web pages).

About this lesson

In this lesson, you will learn how Expression Language injection (ELI) works and how to protect your applications against it. We will begin by exploiting an ELI vulnerability in a simple application. Then we will analyze the vulnerable code and explore some options for remediation and prevention.

FUN FACT

Log4j

Late 2021, the infamous Apache Log4j logging library suffered one of the biggest known expression language injection bugs in history. The vulnerability allowed remote attackers to gain access to the vulnerable system by using a payload that utilizes expression language combined with a JNDI lookup.

Expression Language injection in action

Meet Jane: a fashion fanatic by day and a hacker by night.

Jane decides to test her favorite fashion outlet against a list of vulnerability classes. She is currently testing the search functionality and already tested it against SQL injection (SQLi) and cross-site scripting (XSS). No luck on those, but that doesn’t mean it is safe yet.

Testing for Express Language injection

  • STEP 1
  • STEP 2
  • STEP 3
  • STEP 4
  • STEP 5

Setting the stage

Jane comes across a vulnerability; Expression Language injection. She decides to make this her last test before going to bed after a night of hacking.

express-step-1.svg

Expression Language injection under the hood

Let's break down what happened in the story above.

Jane entered a payload that contained Java enclosed in ${...}. In Java, ${...} as well as #{...} is seen as valid Expression Language. Everything inside this enclosure will be evaluated server-side. See the official Java documentation on this here.

The search engine of the fashion outlet website used Expression Language in a slick way that is similar to templating. The search results stored at the back end would be dynamic for easy maintainability. For example, if a user searches for “Namebrand T-shirt”, the search results returned from the search engine would be something like:

${garment(2932).manufacturer}: T-shirt
${garment(2735).manufacturer}: Polo
${garment(1987).manufacturer}: Short-Sleeve

By keeping these values dynamic, the outlet website does not have to modify all data entries when a garment property needs updating.

To fill in these values, the backend utilizes the Java Expression Language (Expression Factory) library to render all the expressions.

This is a valid and slick approach if there would have been no injection. But unfortunately in the case of the outlet search engine back-end, there was an injection point, where user input ended up in the search results that would be rendered.

Given the following (shortened for easy understanding) JSP code:

And the following (also shortened for easy understanding) Java back-end code:

The system.Search() function returns the search results, but in cases where no results are found, it returns the error string “Sorry, no Search results for" + input.

As you might have guessed already, this string is then evaluated by the expression language renderer and reflected onto the page.

Impacts of Expression Language injection

The impact of an Expression Language injection is practically remote code execution. An attacker can call system functions from within the expression language and utilize this to extract data or run commands.

Because unrestricted code execution is not always possible due to certain restrictions or complications. Expression Language injection can also result in other, more limited, injection attacks such as SQL injection or cross-site scripting, as demonstrated in the BigCorp Clothing example.

Scan your code & stay secure with Snyk - for FREE!

Did you know you can use Snyk for free to verify that your code
doesn't include this or other vulnerabilities?

Scan your code

Expression Language injection mitigation

Preventing ELI vulnerabilities is as simple as not passing user input into an Expression Language interpreter. But this is easier said than done. There exist many frameworks that support Expression Language, and each has its own approach to handling expressions.

For example, the Spring framework has certain tags that, by default, double-interpret expression language. One reason for this is that Spring offers Expression Language (EL) support that is not reliant on the JSP/Servlet container. This was done to ensure compatibility with older versions, as expression language was not supported before JSP 2.0.

One of these “double interpret” locations is the code attribute in the <spring:message> tag. This means that any user input that ends up in that attribute, is evaluated a second time. More on this can be found in this excellent writeup.

In this case, to disable the double resolution functionality in versions 3.0.6 and above, you can place the following configuration in the applications web.xml:

Spring Expression Language Support
springJspExpressionSupport
false

This is a good example to showcase how user input should always be sanitized, even if you think no harm could be done.

To prevent the ELI vulnerability in the scenario of Jane and the Search Engine of the BigCorp Clothing, the steps are simple. Make sure that the system.Search() does not return an error that is constructed using user input, or, only render the search results when no error is returned.

In this scenario, it is easier to not render the user input, rather than trying to sanitize or filter the user input. Sanitization can fail when other encodings or formats are supported.

At last, a general piece of advice is to disable Expression Language, and only enable it when it is needed, and safely implemented.

In Tomcat, this can be done by adding <el-ignored>true</el-ignored> inside the <jsp-config> tag within the web.xml file, to explicitly disallow Expression Language. Then by configuring the @page with isELIgnored=true, this can be overwritten again to allow support for Expression Language.

Keep learning

To learn more about Expression Language injection, check out some other great content:

Congratulations

You have taken your first step into learning what Expression Language injection is, how it works, what the impacts are, and how to protect your own applications. We hope that you will apply this knowledge to make your applications safer. Make sure to check out our lessons on other common vulnerabilities.