이 게시물은 ObjectDataProvider 가젯이 어떻게 악용되는지 이해하기 위해 작성되었습니다. RCE를 얻기 위해 Json.Net 및 xmlSerializer와 함께 이 가젯이 어떻게 남용될 수 있는지 설명합니다.
ObjectDataProvider 가젯
문서에서: ObjectDataProvider 클래스는 바인딩 소스로 사용할 수 있는 객체를 래핑하고 생성합니다.
네, 이상한 설명이니 이 클래스가 왜 흥미로운지 살펴보겠습니다: 이 클래스는 임의의 객체를 래핑하고, _MethodParameters_를 사용하여 임의의 매개변수를 설정한 다음, MethodName을 사용하여 임의의 객체의 임의의 함수를 호출할 수 있게 해줍니다.
따라서 임의의 객체는 역직렬화되는 동안 매개변수와 함께함수를 실행합니다.
이게 어떻게 가능할까요
System.Windows.Data 네임스페이스는 C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF의 PresentationFramework.dll 내에 정의되고 구현되어 있습니다.
dnSpy를 사용하여 우리가 관심 있는 클래스의 코드를 검사할 수 있습니다. 아래 이미지에서 PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name의 코드를 보고 있습니다.
MethodName이 설정되면 base.Refresh()가 호출되는 것을 볼 수 있습니다. 이게 무엇을 하는지 살펴보겠습니다:
좋습니다, this.BeginQuery()가 무엇을 하는지 계속 살펴보겠습니다. BeginQuery는 ObjectDataProvider에 의해 재정의되며, 다음과 같은 작업을 수행합니다:
코드 끝부분에서 this.QueryWorke(null)를 호출하는 것을 주목하세요. 이것이 무엇을 실행하는지 살펴보겠습니다:
이것은 QueryWorker 함수의 전체 코드는 아니지만, 흥미로운 부분을 보여줍니다: 코드 this.InvokeMethodOnInstance(out ex);를 호출합니다. 이 줄이 메서드 세트가 호출되는 부분입니다.
단순히 MethodName**을 설정하는 것만으로도 실행될 것임을 확인하고 싶다면, 이 코드를 실행할 수 있습니다:
using System.Windows.Data;using System.Diagnostics;namespace ODPCustomSerialExample{classProgram{staticvoidMain(string[] args){ObjectDataProvider myODP =newObjectDataProvider();myODP.ObjectType=typeof(Process);myODP.MethodParameters.Add("cmd.exe");myODP.MethodParameters.Add("/c calc.exe");myODP.MethodName="Start";}}}
Note that you need to add as reference C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll in order to load System.Windows.Data
ExpandedWrapper
이전의 익스플로잇을 사용하면 객체가 ObjectDataProvider 인스턴스로 역직렬화될 경우가 있습니다(예: DotNetNuke 취약점에서 XmlSerializer를 사용하여 객체가 GetType을 사용하여 역직렬화됨). 그러면 ObjectDataProvider 인스턴스에 포장된 객체 유형에 대한 지식이 없습니다(예: Process). 여기에서 DotNetNuke 취약점에 대한 더 많은 정보를 찾을 수 있습니다.
이 클래스는 주어진 인스턴스에 캡슐화된 객체의 객체 유형을 지정할 수 있게 해줍니다. 따라서 이 클래스는 소스 객체(ObjectDataProvider)를 새로운 객체 유형으로 캡슐화하고 우리가 필요한 속성(ObjectDataProvider.MethodName 및 ObjectDataProvider.MethodParameters)을 제공하는 데 사용할 수 있습니다.
이는 앞서 제시된 경우와 같은 경우에 매우 유용합니다. 왜냐하면 우리는 _ObjectDataProvider**를 **ExpandedWrapper _ 인스턴스 안에 포장할 수 있고 역직렬화될 때 이 클래스는 OjectDataProvider 객체를 생성하여 _MethodName_에 지정된 함수를 실행할 것입니다.
다음 코드를 사용하여 이 래퍼를 확인할 수 있습니다:
using System.Windows.Data;using System.Diagnostics;using System.Data.Services.Internal;namespace ODPCustomSerialExample{classProgram{staticvoidMain(string[] args){ExpandedWrapper<Process,ObjectDataProvider> myExpWrap =newExpandedWrapper<Process,ObjectDataProvider>();myExpWrap.ProjectedProperty0=newObjectDataProvider();myExpWrap.ProjectedProperty0.ObjectInstance=newProcess();myExpWrap.ProjectedProperty0.MethodParameters.Add("cmd.exe");myExpWrap.ProjectedProperty0.MethodParameters.Add("/c calc.exe");myExpWrap.ProjectedProperty0.MethodName="Start";}}}
Json.Net
공식 웹 페이지에서는 이 라이브러리가 Json.NET의 강력한 JSON 직렬 변환기를 사용하여 모든 .NET 객체를 직렬화 및 역직렬화할 수 있도록 한다고 명시되어 있습니다. 따라서 ObjectDataProvider 가젯을 역직렬화할 수 있다면, 객체를 역직렬화하는 것만으로도 RCE를 유발할 수 있습니다.
Json.Net 예제
우선 이 라이브러리를 사용하여 객체를 직렬화/역직렬화하는 방법에 대한 예제를 살펴보겠습니다: