不安全的反序列化
漏洞案例
漏洞描述
安全编码
反序列化漏洞,当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码(多见于第三方组件产生的漏洞)
1. 更新commons-collections、commons-io等第三方库版本; 2. 业务需要使用反序列化时,尽量避免反序列化数据可被用户控制,如无法避免建议尽量使用白名单校验的修复方式
运行
漏洞代码 - ObjectInputStream
// readObject,读取输入流,并转换对象。ObjectInputStream.readObject() 方法的作用正是从一个源输入流中读取字节序列,再把它们反序列化为一个对象。 // payload:java -jar ysoserial-0.0.6-SNAPSHOT-BETA-all.jar CommonsCollections5 "open -a Calculator" | base64 public String cc(String base64) { try { BASE64Decoder decoder = new BASE64Decoder(); base64 = base64.replace(" ", "+"); byte[] bytes = decoder.decodeBuffer(base64); ByteArrayInputStream stream = new ByteArrayInputStream(bytes); // 反序列化流,将序列化的原始数据恢复为对象 ObjectInputStream in = new ObjectInputStream(stream); in.readObject(); in.close(); return "反序列化漏洞"; } catch (Exception e) { return e.toString(); } }
漏洞代码 - SnakeYaml
运行
// 远程服务器支持用户可以输入yaml格式的内容并且进行数据解析,没有做沙箱,黑名单之类的防控 public void yaml(String content) { Yaml y = new Yaml(); y.load(content); }
运行
漏洞代码 - RMI Registry
// Java RMI Registry 反序列化漏洞,受jdk版本影响,< = jdk8u111 public String rmi() { try { Registry registry = LocateRegistry.createRegistry(9999); } catch (Exception e) { e.printStackTrace(); } return "开启RMI监听,端口:9999"; }
运行
安全代码 - 黑白名单
// 使用Apache Commons IO的ValidatingObjectInputStream,accept方法来实现反序列化类白/黑名单控制 public String safe(String base64) { try { BASE64Decoder decoder = new BASE64Decoder(); base64 = base64.replace(" ", "+"); byte[] bytes = decoder.decodeBuffer(base64); ByteArrayInputStream stream = new ByteArrayInputStream(bytes); ValidatingObjectInputStream ois = new ValidatingObjectInputStream(stream); // 只允许反序列化Student class ois.accept(Student.class); ois.readObject(); return "ValidatingObjectInputStream"; } catch (Exception e) { return e.toString(); }
运行
漏洞代码 - XMLDecoder
// XMLDecoder在JDK 1.4~JDK 11中都存在反序列化漏洞安全风险。攻击者可以通过此漏洞远程执行恶意代码来入侵服务器。在项目中应禁止使用XMLDecoder方式解析XML内容 String path = "src/main/resources/payload/calc-1.xml"; File file = new File(path); FileInputStream fis = null; try { fis = new FileInputStream(file); } catch (Exception e) { e.printStackTrace(); } BufferedInputStream bis = new BufferedInputStream(fis); XMLDecoder xmlDecoder = new XMLDecoder(bis); xmlDecoder.readObject(); xmlDecoder.close();