I tried the following experiment (this is just a pseudocode):
class Server {
public static void main(final String args[]) {
final ServerSocket server = new ServerSocket(PORT);
final Socket client = server.accept();
final ObjectInputStream stream = new ObjectInputStream(client.getInputStream());
final Object object = stream.readObject();
// Can we hope that standard toString method will be called?
System.out.println(object.toString());
}
}
then created a malicious object:
class MaliciousObject extends Object implements Serializable {
private static final long serialVersionUID = 1L;
@Override
public String toString() {
return "I am malicious object";
}
}
and finally sent an instance of malicious object to the sever using another program:
public static void main(final String args[]) {
final Socket socket = new Socket();
socket.connect(serversAddress, TIMEOUT);
final ObjectOutputStream stream = new ObjectOutputStream(socket.getOutputStream());
stream.writeObject(new MaliciousObject());
}
The output that Server printed to the screen was
I am malicious object
So it seems that a hacker can implement a class extending object, override any method M to execute some malicious code, then send this object over the network in a hope that server will call M.
Hence, my question is: how to defend against this? If we read objects from ObjectInputStream, how can we be sure that they're not malformed?
As a side question, is in this case Java class loader involved when reading objects from ObjectInputStream?