이 POST에서는 java.io.Serializable을 사용하는 예제를 설명할 것입니다.
Serializable
Java Serializable 인터페이스(java.io.Serializable는 클래스가 직렬화 및 역직렬화되기 위해 구현해야 하는 마커 인터페이스입니다. Java 객체 직렬화(쓰기)는 ObjectOutputStream으로 수행되며, 역직렬화(읽기)는 ObjectInputStream으로 수행됩니다.
직렬화 가능한Person 클래스의 예를 살펴보겠습니다. 이 클래스는 readObject 함수를 오버라이드하므로, 이 클래스의 어떤 객체가 역직렬화될 때 이 함수가 실행됩니다.
예제에서 Person 클래스의 readObject 함수는 그의 애완동물의 eat() 함수를 호출하고, Dog의 eat() 함수는 (어떤 이유로) calc.exe를 호출합니다. 이 계산기를 실행하기 위해 Person 객체를 직렬화하고 역직렬화하는 방법을 살펴보겠습니다:
importjava.io.Serializable;importjava.io.*;publicclassTestDeserialization {interfaceAnimal {publicvoideat();}//Class must implements Serializable to be serializablepublicstaticclassCatimplementsAnimal,Serializable {@Overridepublicvoideat() {System.out.println("cat eat fish");}}//Class must implements Serializable to be serializablepublicstaticclassDogimplementsAnimal,Serializable {@Overridepublicvoideat() {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {e.printStackTrace();}System.out.println("dog eat bone");}}//Class must implements Serializable to be serializablepublicstaticclassPersonimplementsSerializable {privateAnimal pet;publicPerson(Animal pet){this.pet= pet;}//readObject implementation, will call the readObject from ObjectInputStream and then call pet.eat()privatevoidreadObject(java.io.ObjectInputStream stream)throwsIOException,ClassNotFoundException {pet = (Animal) stream.readObject();pet.eat();}}publicstaticvoidGeneratePayload(Object instance,String file)throwsException {//Serialize the constructed payload and write it to the fileFile f =newFile(file);ObjectOutputStream out =newObjectOutputStream(new FileOutputStream(f));out.writeObject(instance);out.flush();out.close();}publicstaticvoidpayloadTest(String file) throwsException {//Read the written payload and deserialize itObjectInputStream in =newObjectInputStream(new FileInputStream(file));Object obj =in.readObject();System.out.println(obj);in.close();}publicstaticvoidmain(String[] args) throwsException {// Example to call Person with a DogAnimal animal =newDog();Person person =newPerson(animal);GeneratePayload(person,"test.ser");payloadTest("test.ser");// Example to call Person with a Cat//Animal animal = new Cat();//Person person = new Person(animal);//GeneratePayload(person,"test.ser");//payloadTest("test.ser");}}
결론
이 매우 기본적인 예에서 볼 수 있듯이, 여기서 "취약점"은 readObject 함수가 다른 취약한 함수들을 호출하기 때문에 발생합니다.