
DNN (noto anche come DotNetNuke), prima della versione 9.1.1, presenta una vulnerabilità di esecuzione remota di codice tramite cookie, nota anche come "2017-08 (Importante) Possibile esecuzione remota di codice sui siti web DNN".

Cos'è DotNetNuke?
DotNetNuke è un CMS (sistema di gestione dei contenuti) web gratuito e open source scritto in C# e basato sulla piattaforma .NET. DotNetNuke è molto popolare e ampiamente utilizzato su Internet perché è possibile distribuire una versione web di DNN in pochi minuti senza richiedere molte conoscenze tecniche. Un'altra importante funzionalità di DotNetNuke è la capacità di creare o importare moduli personalizzati di terze parti costruiti con VB.NET o C#
È possibile installare DNN su uno stack comprendente Windows Server, IIS, ASP.NET e SQL Server per Windows. DNN supporta anche la registrazione con verifica dei nuovi utenti tramite email, ma è necessario configurare un server SMTP valido affinché questa funzionalità di sicurezza funzioni.
Caratteristiche principali di DNN
• Architettura modulare: DNN consente un'estensione facile installando ulteriori moduli (moduli funzionali) sviluppati dalla community. Gli amministratori possono caricare nuovi moduli tramite l'interfaccia di amministrazione (upload dei pacchetti .zip) o decomprimerli direttamente in una cartella sul server.
• Gestione utenti: Il sistema fornisce funzionalità di sicurezza e di autorizzazione dettagliata (ruoli/autorizzazioni) per portali e moduli. Account utente, ruoli e permessi sono gestiti centralmente in DNN.
• Gestione dei contenuti: Supporta l'editor WYSIWYG, la gestione di articoli, immagini, documenti... Dispone di un sistema di workflow/pubblicazione (pubblicazione con flusso di approvazione) e versionamento dei contenuti. I contenuti vengono archiviati nel database (SQL Server) condiviso.
• API e integrazione estensibile: DNN fornisce API .NET per lo sviluppo di moduli personalizzati (WebForms, MVC, Razor) e l'integrazione di servizi esterni. Molte librerie di terze parti sono disponibili (temi, moduli e-commerce, forum, ecc.) per estendere le funzionalità.
• Interfaccia e temi: Il sistema di skin (temi) separa contenuti e interfaccia, consentendo una progettazione web flessibile. I siti web creati con DNN possono cambiare aspetto cambiando skin.
• Meccanismo di installazione dei moduli: I moduli DNN sono impacchettati in file ZIP e possono essere installati tramite l'interfaccia di amministrazione o tramite estrazione manuale. DNN supporta sia moduli compilati (.NET DLL) sia moduli Razor dinamici; ogni modulo può concedere o revocare l'accesso tramite le impostazioni di autorizzazione su ogni pagina.
Sistemi operativi: Windows 10
.NET Framework: 4.5.1+
Server web: Microsoft IIS 10
Server di database: Microsoft® SQL Server® 2019 Express, SQL Server Management Studio
Versione Dotnetnuke 9.1.0
È possibile utilizzare i seguenti Google dorks per trovare le versioni di Dotnetnuke distribuite disponibili su Internet e verificarle in base al sito web:
inurl:dnn.js
inurl:dnn.modalpopup.js
inurl:dnn.servicesframework.js
inurl:dnn.xml.js
inurl:dnncore.js
inurl:/Portals/0/
inurl:/DesktopModules/
inurl:/DNNCorp/
inurl:/DotNetNuke
inurl:/tabid//Default.aspx
inurl:/tabid//language/*/Default.aspx
intext:"by DNN Corp "
Puoi seguire questo articolo per costruire l'ambiente
Modifica gli attributi dell'assembly in attributi "debuggabili": questo è molto necessario perché in fase di runtime vengono applicate alcune ottimizzazioni che possono ostacolare il debug, alcuni breakpoint potrebbero non essere raggiunti o alcune variabili potrebbero non esistere.
Carica DotNetNuke.dll in dnSpy (32 bit), quindi seleziona Edit Assembly Attributes (C#)

Cambia la riga da
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
a
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]

Quindi seleziona Compile e salva nuovamente il modulo nella posizione originale.
Successivamente, avvia dnSpy come amministratore e seleziona Debug -> Attach to Process

Seleziona il processo w3wp.exe

Il motivo per cui dobbiamo agganciare questo processo per il debug è che le applicazioni web su IIS utilizzano solitamente i worker process. Essi hanno il compito di gestire le richieste web inviate al server web IIS per ogni application pool; i worker process possono essere molteplici su una stessa macchina e condividono tutti lo stesso nome, w3wp.exe. Una piccola nota: può capitare che non ci sia alcun processo w3wp in esecuzione; IIS non avvia i worker process finché non riceve la prima richiesta web.

Tornando al debug, dopo aver agganciato il processo, scegli: Debug -> Windows -> Modules

Fai clic su un modulo e seleziona Open All Modules

A questo punto, nella finestra Assembly si possono vedere tutti i moduli correlati

