
Este é um exploit para CVE-2017-7047, funciona no 10.3.2 e versões anteriores.
triple_fetch - ianbeer [https://bugs.chromium.org/p/project-zero/issues/detail?id=1247]
Este é um exploit para o CVE-2017-7047, um erro de lógica no libxpc que permitia que remetentes maliciosos de mensagens enviassem objetos xpc_data baseados em memória compartilhada. Os consumidores de mensagens xpc não pareciam esperar que os buffers de apoio dos objetos xpc_data pudessem ser modificados pelo remetente enquanto estavam sendo processados pelo destinatário.
Este projeto explora o CVE-2017-7047 para construir um stub remoto de prova de conceito do debugserver do lldb, capaz de se anexar a e permitir a depuração remota de todos os processos de espaço de usuário no iOS.
Esta é uma visão geral de alto nível do exploit; um artigo detalhado pode ser publicado posteriormente. Por enquanto, consulte o código para mais detalhes :)
Parte I
O exploit tem como alvo o NSXPC, uma implementação de chamada de procedimento remoto (RPC) em Objective-C usada por muitos serviços do iOS (1). Uma mensagem NSXPC consiste em um objeto serializado bplist16 dentro de um objeto xpc_data serializado via XPC, dentro de uma mensagem mach.
Entre outras coisas, o objeto bplist16 contém uma string de codificação de tipo Objective-C (2) que será analisada pela função ___NSMS1 na CoreFoundation. Esta função não espera que o conteúdo da string que está analisando mude, e este exploit usa isso para construir uma primitiva de estouro de heap, explorando o fato de que uma determinada parte da string será buscada da memória três vezes. Ao alternar entre três valores diferentes, cuidadosamente escolhidos, conseguimos estourar um tamanho de alocação de heap escolhido com bytes arbitrários.
O arquivo minibplist16.c contém uma implementação mínima da serialização bplist e uma discussão sobre como ela funciona.
A mensagem xpc externa contém o heap groom. Ela usa uma implementação personalizada do protocolo de serialização XPC para preparar o heap, criando dicionários xpc com chaves em colisão para construir primitivas de alocação e liberação. A mensagem xpc externa também contém um heap spray (usando múltiplas cópias de um objeto de memória compartilhada para manter o uso de memória baixo) e um spray de nomes de direitos de envio de portas mach.
O overflow aponta o ponteiro isa de classe de um objeto Objective-C para um objeto falso pulverizado no heap, de modo que, quando um método é chamado nesse objeto falso, a pilha é pivoteada para uma pequena stack ROP. O ROP faz força bruta através dos nomes de direitos de envio de porta mach pulverizados, tentando enviar o direito de envio do alvo para sua própria porta de tarefa para cada um dos nomes de direitos de envio pulverizados candidatos. O exploit escuta em todas as portas pulverizadas e, se for bem-sucedido, recebe um direito de envio para a porta de tarefa do alvo, momento em que tem controle total sobre a tarefa alvo.
Interlúdio
O exploit tem como alvo o serviço com.apple.CoreAuthentication.daemon hospedado pelo daemon coreauthd, que roda como root. Esse serviço pode ser alcançado a partir do sandbox do app. Um pouco de experimentação depois que eu inicialmente fiz o exploit funcionar revelou que, a partir do contexto do coreauthd, a API processor_set_tasks é capaz de obter direitos de envio para as portas de tarefa de todos os processos de espaço de usuário em execução no dispositivo. Isso é de conhecimento público desde pelo menos 2012, e a história é abordada em profundidade pelo proeminente pesquisador de internals do iOS, Jonathan Levin, em seu site (3). O código que Levin enviou em 2015 ainda funciona hoje — não requer um dispositivo com jailbreak, apenas root em um dispositivo de estoque.
Parte II
O objetivo principal do depurador que eu queria construir com este exploit era poder anexar a um processo arbitrário, definir breakpoints e inspecionar e alterar o estado de registradores e memória quando eles fossem atingidos. Em vez de implementar o protocolo remoto gdb ou lldb do zero, decidi fazer as alterações necessárias no projeto debugserver do lldb e então usar o exploit para executá-lo.
Em vez de usar breakpoints de software, que exigem desabilitar ou burlar a assinatura de código, o debugserver é modificado para usar exclusivamente breakpoints de hardware. A ARM64 tem 16 registradores de breakpoint de hardware, o que significa que você só pode ter no máximo 16 breakpoints ativos.
O suporte protótipo para breakpoints de hardware ARM existia no código do debugserver do lldb, mas exigia alguns ajustes para funcionar. Por exemplo, tive que adicionar código que corrige o ponteiro de função pthread_introspection_hook no debugee para sempre travar, de modo que eu pudesse detectar a criação de novas threads e propagar o estado dos breakpoints de hardware para as threads recém-criadas e continuar como se nunca tivesse travado.
Também modifiquei o código de attach e continue para suspender e retomar a tarefa diretamente via porta de tarefa, em vez de usar ptrace e sinais.
Dicas de compilação
Tudo deve funcionar em todos os dispositivos iOS rodando de 10.0 a 10.3.2 inclusive. Testei em:
iPhone 7 + 10.3.2 iPod Touch + 10.1.1 iPad Mini 2 + 10.2
Incluí um binário debugserver pré-compilado que sugiro que você use, mas o patch para o debugserver do lldb também está incluído em debugserver.diff.
Compilar o debugserver não é muito difícil. Eu estava trabalhando com as seguintes revisões do git: lldb: 0db640c4cd1ec4e4c2580336fa5f53be029c5bc7 llvm: ec48fd127774a4b67c72ea7c3057b5c964375e77 clang: b6e778e0bfa2fc32f8821c6b33762f5cb6724659
aplique o debugserver.diff fornecido.
Para a compilação, você precisa de cmake e ninja (recentes). Você pode obtê-los a partir do código-fonte ou de binários do seu gerenciador de pacotes Mac favorito.
(4) tem um guia de como configurar uma compilação normal do llvm no MacOS, que pode ser útil.
Você precisará criar symlinks de vários arquivos de cabeçalho no seu SDK do iOS, pelo menos:
xpc/ launchd.h libproc.h sys/proc_info.h sys/kern_control.h net/route.h mach/mach_vm.h mach/shared_region.h sys/ptrace.h crt_externs.h
a seguinte invocação do cmake deve lhe dar todas as dicas de que você precisa:
cmake -G "Ninja" -DCMAKE_OSX_ARCHITECTURES="armv7;armv7s;arm64" -DCMAKE_TOOLCHAIN_FILE=../cmake/platforms/iOS.cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_RUNTIME=Off -DLLVM_INCLUDE_TESTS=Off -DLLVM_INCLUDE_EXAMPLES=Off -DLLVM_ENABLE_BACKTRACES=Off ../
ninja debugserver
Em seguida, você precisará assinar ou falsificar a assinatura do binário debugserver e substituir o que está no projeto xcode fornecido.
Assinatura de código
O projeto do exploit, por padrão, instalará uma versão melhorada do hook amfid do mach_portal (desta vez com suporte funcional para arquivos fat e sem offsets fixos no código :) )
Se você só quiser depurar coisas, deve ser capaz de assinar o binário debugserver com seu próprio certificado e desabilitar o hook amfid.
Se você usar o hook amfid, lembre-se de que o app em que ele está rodando ainda está sujeito aos limites de execução de código em segundo plano. O app solicita mais tempo via beginBackgroundTaskWithName.
Uso:
Conecte seu host e o iDevice alvo à mesma rede sem fio e anote o endereço IP do iDevice.
Compile e execute o app do exploit. Recomendo fazer isso dentro do xcode, mas funcionará de forma autônoma.
Espere um pouco. Se não funcionar depois de alguns minutos, reinicie o dispositivo de forma forçada, espere um pouco e tente novamente.
Se funcionar, deve imprimir “patched debugserver listening on port 1234”
Se você clicar no botão “get process listing”, deverá ver a saída do ps
(é mais fácil ver a saída se você usar o xcode, mas o exploit também mostrará a saída)
Procure o processo alvo em que você está interessado em depurar e anote o pid dele.
no host, inicie o lldb a partir da linha de comando: $ lldb (lldb)
defina a plataforma como ios remote: (lldb) platform select remote-ios
conecte-se ao stub do debugserver: (lldb) process connect connect://192.168.0.172:1234
(onde 192.168.0.172 é o endereço IP do iDevice)
anexe-se ao processo em que você está interessado: (lldb) attach 55
...espere um pouco, o debugserver está rodando em modo verboso...
Process 55 stopped
Executable module set to "/usr/libexec/backboardd".
você está anexado :)
defina um breakpoint: (lldb) break set --name malloc Breakpoint 1: 4 locations.
continuar:
(lldb) c Process 55 resuming Process 55 stopped
malloc libsystem_malloc.dylibmalloc:
-> 0x1936161e0 <+0>: stp x20, x19, [sp, #-0x20]!
0x1936161e4 <+4>: stp x29, x30, [sp, #0x10]
0x1936161e8 <+8>: add x29, sp, #0x10 ; =0x10obtenha um backtrace:
(lldb) bt
malloc frame #1: 0x0000000100099648 backboardd_mh_execute_header + 71240
frame #2: 0x00000001945bf218 CoreFoundation__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56 frame #3: 0x00000001945be9cc CoreFoundation__CFRunLoopDoSource1 + 436
frame #4: 0x00000001945bc4b0 CoreFoundation__CFRunLoopRun + 1840 frame #5: 0x00000001944ea2b8 CoreFoundationCFRunLoopRunSpecific + 444
frame #6: 0x0000000194537b44 CoreFoundationCFRunLoopRun + 112 frame #7: 0x00000001000a5ba8 backboardd_mh_execute_header + 121768
frame #8: 0x00000001000a5bec backboardd_mh_execute_header + 121836 frame #9: 0x00000001936a5850 libsystem_pthread.dylib_pthread_body + 240
frame #10: 0x00000001936a5760 libsystem_pthread.dylib_pthread_start + 284 frame #11: 0x00000001936a2d94 libsystem_pthread.dylibthread_start + 4Solução de problemas:
Instale a versão mais recente do XCode (desenvolvido e testado com 8.3.3)
Se a conexão do lldb falhar, certifique-se de ter o SDK para a versão do iOS alvo instalado.
Ressalvas:
Espero corrigir isso, mas estou muito ocupado no momento, desculpe!
Executando outros PoCs:
Se você colocar um binário na pasta pocs deste projeto, pode fazer o exploit executá-lo selecionando-o na interface no dispositivo e clicando em "exec bundle binary".
Ele ainda será executado dentro do sandbox do app, mas se o app tiver um símbolo chamado privileged_task_port, ele receberá um direito de envio para a porta de tarefa do launchd. A pasta triple_fetch_sdk contém um projeto de exemplo mostrando como você pode usar isso para criar PoCs, por exemplo, para acionar comportamentos em processos interessantes que você pode então depurar usando o debugserver.
Ela também contém as APIs remote call/ports/files/memory, que permitem chamar facilmente funções em outros processos e mover descritores de arquivo, portas mach e memória.
(1) [https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html] (2) [https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html] (3) [http://newosxbook.com/articles/PST2.html] (4) [https://gist.github.com/thlorenz/a068c202f2487ec13809]
Este projeto contém código (debugserver.diff) e um binário (debugserver) baseado no lldb, que está sujeito à seguinte licença:
University of Illinois/NCSA Open Source License
Copyright (c) 2010 Apple Inc. Todos os direitos reservados.
Desenvolvido por:
LLDB Team
A permissão é concedida, gratuitamente, a qualquer pessoa que obtenha uma cópia deste software e dos arquivos de documentação associados (o "Software"), para lidar com o Software sem restrição, incluindo, sem limitação, os direitos de usar, copiar, modificar, mesclar, publicar, distribuir, sublicenciar e/ou vender cópias do Software, e permitir que as pessoas às quais o Software seja fornecido façam o mesmo, sujeito às seguintes condições:
As redistribuições do código-fonte devem manter o aviso de copyright acima, esta lista de condições e os seguintes avisos de isenção de responsabilidade.
As redistribuições em formato binário devem reproduzir o aviso de copyright acima, esta lista de condições e os seguintes avisos de isenção de responsabilidade na documentação e/ou em outros materiais fornecidos com a distribuição.
Nem os nomes da LLDB Team, dos detentores dos direitos autorais, nem os nomes de seus contribuidores podem ser usados para endossar ou promover produtos derivados deste Software sem permissão escrita prévia específica.
O SOFTWARE É FORNECIDO "COMO ESTÁ", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIABILIDADE, ADEQUAÇÃO A UM DETERMINADO FIM E NÃO VIOLAÇÃO. EM NENHUM CASO OS CONTRIBUIDORES OU DETENTORES DOS DIREITOS AUTORAIS SERÃO RESPONSÁVEIS POR QUALQUER RECLAMAÇÃO, DANOS OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, ATO ILÍCITO OU DE OUTRA FORMA, DECORRENTE DE, OU EM CONEXÃO COM, O SOFTWARE OU O USO OU OUTRAS NEGOCIAÇÕES COM O SOFTWARE.