
Análisis detallado y exploit de prueba de concepto para CVE-2017-9822, una vulnerabilidad de XXE/deserialización insegura en DotNetNuke CMS que conduce a la ejecución remota de código mediante la manipulación de cookies.
DotNetNuke (a menudo abreviado como DNN) es una plataforma CMS (Content Management System) y framework de aplicaciones web basado en la tecnología ASP.NET de Microsoft.
Producto afectado: DotNetNuke (DNN Platform) – un CMS/portal .NET popular.
Fecha de divulgación: Julio de 2017.
Gravedad: Critical (CVSS ~9.8).
Tipo de vulnerabilidad: XML External Entity (XXE) / Deserialización insegura → Remote Code Execution (RCE).
Impacto: antes de la versión 9.1.1, es posible ejecutar código de forma remota a través de la cookie
Aquí estoy usando Windows 10 para configurar y depurar el programa. La versión que estoy instalando es 9.1.0; puedes consultar cómo instalarlo aquí. Y el resultado al terminar es:


Según los informes que he leído, esta vulnerabilidad se encuentra en el manejo de la cookie de DotNetNuke.
DNN utiliza un método de deserialización inseguro (unsafe deserialization) para la cookie DNNPersonalization.

.dll o .exe escritos en .NET. Puedes instalarlo aquí. Necesitamos descargar 2 versiones para llevar a cabo la depuración.
DotNetNuke.dll con la versión de 32 bits y selecciona Edit Assembly Attributes (C#).
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]

Después guárdalo.
Attach to Process.
w3wp.exe.
La razón para elegir w3wp.exe es:
w3wp.exe = IIS Worker Process.
Es el proceso de ejecución del Application Pool en IIS.
Cuando llega una solicitud HTTP al sitio web, IIS crea o reutiliza un w3wp.exe para procesarla (ejecutar código ASP.NET, manejar módulos, middleware, conexiones de base de datos...).
Cada Application Pool puede tener uno o varios procesos w3wp.exe según la configuración (web garden, reciclaje).
A continuación, ve a Debug -> Window -> Modules.

Cuando aparezcan los módulos, haz clic derecho en cualquiera de ellos y selecciona Open All Modules.

Y al final aparecerán todos los ensamblados relacionados con DNN.

DotNetNuke.dll -> PersonalizationController#LoadProfile(int, int).
Esta función se usa para cargar los datos de personalización (perfil) del usuario en el portal DNN.
Si el usuario ha iniciado sesión → obtiene el perfil de la base de datos + caché.
Si es un usuario anónimo (sin iniciar sesión) → obtiene el perfil de la cookie DNNPersonalization.
Aquí debemos centrarnos en DNNPersonalization.
Si userId no es válido (usuario anónimo).
Comprueba si la solicitud contiene la cookie DNNPersonalization.
Si la tiene → toma el valor XML de esa cookie.
Enviaremos una solicitud 404 al sitio web con cualquier DNNPersonalization y usaremos dnSpy para establecer un breakpoint en DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int); así podremos depurarlo.


PortalSettings.
Lo que llama la atención es que aquí se usa una condición if para comprobar si la solicitud actual ya está IsAuthenticated o no.
Y como la solicitud que enviamos es 404 -> unauthenticated.
Continuando con el Call Stack, nos centramos en Handle404OrException.

context.User de la solicitud actual es null; si es así, asigna context.User al usuario del hilo actual.

Podemos ver que en Handle404OrException la variable IsAuthenticated ahora tiene el valor true y el usuario es el del servidor IIS, por lo que la solicitud se procesa como un usuario autenticado.
La razón del problema está en este fragmento de código:
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);
}
Si context.User no existe → asigna Thread.CurrentPrincipal (es decir, la identidad actual del hilo).
Esto permite que la solicitud tenga la información de usuario/rol al continuar procesándose.
=> Cuando pasamos cualquier contenido a la cookie con la variable DNNPersonalization, se ejecutará como un usuario normal.
Seguimos en DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int).
Vemos que la variable text recibe el valor de la cookie y luego se usa como entrada para Globals.DeserializeHashTableXml().
