Java反序列化-WebGoat
源项目:webgoat-server-8.2.2(https://github.com/WebGoat/WebGoat/releases)
Jdk:>=15(11不行)
启动命令:
1
| java -jar webgoat-server-8.2.2.jar
|
http://127.0.0.1:8080/WebGoat/login

题目java文件:webgoat-server-8.2.2.jar 解包,webgoat-server-8.2.2/BOOT-INF/lib/insecure-deserialization-8.2.2.jar再次解包,org/org.owasp.webgoat.deserialization下的文件
分析源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| package org.owasp.webgoat.deserialization;
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InvalidClassException; import java.io.ObjectInputStream; import java.util.Base64; import org.dummy.insecure.framework.VulnerableTaskHolder; import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentHints; import org.owasp.webgoat.assignments.AttackResult; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController;
@RestController @AssignmentHints({"insecure-deserialization.hints.1", "insecure-deserialization.hints.2", "insecure-deserialization.hints.3"}) public class InsecureDeserializationTask extends AssignmentEndpoint { public InsecureDeserializationTask() { }
@PostMapping({"/InsecureDeserialization/task"}) @ResponseBody public AttackResult completed(@RequestParam String token) throws IOException { String b64token = token.replace('-', '+').replace('_', '/');
long before; long after; try { label71: { ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(b64token)));
AttackResult var10; label64: { label63: { try { before = System.currentTimeMillis(); Object o = ois.readObject(); if (!(o instanceof VulnerableTaskHolder)) { if (o instanceof String) { var10 = this.failed(this).feedback("insecure-deserialization.stringobject").build(); break label64; }
var10 = this.failed(this).feedback("insecure-deserialization.wrongobject").build(); break label63; }
after = System.currentTimeMillis(); } catch (Throwable var12) { try { ois.close(); } catch (Throwable var11) { var12.addSuppressed(var11); }
throw var12; }
ois.close(); break label71; }
ois.close(); return var10; }
ois.close(); return var10; } } catch (InvalidClassException var13) { return this.failed(this).feedback("insecure-deserialization.invalidversion").build(); } catch (IllegalArgumentException var14) { return this.failed(this).feedback("insecure-deserialization.expired").build(); } catch (Exception var15) { return this.failed(this).feedback("insecure-deserialization.invalidversion").build(); }
int delay = (int)(after - before); if (delay > 7000) { return this.failed(this).build(); } else { return delay < 3000 ? this.failed(this).build() : this.success(this).build(); } } }
|
Read More
Java反序列化原理
Serializable 接口的使用
类需要被序列化和反序列化,需要实现接口 java.io.Serializable
Java 提供的序列化接口 Serializable ,是一个空接口,没有成员方法和变量
1 2
| public interface Serializable { }
|
1 2 3 4 5 6
| import java.io.Serializable;
public class Example implements Serializable{ private String name; .... }
|
序列化 调用 ObjectOutputStream
类的 writeObject
方法
反序列化 调用 ObjectInputStream
类的 readObject
方法
注意:
只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列,否则会抛出异常。Externalizable 接口继承自Serializable接口,实现 Externalizable接口的类完全由自身来控制序列化的行为,而仅实现 Serializable 接口的类可以采用默认的序列化方式。
- 它是Java 提供的序列化接口,是一个空接口,没有成员方法和变量
- 一个类要想序列化就必须继承java.io.Serializable接口,同时它的子类也可以序列化(不用再继承Serializable接口)
- 一个实现Serializable 接口的子类也是可以被序列化的。在反序列化过程中,它的父类如果没有实现序列化接口,那么父类将需要提供无参构造函数来重新创建对象,这样做的目的是重新初始化父类的属性,父类对应的属性不会被序列化
- 序列化只能保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量,而且序列化保存的只是变量的值,对于变量的任何修饰符都不能保存。即序列化是保存对象的状态(对象属性)
- transient 标识的对象成员变量不参与序列化
- Serializable 在序列化和反序列化过程中大量使用了反射,因此其过程会产生的大量的内存碎片
注:JAVA会被称为八股文,原因在于它的一个小知识点里会有很多细节在里面
Person
Read More