diff --git a/src/de/qtc/rmg/io/Formatter.java b/src/de/qtc/rmg/io/Formatter.java index b690111..b1755cc 100644 --- a/src/de/qtc/rmg/io/Formatter.java +++ b/src/de/qtc/rmg/io/Formatter.java @@ -13,6 +13,7 @@ import de.qtc.rmg.operations.RemoteObjectClient; import de.qtc.rmg.utils.ActivatableWrapper; import de.qtc.rmg.utils.RemoteObjectWrapper; +import de.qtc.rmg.utils.SpringRemotingWrapper; import de.qtc.rmg.utils.UnicastWrapper; /** @@ -245,11 +246,40 @@ private void listVulnerabilities(List vulns) */ private void printRemoteRef(RemoteObjectWrapper wrapper) { - if (wrapper instanceof UnicastWrapper) + if (wrapper instanceof SpringRemotingWrapper) + { + printSpringRemoting((SpringRemotingWrapper)wrapper); + } + + else if (wrapper instanceof UnicastWrapper) + { printUnicastRef((UnicastWrapper)wrapper); + } else + { printActivatableRef((ActivatableWrapper)wrapper); + } + } + + /** + * Print information on a SpringRemotingWrapper. This information includes the real + * interface name that can be accessed via the spring remoting wrapper and all information + * that is printed by the printUnicastRef method. + * + * @param ref SpringRemotingWrapper containing the wrapper + */ + private void printSpringRemoting(SpringRemotingWrapper ref) + { + String interfaceName = ref.getInterfaceName(); + + if (interfaceName != null) + { + Logger.print(" "); + Logger.printlnPlainMixedPurple("Spring Remoting Interface:", interfaceName); + } + + printUnicastRef((UnicastWrapper)ref); } /** diff --git a/src/de/qtc/rmg/operations/RemoteObjectClient.java b/src/de/qtc/rmg/operations/RemoteObjectClient.java index 5f68c94..bd72f68 100644 --- a/src/de/qtc/rmg/operations/RemoteObjectClient.java +++ b/src/de/qtc/rmg/operations/RemoteObjectClient.java @@ -16,7 +16,7 @@ import de.qtc.rmg.networking.RMIRegistryEndpoint; import de.qtc.rmg.utils.DefinitelyNonExistingClass; import de.qtc.rmg.utils.RMGUtils; -import de.qtc.rmg.utils.SpringRemoting; +import de.qtc.rmg.utils.SpringRemotingWrapper; import de.qtc.rmg.utils.UnicastWrapper; import javassist.CannotCompileException; import javassist.CtClass; @@ -276,10 +276,10 @@ public void codebaseCall(MethodCandidate targetMethod, Object gadget, int argume */ public void genericCall(MethodCandidate targetMethod, Object[] argumentArray) { - if (SpringRemoting.isRemotingCall(remoteObject, targetMethod)) + if (remoteObject instanceof SpringRemotingWrapper && ((SpringRemotingWrapper)remoteObject).isRemotingCall(targetMethod)) { - argumentArray = new Object[] { SpringRemoting.buildRemoteInvocation(targetMethod, argumentArray) }; - targetMethod = SpringRemoting.getInvokeMethod(); + argumentArray = new Object[] { SpringRemotingWrapper.buildRemoteInvocation(targetMethod, argumentArray) }; + targetMethod = SpringRemotingWrapper.getInvokeMethod(); } CtClass rtype = null; @@ -359,6 +359,7 @@ public void guessingCall(MethodCandidate targetMethod) throws Exception public static List filterEmpty(List clientList) { Iterator it = clientList.iterator(); + while (it.hasNext()) { if (it.next().remoteMethods.isEmpty()) diff --git a/src/de/qtc/rmg/plugin/ReturnValueProvider.java b/src/de/qtc/rmg/plugin/ReturnValueProvider.java new file mode 100644 index 0000000..eb6c846 --- /dev/null +++ b/src/de/qtc/rmg/plugin/ReturnValueProvider.java @@ -0,0 +1,16 @@ +package de.qtc.rmg.plugin; + +public class ReturnValueProvider implements IResponseHandler +{ + private Object value = null; + + public void handleResponse(Object responseObject) + { + value = responseObject; + } + + public Object getValue() + { + return value; + } +} diff --git a/src/de/qtc/rmg/utils/RemoteObjectWrapper.java b/src/de/qtc/rmg/utils/RemoteObjectWrapper.java index d3b63ab..d41d2b3 100644 --- a/src/de/qtc/rmg/utils/RemoteObjectWrapper.java +++ b/src/de/qtc/rmg/utils/RemoteObjectWrapper.java @@ -84,16 +84,32 @@ public static RemoteObjectWrapper getInstance(Remote remote) throws IllegalArgum public static RemoteObjectWrapper getInstance(Remote remote, String boundName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { RemoteObjectWrapper wrapper = null; + RemoteRef ref = RMGUtils.extractRef(remote); + String className = RMGUtils.getClassName(remote); if (ref instanceof UnicastRef) - wrapper = new UnicastWrapper(remote, boundName, (UnicastRef)ref); + { + if (className.equals(SpringRemotingWrapper.invocationHandlerClass)) + { + wrapper = new SpringRemotingWrapper(remote, boundName, (UnicastRef)ref); + } + + else + { + wrapper = new UnicastWrapper(remote, boundName, (UnicastRef)ref); + } + } else if (ref.getClass().getName().contains("ActivatableRef")) + { wrapper = new ActivatableWrapper(remote, boundName, ref); + } else + { ExceptionHandler.internalError("RemoteObjectWrapper.getInstance", "Unexpected reference type"); + } return wrapper; } @@ -188,14 +204,18 @@ public static UnicastWrapper[] getUnicastWrappers(RemoteObjectWrapper[] wrappers { if (wrappers[ctr] instanceof UnicastWrapper) { - unicastWrappers[ctr] = (UnicastWrapper) wrappers[ctr]; + unicastWrappers[ctr] = (UnicastWrapper)wrappers[ctr]; } else { - try { + try + { unicastWrappers[ctr] = ((ActivatableWrapper)wrappers[ctr]).activate(); - } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { + } + + catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) + { ExceptionHandler.unexpectedException(e, "activate", "call", true); } } diff --git a/src/de/qtc/rmg/utils/SpringRemoting.java b/src/de/qtc/rmg/utils/SpringRemotingWrapper.java similarity index 78% rename from src/de/qtc/rmg/utils/SpringRemoting.java rename to src/de/qtc/rmg/utils/SpringRemotingWrapper.java index ad391b0..fec0e4f 100644 --- a/src/de/qtc/rmg/utils/SpringRemoting.java +++ b/src/de/qtc/rmg/utils/SpringRemotingWrapper.java @@ -1,13 +1,18 @@ package de.qtc.rmg.utils; +import java.rmi.Remote; + import org.springframework.remoting.support.RemoteInvocation; import de.qtc.rmg.internal.ExceptionHandler; import de.qtc.rmg.internal.MethodCandidate; -import de.qtc.rmg.internal.RMGOption; +import de.qtc.rmg.operations.RemoteObjectClient; +import de.qtc.rmg.plugin.PluginSystem; +import de.qtc.rmg.plugin.ReturnValueProvider; import javassist.CannotCompileException; import javassist.CtClass; import javassist.NotFoundException; +import sun.rmi.server.UnicastRef; /** * SpringRemoting represents a wrapper around regular Java RMI. Exposed methods are not directly available via @@ -16,7 +21,8 @@ * * @author Tobias Neitzel (@qtc_de) */ -public class SpringRemoting +@SuppressWarnings("restriction") +public class SpringRemotingWrapper extends UnicastWrapper { public final static String invocationHandlerClass = "org.springframework.remoting.rmi.RmiInvocationHandler"; public final static String methodGetStr = "java.lang.String getTargetInterfaceName()"; @@ -25,6 +31,26 @@ public class SpringRemoting private static MethodCandidate methodGet; private static MethodCandidate methodInvoke; + private static String interfaceName; + + public SpringRemotingWrapper(Remote remoteObject, String boundName, UnicastRef ref) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException + { + super(remoteObject, boundName, ref); + + ReturnValueProvider respHandler = new ReturnValueProvider(); + PluginSystem.setResponeHandler(respHandler); + + RemoteObjectClient client = new RemoteObjectClient(this); + client.genericCall(getInterfaceNameMethod(), new Object[] {}); + + interfaceName = (String)respHandler.getValue(); + } + + public String getInterfaceName() + { + return interfaceName; + } + /** * Return a MethodCandidate for the getTargetInterfaceName method that is exposed by the RmiInvocationHandler * remote object. @@ -73,18 +99,8 @@ public static MethodCandidate getInvokeMethod() return methodInvoke; } - public static boolean isRemotingCall(RemoteObjectWrapper remoteObject, MethodCandidate targetMethod) + public boolean isRemotingCall(MethodCandidate targetMethod) { - if (RMGOption.SPRING_REMOTING.getBool()) - { - return true; - } - - if (remoteObject == null || !remoteObject.className.equals(invocationHandlerClass)) - { - return false; - } - long targetHash = targetMethod.getHash(); if (targetHash == getInvokeMethod().getHash() || targetHash == getInterfaceNameMethod().getHash())