Insecure Deserialization

Insecure Deserialization in Java

Vulnerability: Insecure Deserialization

Vulnerable Code:

javaCopy codeObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.ser"));
Object obj = ois.readObject();

Reason for vulnerability: Deserializing untrusted data can lead to remote code execution or other security issues.

Fixed Code:

javaCopy codeObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.ser")) {
    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
        if (!allowedClasses.contains(desc.getName())) {
            throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
        }
        return super.resolveClass(desc);
    }
};
Object obj = ois.readObject();

Reason for fix: Restricting the classes that can be deserialized prevents malicious code execution.


Insecure Deserialization in Python

Vulnerability: Insecure Deserialization

Vulnerable Code:

pythonCopy codeimport pickle

data = pickle.loads(request.data)

Reason for vulnerability: Deserializing untrusted data with pickle can lead to arbitrary code execution.

Fixed Code:

pythonCopy codeimport json

data = json.loads(request.data)

Reason for fix: Using json for deserialization instead of pickle prevents arbitrary code execution since json only handles basic data types.


Example 2: Python

Vulnerable Code:

pythonCopy codeobj = pickle.load(open('file.pkl', 'rb'))

Reason for vulnerability: Deserializing untrusted data, leading to insecure deserialization.

Fixed Code:

pythonCopy codeclass SafeUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module == "allowed.module" and name == "AllowedClass":
            return super().find_class(module, name)
        raise pickle.UnpicklingError("Unauthorized deserialization attempt")

obj = SafeUnpickler(open('file.pkl', 'rb')).load()

Reason for fix: Restrict the classes that can be deserialized.


Java Example

Vulnerable Code:

javaCopyimport java.io.*;

public class UserDeserializer {
    public static User deserializeUser(String serializedUser) {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(Base64.getDecoder().decode(serializedUser));
             ObjectInputStream ois = new ObjectInputStream(bis)) {
            return (User) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

Reason for Vulnerability:

This code blindly deserializes user-provided data, which can lead to remote code execution if the User class or any of its members are not designed securely.

Fixed Code:

javaCopyimport com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;

public class UserDeserializer {
    private static final ObjectMapper mapper = JsonMapper.builder()
            .activateDefaultTyping(null, ObjectMapper.DefaultTyping.NON_FINAL)
            .build();

    public static User deserializeUser(String serializedUser) {
        try {
            return mapper.readValue(serializedUser, User.class);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

Reason for Fix:

The fixed code uses Jackson for JSON deserialization instead of Java's built-in serialization. This approach is generally safer and allows for fine-grained control over deserialization behavior.

Java Example

Vulnerable Code:

javaCopyimport org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

public class CommandExecutor {
    public static void executeCommand(String command) {
        InvokerTransformer transformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{command});
        Map<String, String> map = new HashMap<String, String>();
        map.put("key", "value");
        Map<String, String> transformedMap = TransformedMap.decorate(map, null, transformer);
        // Use transformedMap...
    }
}

Reason for Vulnerability:

This code uses Apache Commons Collections' TransformedMap with InvokerTransformer, which can be exploited in deserialization attacks to execute arbitrary commands.

Fixed Code:

javaCopyimport java.util.HashMap;
import java.util.Map;

public class CommandExecutor {
    public static void executeCommand(String command) {
        // Validate and sanitize the command
        if (!isValidCommand(command)) {
            throw new IllegalArgumentException("Invalid command");
        }
        // Execute the command safely
        ProcessBuilder processBuilder = new ProcessBuilder(command.split("\\s+"));
        processBuilder.start();
    }

    private static boolean isValidCommand(String command) {
        // Implement command validation logic
        return command.matches("^[a-zA-Z0-9\\s-]+$");
    }
}

Reason for Fix:

The fixed code removes the use of potentially dangerous Apache Commons Collections classes and implements a safer way to execute commands with proper validation.

Python Example

Vulnerable Code:

pythonCopyimport pickle
import base64

def process_data(encoded_data):
    data = base64.b64decode(encoded_data)
    return pickle.loads(data)

Reason for Vulnerability:

This code uses Python's pickle module to deserialize data, which can lead to arbitrary code execution if an attacker controls the serialized data.

Fixed Code:

pythonCopyimport json
import base64

def process_data(encoded_data):
    data = base64.b64decode(encoded_data)
    return json.loads(data)

Reason for Fix:

The fixed code uses JSON for deserialization instead of pickle. JSON is a data-only format and doesn't allow for code execution, making it a safer choice for deserializing untrusted data.

Last updated