La deserializzazione è il processo di interpretazione dei flussi di byte e la loro conversione in dati che l'applicazione può eseguire.
Il problema principale della deserializzazione è che, per la maggior parte del tempo, può utilizzare dati di input forniti dall'utente. Ciò significa che è possibile inserire payload dannosi nel formato richiesto dall'applicazione e manipolare la logica, divulgare dati o persino eseguire codice in remoto.
DotNetNuke utilizza il cookie DNNPersonalization per memorizzare le preferenze di personalizzazione degli utenti anonimi (le preferenze per gli utenti autenticati vengono memorizzate tramite la loro pagina di profilo). Come riportato, la vulnerabilità si verifica nella gestione del cookie DNNPersonalization; questo cookie viene utilizzato per caricare il profilo utente, ma può comunque essere innescato senza autenticazione quando si accede a una pagina inesistente (errore 404). L'entry point di questo bug si trova nella funzione LoadProfile del modulo DotNetNuke.dll; decomplieremo questo modulo con dnSpy e lo analizzeremo più in dettaglio:
In PersonalizationController#LoadProfile(int, int)

Se userId è diverso da null, alla variabile text viene assegnato il valore del cookie DNNPersonalization dalla richiesta e successivamente viene chiamato Globals#DeserializeHashTableXml

Globals#DeserializeHashTableXml chiama XmlUtils#DeSerializeHashtable

Il processo di elaborazione è il seguente:
Usa Burp per inviare una richiesta che innesca lo stato 404 + il cookie DNNPersonalization

Qui si può vedere che la funzione chiamata per gestire il 404 è Handler404OrException, che ha innescato una call chain e ha chiamato Personalization.LoadProfile(int,int).

La cosa notevole nel codice sopra è una condizione if che controlla se la richiesta corrente è già autenticata (IsAuthenticated); chiaramente la richiesta appena effettuata era una richiesta non autenticata verso un entrypoint inesistente. Allora perché la richiesta corrente viene eseguita come utente autenticato?
Continuando il debug e tornando verso la fine dello stack, si vede che in AdvancedUrlRewriter#Handle404OrException c'è un ramo else if come segue:

Qui viene controllato se context.User della richiesta corrente è null; in tal caso, context.User viene impostato all'utente del thread corrente. Impostando un breakpoint si può vedere il risultato:

La variabile IsAuthenticated ora ha valore true e l'utente assegnato è proprio l'utente che esegue il thread corrente, appartenente al gruppo IIS APPPOOL del server IIS; pertanto la richiesta viene eseguita come utente autenticato. Il motivo per cui questa logica esiste è che il gestore 404 viene invocato prima che HttpContext.User venga impostato e il successivo flusso di elaborazione si basa su User.IsAuthenticated; quindi, per evitare errori di riferimenti null (Null references), gli sviluppatori assegnano all'oggetto User l'oggetto WindowsPrinicipal del thread corrente.
XmlSerializer è la classe di serializzazione proprietaria di Microsoft, utilizzata per convertire tra stringhe e oggetti XML. Il suo namespace è: System.Xml.Serialization.
Esempio di utilizzo di XmlSerializer:


La condizione per un attacco RCE tramite XmlSerializer è che sia obbligatorio controllare il tipo di dati passato al costruttore di XmlSerializer. In altre parole, i tipi di dati che portano al gadget devono essere passati nella proprietà XmlSerializer.mapping
Il gadget più comune per attaccare la deserializzazione XML è ObjectDataProvider. Questo gadget può essere creato utilizzando lo strumento ysoserrial .net
In pratica, usando questa classe, possiamo chiamare qualsiasi metodo di qualsiasi classe.

Ad esempio, possiamo chiamare Process.Start con i parametri passati come segue:
ObjectDataProvider o = new ObjectDataProvider(); o.MethodParameters.Add("cmd.exe"); o.MethodParameters.Add("/c calc"); o.MethodName = "Start"; o.ObjectInstance = new Process(); Console.ReadKey();
Costruiamo un payload di deserializzazione XML con il codice sopra:


ResourceDictionary viene utilizzato per lo sviluppo WPF; poiché si tratta di WPF, deve usare il linguaggio XAML. Per prima cosa, vediamo un payload che usa ResourceDictionary per eseguire comandi.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:b="clr-namespace:System;assembly=mscorlib" xmlns:c="clr-namespace:System.Diagnostics;assembly=system"> <ObjectDataProvider d:Key="" ObjectType="{d:Type c:Process}" MethodName="Start"> <ObjectDataProvider.MethodParameters> <b:String>cmd</b:String> <b:String>/c calc</b:String> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </ResourceDictionary>
Spiegazione di questo XAML:

L'esecuzione del codice sopra equivale a ObjectDataProvider -> Person.Evil(). Se si esegue un attacco RCE tramite XmlSerializer, il flusso apparirà così: ObjectDataProvider -> XamlReader.Parse() -> ObjectDataProvider -> System.Diagnostics.Process.Start("cmd.exe","/c calc")
L'obiettivo ora è trovare un oggetto che possa eseguire codice durante la deserializzazione. Nel POC, la funzione PullFile di DotNetNuke.Common.Utilities.FileSystemUtils viene utilizzata per sfruttare un "arbitrary file upload"


Otteniamo obj.xml:

Invia il payload


Dopo che DNN deserializza i cookie, sul server HTTP arriva una richiesta a /cmd.aspx, ovvero la deserializzazione è riuscita; la webshell è stata caricata su DN

Allo stesso modo, sfruttiamo la funzione WriteFile di DotNetNuke.Common.Utilities.FileSystemUtils per leggere file

