Giới Thiệu Về Lỗ Hổng .NET Deserialization
Bài viết này là phần thứ ba trong seri các bài viết về lỗ hổng .NET deserialization. Ở phần này, chúng ta sẽ tìm hiểu về tấn công .NET deserialization thông qua hai thành phần quan trọng: DataContractSerializer và DataContractJsonSerializer.
DataContractSerializer
DataContractSerializer là một công cụ mạnh mẽ trong .NET, cho phép chuyển đổi các đối tượng thành dạng stream hoặc tài liệu XML dựa trên một DataContract đã được xác định trước. Công cụ này thường được sử dụng trong các ứng dụng WCF (Windows Communication Foundation) để xử lý dữ liệu
Ví Dụ Về DataContractSerializer
Để sử dụng DataContractSerializer, trước tiên, bạn cần phải chỉ định kiểu dữ liệu bằng cách sử dụng thuộc tính DataContract trên lớp chính, và thuộc tính DataMember trên các thuộc tính mà bạn muốn serialize.
csharp
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
namespace DataContractDeserialize
{
[DataContract(Name = "Customer", Namespace = "http://www.contoso.com")]
class Person
{
[DataMember()]
public string FirstName;
[DataMember]
public string LastName;
[DataMember()]
public int Age;
public Person(string newfName, string newLName, int age)
{
FirstName = newfName;
LastName = newLName;
Age = age;
}
}
class Program
{
static void Main(string[] args)
{
try
{
WriteObject("DataContractSerializerExample.xml");
ReadObject("DataContractSerializerExample.xml");
}
catch (SerializationException serExc)
{
Console.WriteLine("Serialization Failed");
Console.WriteLine(serExc.Message);
}
catch (Exception exc)
{
Console.WriteLine("The serialization operation failed: {0} StackTrace: {1}," , exc.Message, exc.StackTrace);
}
finally
{
Console.WriteLine("Press <Enter> to exit....");
Console.ReadLine();
}
}
public static void WriteObject(string fileName)
{
Console.WriteLine("Creating a Person object and serializing it.");
Person p1 = new Person("bill", "gates", 100);
FileStream writer = new FileStream(fileName, FileMode.Create);
DataContractSerializer ser = new DataContractSerializer(typeof(Person));
ser.WriteObject(writer, p1);
writer.Close();
}
public static void ReadObject(string fileName)
{
Console.WriteLine("Deserializing an instance of the object.");
FileStream fs = new FileStream(fileName, FileMode.Open);
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
DataContractSerializer ser = new DataContractSerializer(typeof(Person));
Person deserializedPerson = (Person)ser.ReadObject(reader, true);
reader.Close();
fs.Close();
Console.WriteLine(String.Format("{0} {1}, Age: {2}", deserializedPerson.FirstName, deserializedPerson.LastName, deserializedPerson.Age));
}
}
}
Khi chạy đoạn mã trên, file XML tạo ra có nội dung như sau:
xml
<Customer xmlns="http://www.contoso.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Age>100</Age>
<FirstName>bill</FirstName>
<LastName>gates</LastName>
</Customer>
Điều Kiện Để Trigger RCE (Remote Code Execution)
- Kiểu dữ liệu object phải được truyền vào constructor của DataContractSerializer.
- Object cần deserialized phải chứa property kiểu object (để chèn gadget).
- Các kiểu dữ liệu gadget phải nằm trong KnownType hoặc DataContractResolver có phương thức ResolveName.
Thực Hiện Áp Dụng RCE với Gadget
Ví dụ về gadget được sử dụng cho việc khai thác RCE:
csharp
using System;
using System.IO;
using System.Runtime.Serialization;
namespace DataContractDeserialize
{
[Serializable]
public class RCE
{
private string _cmd;
public string cmd
{
get { return _cmd; }
set { _cmd = value; Run(); }
}
private void Run()
{
if (!string.IsNullOrEmpty(_cmd))
{
System.Diagnostics.Process.Start(_cmd);
}
}
}
}
DataContractJsonSerializer
Ngoài DataContractSerializer, DataContractJsonSerializer cũng cho phép chúng ta chuyển đổi giữa các đối tượng và định dạng JSON. Tương tự như cách mà DataContractSerializer thực hiện, DataContractJsonSerializer yêu cầu các lớp được serializable phải có thuộc tính DataContract và các thuộc tính cần serializable phải có thuộc tính DataMember.
csharp
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
namespace DataContractJsonDeserializer
{
[DataContract]
class Person
{
[DataMember]
internal string name;
[DataMember]
internal int age;
}
}
Điều Kiện Để Trigger RCE Với DataContractJsonSerializer
- Kiểu dữ liệu phải được biết trong knownTypes.
- Có thể sử dụng IDataContractSurrogate để kiểm soát việc serialization cho các lớp không được đánh dấu với DataContract.
Kết Luận
Lỗ hổng .NET deserialization cung cấp một cơ hội cho kẻ tấn công thực hiện Remote Code Execution nếu các ứng dụng không được cấu hình an toàn. Việc hiểu rõ về DataContractSerializer và DataContractJsonSerializer là rất quan trọng trong việc bảo vệ ứng dụng của bạn.
Hãy theo dõi các bài viết tiếp theo trong seri này để tìm hiểu thêm về các kỹ thuật khai thác lỗ hổng trong .NET.
source: viblo