
CVE-2017-9822에 대한 상세 분석 및 개념 증명 익스플로잇. DotNetNuke CMS의 XXE/안전하지 않은 역직렬화 취약점으로, 쿠키 조작을 통해 원격 코드 실행으로 이어집니다.
DotNetNuke (일반적으로 DNN으로 약칭)은 마이크로소프트의 ASP.NET 기술을 기반으로 하는 CMS(Content Management System) 플랫폼이자 웹 애플리케이션 프레임워크입니다.
여기서는 Windows 10을 사용하여 프로그램을 설정하고 디버그합니다. 설치한 버전은 9.1.0이며, 설치 방법은 여기를 참조하세요. 완료 후 결과는 다음과 같습니다:



여기서는 dnSpy를 사용합니다. dnSpy는 .NET (C#, VB.NET, F#...) 애플리케이션을 위한 디컴파일러(역컴파일러) 및 디버거 도구입니다. 이를 사용하면 .NET으로 작성된 .dll 또는 .exe와 같은 컴파일된 파일에서 소스 코드를 보고, 분석하고, 편집할 수 있습니다. 여기에서 설치할 수 있습니다. 디버깅을 위해 두 가지 버전을 다운로드해야 합니다.

먼저 32비트 버전으로 DotNetNuke.dll을 열고 **Edit Assembly Attributes (C#)**을 선택합니다.

그런 다음 다음 줄을
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
다음으로 변경합니다.
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]

그런 다음 저장합니다.
64비트 버전을 관리자 권한으로 열고 Attach to Process를 선택합니다.

다음으로 w3wp.exe를 선택합니다.

w3wp.exe를 선택하는 이유는 다음과 같습니다:
w3wp.exe = IIS 작업자 프로세스.w3wp.exe를 생성하거나 재사용합니다 (ASP.NET 코드 실행, 모듈, 미들웨어, 데이터베이스 연결 처리 등).w3wp.exe 프로세스를 가질 수 있습니다.다음으로 Debug -> Window -> Modules를 선택합니다.

완료되면 Modules가 나타납니다. 아무 모듈이나 마우스 오른쪽 버튼으로 클릭하고 Open All Modules을 선택합니다.

그리고 마지막으로 DNN 관련 모든 어셈블리가 표시됩니다.

DotNetNuke.dll -> PersonalizationController#LoadProfile(int, int)로 이동합니다.

이 함수는 DNN 포털에서 사용자 프로필 데이터를 로드하는 데 사용됩니다.
DNNPersonalization**에서 프로필을 가져옵니다.여기서는 DNNPersonalization에 초점을 맞춰야 합니다.
userId가 유효하지 않은 경우 (익명 사용자).DNNPersonalization 쿠키가 있는지 확인합니다.웹사이트에 404 요청을 보내고 임의의 DNNPersonalization을 사용한 후, dnSpy를 사용하여 DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int)에 중단점을 설정하면 디버그할 수 있습니다.


Call Stack 부분에서는 PortalSettings 클래스 분석에 집중하겠습니다.

주목할 점은 여기서 if 조건을 사용하여 현재 요청이 이미 IsAuthenticated인지 확인한다는 것입니다.
그리고 우리가 보낸 요청은 404 -> unauthenticated입니다.
계속해서 Call Stack 부분에서 Handle404OrException에 집중합니다.

여기서는 현재 요청의 context.User가 null인지 확인하고, 그렇다면 context.User를 현재 스레드 사용자로 설정합니다.


Handle404OrException에서 IsAuthenticated 변수가 이제 true 값이고, 사용자는 IIS 서버의 사용자이므로 요청이 인증된 사용자로 실행됩니다.
문제의 원인은 다음 코드 조각에 있습니다.
else if (transfer)
{
if (context.User == null)
{
context.User = Thread.CurrentPrincipal;
}
response.TrySkipIisCustomErrors = true;
IHttpHandler handler = new CDefault();
context.Handler = handler;
server.Transfer("~/" + text, true);
}
context.User가 없으면 → Thread.CurrentPrincipal(현재 스레드의 ID)을 할당합니다.=> DNNPersonalization 변수로 쿠키에 어떤 내용이든 전달하면 일반 사용자처럼 처리됩니다.
여전히 DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int)에 있습니다.
text 변수가 쿠키 값에서 값을 가져온 다음 Globals.DeserializeHashTableXml()의 입력으로 전달되는 것을 볼 수 있습니다.

Globals.DeserializeHashTableXml()로 들어갑니다.

DeserializeHashTableXml 함수의 역할:
Source)을 입력으로 받습니다.Hashtable 객체로 변환합니다."profile" 매개변수를 사용하여 XML 루트 노드를 지정하는 XmlUtils.DeSerializeHashtable 함수를 호출합니다.XmlUtils.DeSerializeHashtable 내부로 들어가면 처리 방식을 확인할 수 있습니다.

DeSerializeHashtable 함수는 XML 문자열을 입력받아 Hashtable로 변환합니다. 각 <item> 노드에 대해 함수는:
key를 키로 가져옵니다.type을 가져온 다음 Type.GetType(type)을 호출하여 데이터 형식을 결정합니다.XmlSerializer.Deserialize**를 사용하여 XML 내용을 실제 객체로 변환합니다.Hashtable에 추가합니다.👉 문제: type과 XML 내용이 완전히 사용자에 의해 제어되기 때문입니다 (DNNPersonalization 쿠키에서).
XmlUtils#DeSerializeHashtable이 취약점 위치임을 기반으로 객체를 직렬화 및 역직렬화하는 유사한 프로그램을 생성합니다:
using System.Xml;
using System.Diagnostics;
using System.Xml.Serialization;
namespace example
{
public class Test
{
private string _name;
public string name
{
get { return _name; }
set { this._name = value; execCMD(); }
}
private void execCMD()
{
Process process = new Process();
process.StartInfo.FileName = this._name;
process.Start();
process.Dispose(); // close
}
}