SELECT code_execution FROM * USING SQLite;

Obtendo execução de código usando um banco de dados SQLite malicioso

Pesquisa por: Omer Gull

tl; dr

O SQLite é um dos softwares mais implantados no mundo. No entanto, do ponto de vista da segurança, ele só foi examinado através da lente do WebSQL e da exploração do navegador. Acreditamos que esta é apenas a ponta do iceberg.

Em nossa pesquisa de longo prazo, experimentamos a exploração de problemas de corrupção de memória no SQLite sem depender de nenhum ambiente além da linguagem SQL. Usando nossas técnicas inovadoras de Query Hijacking e Query Oriented Programming, provamos que é possível explorar com segurança problemas de corrupção de memória no mecanismo SQLite. Demonstramos essas técnicas em alguns cenários do mundo real: criar um servidor de ladrão de senhas e obter persistência do iOS com privilégios mais altos.

Esperamos que, ao divulgar nossa pesquisa e metodologia, a comunidade de pesquisa de segurança seja inspirada a continuar examinando o SQLite nos inúmeros cenários em que está disponível. Dado o fato de o SQLite estar praticamente embutido em todos os principais sistemas operacionais, computadores ou dispositivos móveis, o cenário e as oportunidades são infinitas. Além disso, muitas das primitivas apresentadas aqui não são exclusivas do SQLite e podem ser portadas para outros mecanismos SQL. Bem-vindo ao admirável mundo novo do uso da familiar Structured Query Language para primitivas de exploração.

Motivação

Essa pesquisa começou quando eu e Omriher estávamos examinando o código-fonte vazado de alguns notórios ladrões de senhas. Embora haja muitos ladrões de senhas por aí ( Azorult , Loki Bot e Pony, para citar alguns), seu modus operandi é basicamente o mesmo:

Um computador é infectado e o malware captura credenciais à medida que são usadas ou coleta credenciais armazenadas mantidas por vários clientes.
Não é incomum que o software cliente use bancos de dados SQLite para tais fins.
Depois que o malware coleta esses arquivos SQLite, ele os envia para o servidor C2, onde são analisados ​​usando PHP e armazenados em um banco de dados coletivo que contém todas as credenciais roubadas.

Percorrendo o código-fonte vazado desses ladrões de senhas, começamos a especular sobre a superfície de ataque descrita acima.
Podemos aproveitar a carga e a consulta de um banco de dados não confiável para nossa vantagem?
Tais recursos podem ter implicações muito maiores em inúmeros cenários, pois o SQLite é um dos mais amplamente implementados softwares existentes .

Uma base de código surpreendentemente complexa, disponível em quase todos os dispositivos imagináveis. é toda a motivação que precisávamos, e assim nossa jornada começou.

Introdução ao SQLite

As chances são altas de que você esteja usando o SQLite no momento, mesmo que não o saiba.
Para citar seus autores:

O SQLite é uma biblioteca em linguagem C que implementa um mecanismo de banco de dados SQL pequeno, rápido, independente, de alta confiabilidade e completo. O SQLite é o mecanismo de banco de dados mais usado no mundo. O SQLite está embutido em todos os telefones celulares e na maioria dos computadores e é fornecido em inúmeras outras aplicações que as pessoas usam todos os dias.

Diferentemente da maioria dos outros bancos de dados SQL, o SQLite não possui um processo de servidor separado. O SQLite lê e grava diretamente em arquivos de disco comuns. Um banco de dados SQL completo com várias tabelas, índices, gatilhos e visualizações está contido em um único arquivo de disco.

Superfície de ataque

O fragmento a seguir é um exemplo bastante genérico de back-end de ladrão de senhas.

Dado que controlamos o banco de dados e seu conteúdo, a superfície de ataque disponível para nós pode ser dividida em duas partes: a carga e a análise inicial do nosso banco de dados e a consulta SELECT executada nele.

O carregamento inicial feito pelo sqlite3_open é na verdade uma superfície muito limitada; é basicamente um monte de código de instalação e configuração para abrir o banco de dados. Nossa superfície é principalmente a análise de cabeçalho que é testada em batalha contra a AFL.

As coisas ficam mais interessantes quando começamos a consultar o banco de dados.
Usando as palavras dos autores do SQLite:

“A instrução SELECT é o comando mais complicado da linguagem SQL.”

Embora não tenhamos controle sobre a consulta propriamente dita (como está codificada em nosso destino), estudar o processo SELECT com cuidado será benéfico em nossa busca por exploração.

Como o SQLite3 é uma máquina virtual, toda instrução SQL deve primeiro ser compilada em um programa de código de bytes usando uma das rotinas sqlite3_prepare * .
Entre outras operações, a função de preparação caminha e expande todas as subconsultas SELECT. Parte desse processo é verificar se todos os objetos relevantes (como tabelas ou visualizações) realmente existem e localizá-los no esquema principal.

sqlite_master e DDL

Todo banco de dados SQLite possui uma sqlite_mastertabela que define o esquema para o banco de dados e todos os seus objetos (como tabelas, visualizações, índices etc.).
A tabela sqlite_master é definida como:

A parte que nos interessa especialmente é a coluna sql.
Este campo é o DDL (Data Definition Language) usado para descrever o objeto.
De certo modo, os comandos DDL são semelhantes aos arquivos de cabeçalho C. Os comandos DDL são usados ​​para definir a estrutura, nomes e tipos dos contêineres de dados em um banco de dados, assim como um arquivo de cabeçalho geralmente define definições de tipos, estruturas, classes e outras estruturas de dados.

Essas instruções DDL realmente aparecem em texto sem formatação se inspecionarmos o arquivo do banco de dados:

Durante a preparação da consulta, o sqlite3LocateTable () tenta encontrar a estrutura da memória que descreve a tabela que estamos interessados ​​em consultar.

sqlite3LocateTable () lê o esquema disponível em sqlite_master e, se for a primeira vez, também possui um retorno de chamada para todos os resultados que verificam que a instrução DDL é válida e cria as estruturas de dados internas necessárias que descrevem o objeto em questão.

Correção de DDL

Perguntamos: aprendendo sobre esse processo de preparação, podemos simplesmente substituir o DDL que aparece em texto sem formatação no arquivo? Se pudermos injetar nosso próprio SQL no arquivo, talvez possamos afetar seu comportamento.

Com base no snippet de código acima, parece que as instruções DDL devem começar com “create”.
Com essa limitação em mente, precisávamos avaliar nossa superfície.
A verificação da documentação do SQLite revelou que estes são os possíveis objetos que podemos criar:

O comando CREATE VIEW nos deu uma ideia interessante. Para simplificar, VIEWs são apenas instruções SELECT pré-empacotadas. Se substituirmos a tabela esperada pelo software de destino por uma VIEW compatível, oportunidades interessantes se revelam.

Seqüestrar qualquer consulta

Imagine o seguinte cenário:
O banco de dados original possui uma única TABLE chamada dummy, definida como:

O software de destino consulta com o seguinte:

Na verdade, podemos seqüestrar essa consulta se criarmos fictícios como uma VIEW:

Essa “armadilha” VIEW nos permite seqüestrar a consulta – o que significa que geramos uma consulta completamente nova que controlamos totalmente.

Essa nuance expande bastante nossa superfície de ataque, desde a análise mínima do cabeçalho e uma consulta incontrolável realizada pelo software de carregamento, até o ponto em que agora podemos interagir com vastas partes do interpretador SQLite corrigindo o DDL e criando nossas próprias visualizações com subconsultas.

Agora que podemos interagir com o intérprete SQLite, nossa próxima pergunta foi: quais primitivas de exploração estão embutidas no SQLite? Permite algum comando do sistema, ler ou gravar no sistema de arquivos?

Como não somos os primeiros a perceber o enorme potencial SQLite do ponto de vista da exploração, faz sentido revisar o trabalho anterior realizado em campo. Começamos desde o básico.

Injeções de SQL

Como pesquisadores, é difícil escrevermos SQL sem o “i”, então parece um lugar razoável para começar. Afinal, queremos nos familiarizar com as primitivas internas oferecidas pelo SQLite. Existem comandos do sistema? Podemos carregar bibliotecas arbitrárias?

Parece que o truque mais direto envolve anexar um novo arquivo de banco de dados e gravá-lo usando algo como:

Anexamos um novo banco de dados, criamos uma única tabela e inserimos uma única linha de texto. O novo banco de dados cria um novo arquivo (como os bancos de dados são arquivos no SQLite) com nosso shell da web dentro dele.
A natureza perdoadora do interpretador PHP analisa nosso banco de dados até atingir a tag aberta do PHP “<?”.
Escrever um webshell é definitivamente uma vitória no nosso cenário de ladrões de senhas, no entanto, como você se lembra, o DDL não pode começar com “ATTACH”

Outra opção relevante é a função load_extension . Embora essa função nos permita carregar um objeto compartilhado arbitrário, ela é desativada por padrão.

Corrupções de memória no SQLite

Como qualquer outro software escrito em C, os problemas de segurança da memória são definitivamente algo a considerar ao avaliar a segurança do SQLite.
Em seu ótimo post no blog , Michał Zalewski descreveu como ele mexeu no SQLite com o AFL para obter alguns resultados impressionantes: 22 bugs em apenas 30 minutos de fuzzing.

Curiosamente, o SQLite começou a usar o AFL como parte integrante de seu notável conjunto de testes.

Essas corrupções de memória foram tratadas com a gravidade esperada (Richard Hip e sua equipe merecem muito respeito). No entanto, da perspectiva de um invasor, esses bugs provariam ser um caminho difícil para a exploração, sem uma estrutura decente para aproveitá-los.
As mitigações modernas representam um grande obstáculo na exploração de problemas de corrupção de memória e os invasores precisam encontrar um ambiente mais flexível.

A comunidade de pesquisa de segurança em breve encontrará o alvo perfeito!

Web SQL

O Banco de Dados SQL da Web é uma API de página da Web para armazenar dados em bancos de dados que podem ser consultados usando uma variante do SQL por meio de JavaScript. O Grupo de Trabalho de Aplicativos Web do W3C parou de trabalhar na especificação em novembro de 2010, citando a falta de implementações independentes, além do SQLite.

Atualmente, a API ainda é suportada pelo Google Chrome, Opera e Safari.
Todos eles usam o SQLite como back-end desta API.

A entrada não confiável no SQLite, acessível a partir de qualquer site dentro de alguns dos navegadores mais populares, chamou a atenção da comunidade de segurança e, como resultado, o número de vulnerabilidades começou a aumentar.
De repente, os erros no SQLite poderiam ser aproveitados pelo interpretador JavaScript para obter uma exploração confiável do navegador.

Vários relatórios de pesquisa impressionantes foram publicados:

Um padrão claro em pesquisas anteriores do WebSQL revela que um módulo de tabela virtual chamado “FTS” pode ser um alvo interessante para nossa pesquisa.

FTS

A pesquisa de texto completo (FTS) é um módulo de tabela virtual que permite pesquisas de texto em um conjunto de documentos.
Da perspectiva de uma instrução SQL, o objeto de tabela virtual se parece com qualquer outra tabela ou exibição. Mas nos bastidores, as consultas em uma tabela virtual invocam métodos de retorno de chamada em tabelas de sombra em vez da leitura e gravação usuais no arquivo de banco de dados.

Algumas implementações de tabela virtual, como o FTS, usam tabelas de banco de dados reais (não virtuais) para armazenar conteúdo.

Por exemplo, quando uma sequência é inserida na tabela virtual do FTS3, alguns metadados devem ser gerados para permitir uma pesquisa textual eficiente. Esses metadados são finalmente armazenados em tabelas reais denominadas “% _segdir” e “% _segments”, enquanto o conteúdo em si é armazenado em “”% _content “onde”% “é o nome da tabela virtual original.
Essas tabelas reais auxiliares que contêm dados para uma tabela virtual são chamadas de “tabelas de sombra”

Devido à sua natureza confiante, as interfaces que passam dados entre as tabelas de sombra fornecem um terreno fértil para erros. CVE-2019-8457, – uma nova vulnerabilidade de leitura OOB que encontramos no módulo de tabela virtual RTREE, demonstra isso bem.

As tabelas virtuais RTREE, usadas para indexação geográfica, devem começar com uma coluna inteira. Portanto, outras interfaces RTREE esperam que a primeira coluna em um RTREE seja um número inteiro. No entanto, se criarmos uma tabela em que a primeira coluna é uma string, como mostra a figura abaixo, e a passamos para a interface rtreenode () , ocorre uma leitura OOB.

Agora que podemos usar o seqüestro de consultas para obter controle sobre uma consulta e saber onde encontrar vulnerabilidades, é hora de explorar o desenvolvimento.

SQLite Internals para desenvolvimento de exploração

Publicações anteriores sobre exploração de SQLite mostram claramente que sempre houve a necessidade de um ambiente de agrupamento, seja o intérprete PHP visto nesta impressionante postagem no blog sobre abuso de tokenizadores SQLite ou o trabalho mais recente sobre Web SQL no conforto de um intérprete JavaScript .

Como o SQLite está praticamente em todo lugar, limitar seu potencial de exploração soou pouco para nós e começamos a explorar o uso de componentes internos do SQLite para fins de exploração.
A comunidade de pesquisa se tornou muito boa em utilizar JavaScript para explorar o desenvolvimento. Podemos obter primitivas semelhantes com o SQL?

Tendo em mente que o SQL é Turing completo ([ 1 ], [ 2 ]), começamos a criar uma lista de desejos primitiva para o desenvolvimento da exploração, com base em nossa experiência inicial.
Uma exploração moderna escrita puramente em SQL possui os seguintes recursos:

  • Vazamento de memória.
  • Embalagem e descompactação de números inteiros para ponteiros de 64 bits.
  • Aritmética de ponteiro.
  • Criando objetos falsos complexos na memória.
  • Heap Spray.

Um por um, abordaremos essas primitivas e as implementaremos usando nada além de SQL.

Com o objetivo de atingir o RCE no PHP7, utilizaremos o dia ainda não corrigido de  CVE-2015-7036 .

Espere o que? Como é que um erro de 4 anos nunca foi corrigido? Na verdade, é uma história interessante e um ótimo exemplo de nosso argumento.
Esse recurso só foi considerado vulnerável no contexto de um programa que permite SQL arbitrário a partir de uma fonte não confiável (Web SQL) e, portanto, foi mitigado de acordo.
No entanto, o uso do SQLite é tão versátil que ainda podemos ativá-lo em muitos cenários.

Plano de exploração do jogo

CVE-2015-7036 é um bug muito conveniente para se trabalhar.
Em poucas palavras, a vulnerável função fts3_tokenizer () retorna o endereço do tokenizer quando chamada com um único argumento (como “simple”, “porter” ou qualquer outro tokenizer registrado).

Quando chamado com 2 argumentos, fts3_tokenizer substitui o endereço do tokenizer no primeiro argumento pelo endereço fornecido por um blob no segundo argumento.
Após a substituição de um determinado tokenizer, qualquer nova instância da tabela fts que use esse tokenizer nos permite seqüestrar o fluxo do programa.

Nosso plano de jogo de exploração:

  • Vazar um endereço de tokenizer
  • Calcular o endereço base
  • Crie um tokenizador falso que executará nosso código malicioso
  • Substitua um dos tokenizers pelo nosso tokenizer malicioso
  • Instancie uma tabela fts3 para acionar nosso código malicioso

Agora, de volta ao nosso desenvolvimento de exploração.

Programação Orientada a Consultas ©

Estamos orgulhosos de apresentar nossa própria abordagem exclusiva para o desenvolvimento de exploração usando a familiar linguagem de consulta estruturada. Compartilhamos o QOP com a comunidade na esperança de incentivar os pesquisadores a buscar as infinitas possibilidades de exploração dos mecanismos de banco de dados.
Cada uma das seguintes primitivas é acompanhada por um exemplo do shell sqlite3.

Embora isso lhe dê uma dica do que você deseja alcançar, lembre-se de que nosso objetivo final é plantar todas essas primitivas na tabela sqlite_master e seqüestrar as consultas emitidas pelo software de destino que carrega e consulta nosso arquivo db SQLite malicioso

Vazamento de memória – binário

Mitigações como o ASLR definitivamente elevaram o nível da exploração de corrupção de memória. Uma maneira comum de derrotá-lo é aprender algo sobre o layout da memória que nos rodeia.
Isso é amplamente conhecido como vazamento de memória.
Vazamentos de memória são sua própria subclasse de vulnerabilidades, e cada um tem uma configuração ligeiramente diferente.

No nosso caso, o vazamento é o retorno de um BLOB pelo SQLite.
Esses BLOBs são um excelente alvo de vazamento, pois às vezes mantêm ponteiros de memória.

O vulnerável fts3_tokenizer () é chamado com um único argumento e retorna o endereço de memória do tokenizer solicitado. hex () torna legível por humanos.
Obviamente, obtemos algum endereço de memória, mas ele é revertido devido à pouca endianidade.
Certamente podemos alterá-lo usando algumas operações de string internas do SQLite.

substr () parece ser um ajuste perfeito! Podemos ler BLOBs little-endianos, mas isso levanta outra questão: como armazenamos as coisas?

Cadeia QOP

Naturalmente, armazenar dados no SQL requer uma instrução INSERT. Devido à verificação rigorosa do sqlite_master, não podemos usar INSERT, pois todas as instruções devem começar com “CREATE”. Nossa abordagem para esse desafio é simplesmente armazenar nossas consultas sob uma VISÃO significativa e encaderná-las.
O exemplo a seguir torna um pouco mais claro:

Isso pode não parecer uma grande diferença, mas à medida que nossa cadeia se torna mais complicada, poder usar pseudo-variáveis ​​certamente tornará nossa vida mais fácil.

Descompactar ponteiros de 64 bits

Se você já enfrentou algum desafio, o conceito de empacotar e descompactar ponteiros não deve ser estranho.
Essa primitiva deve facilitar a conversão de nossos valores hexadecimais (como o vazamento que acabamos de obter) em números inteiros. Isso nos permite realizar vários cálculos sobre esses ponteiros nas próximas etapas.

Esta consulta itera uma string hexadecimal char por char de maneira reversa usando substr ().

Uma tradução desse char é feita usando esse truque inteligente com o pequeno ajuste de instr () que é baseado em 1.
Tudo o que é necessário agora é a mudança adequada à direita do sinal *.

Aritmética de ponteiros

A aritmética de ponteiro é uma tarefa bastante fácil com números inteiros em mãos. Por exemplo, extrair a base da imagem do ponteiro do tokenizer vazado é tão fácil quanto:

Embalagem de ponteiros de 64 bits

Depois de ler os ponteiros vazados e manipulá-los de acordo com a nossa vontade, faz sentido empacotá-los de volta à sua forma little-endian para que possamos escrevê-los em algum lugar.
O SQLite char ()   deve ser útil aqui, pois sua documentação afirma que “retornará uma sequência composta de caracteres com os valores de ponto de código Unicode de um número inteiro”.
Ele provou funcionar razoavelmente bem, mas apenas em um intervalo limitado de números inteiros

Inteiros maiores foram traduzidos para seus pontos de código de 2 bytes.
Depois de bater a cabeça na documentação do SQLite, de repente tivemos uma estranha epifania: nossa exploração é na verdade um banco de dados.
Podemos preparar antecipadamente uma tabela que mapeie números inteiros para seus valores esperados.

Agora, nossa consulta de empacotamento de ponteiro é a seguinte:

Criando objetos falsos complexos na memória

Escrever um único ponteiro é definitivamente útil, mas ainda não é suficiente. Muitos cenários de exploração de problemas de segurança de memória exigem que os atacantes forjem algum objeto ou estrutura na memória ou mesmo escrevam uma cadeia ROP.

Essencialmente, definiremos vários dos blocos de construção apresentados anteriormente.
Por exemplo, vamos forjar nosso próprio tokenizer, conforme explicado aqui .
Nosso tokenizer falso deve estar em conformidade com a interface esperada pelo SQLite definida aqui:

Usando os métodos descritos acima e uma simples consulta JOIN, somos capazes de falsificar o objeto desejado com bastante facilidade.

Verificando o resultado em um depurador de baixo nível, vemos que, de fato, um objeto tokenizer falso foi criado.

Heap Spray

Agora que criamos nosso objeto falso, às vezes é útil borrifá-lo.
Idealmente, essa deve ser uma forma repetitiva deste último.

Infelizmente, o SQLite não implementa a função REPEAT () como o MySQL.
No entanto, esse segmento nos deu uma solução elegante.

A função zeroblob (N) retorna um BLOB composto por N bytes, enquanto usamos replace () para substituir esses zeros pelo nosso objeto falso.

Pesquisando esses 0x41s, também alcançamos uma consistência perfeita. Observe a repetição a cada 0x20 bytes.

Vazamento de memória – Heap

Olhando para o nosso plano de exploração, parece que estamos caminhando na direção certa.
Já sabemos onde a imagem binária está localizada, conseguimos deduzir onde estão as funções necessárias e pulverizar a pilha com nosso tokenizador malicioso.

Agora é hora de substituir um tokenizador por um de nossos objetos pulverizados. No entanto, como o endereço da pilha também é randomizado, não sabemos onde nosso spray está alocado.
Um vazamento de heap exige que tenhamos outra vulnerabilidade.

Novamente, vamos direcionar uma interface de tabela virtual.
Como as tabelas virtuais usam tabelas de sombra subjacentes, é bastante comum que elas passem ponteiros brutos entre diferentes interfaces SQL.

Nota: Esse tipo exato de problema foi atenuado no SQLite 3.20 . Felizmente, o PHP7 é compilado com uma versão anterior. No caso de uma versão atualizada, o CVE-2019-8457 também pode ser usado aqui.

Para vazar o endereço de heap, precisamos gerar uma tabela fts3 antecipadamente e abusar de sua interface MATCH.

Assim como vimos em nosso primeiro vazamento de memória, o ponteiro é pouco endian e, portanto, precisa ser revertido. Felizmente, já sabemos como fazê-lo usando SUBSTR ().
Agora que conhecemos nossa localização de heap e podemos pulverizar corretamente, podemos finalmente substituir um tokenizer por nosso tokenizer malicioso!

Juntando tudo

Com todas as primitivas de exploração desejadas em mãos, é hora de voltar para onde começamos: explorar um ladrão de senhas C2.

Como explicado acima, precisamos configurar uma VIEW “trap” para iniciar nossa exploração. Portanto, precisamos examinar nosso objetivo e preparar a visão correta.

Como visto no snippet acima, nosso alvo espera que nosso banco de dados tenha uma tabela chamada Notes com uma coluna chamada BodyRich dentro dela. Para seqüestrar essa consulta, criamos a seguinte VIEW

Após a consulta do Notes, três cadeias QOP são executadas. Vamos analisar o primeiro deles.

heap_spray

Nossa primeira cadeia de QOP deve preencher o heap com uma grande quantidade de nosso tokenizer malicioso.

p64_simple_create, p64_simple_destroy e p64_system são essencialmente todas as cadeias alcançadas com nossos recursos de vazamento e empacotamento.

Por exemplo, p64_simple_create é construído como:

Como estas cadeias ficar muito complexo, muito rápido, e são bastante repetitivo, criamos QOP.py .
O QOP.py torna as coisas um pouco mais simples, gerando essas consultas no estilo pwntools.
Criar as instruções anteriores se torna tão fácil quanto:

Demo

COMMIT;

Agora que estabelecemos uma estrutura para explorar qualquer situação em que o pesquisador não possa ter certeza de que o banco de dados não é malicioso, vamos explorar outro caso de uso interessante para a exploração do SQLite.

Persistência do iOS

É difícil conseguir persistência no iOS, pois todos os arquivos executáveis ​​devem ser assinados como parte do Secure Boot da Apple. Felizmente para nós, os bancos de dados SQLite não são assinados.

Utilizando nossos novos recursos, substituiremos um dos bancos de dados comumente usados ​​por uma versão maliciosa. Depois que o dispositivo é reiniciado e nosso banco de dados malicioso é consultado, obtemos a execução do código.

Para demonstrar esse conceito, substituímos o banco de dados de contatos “AddressBook.sqlitedb”. Conforme feito em nossa exploração do PHP7, criamos duas instruções DDL extras. Uma instrução DDL substitui o tokenizer padrão como “simples” e a outra instrução DDL aciona a falha ao tentar instanciar o tokenizer substituído. Agora, tudo o que precisamos fazer é reescrever todas as tabelas do banco de dados original como uma exibição que seqüestra qualquer consulta executada e a redireciona para nossa DDL maliciosa.

Substituir o banco de dados de contatos pelo banco de dados de contatos maliciosos e reiniciar resulta no seguinte despejo de memória do iOS:

Como esperado, o processo de contatos travou em 0x4141414141414149, onde esperava encontrar o construtor xCreate do nosso falso tokenizador.

Além disso, o banco de dados de contatos é realmente compartilhado entre muitos processos. Contatos, Facetime, Springboard, WhatsApp, Telegram e XPCProxy são apenas alguns dos processos que o consultam. Alguns desses processos são mais privilegiados que outros. Depois de provarmos que podemos executar o código no contexto do processo de consulta, essa técnica também nos permite expandir e elevar nossos privilégios.

Nossa pesquisa e metodologia foram divulgadas com responsabilidade à Apple e receberam as seguintes CVEs:

  • CVE-2019-8600
  • CVE-2019-8598
  • CVE-2019-8602
  • CVE-2019-8577

Trabalho futuro

Dado o fato de o SQLite estar praticamente embutido em praticamente qualquer plataforma, achamos que mal arranhamos a ponta do iceberg quando se trata de seu potencial de exploração. Esperamos que a comunidade de segurança leve essa pesquisa inovadora e as ferramentas lançadas e a leve ainda mais longe. Algumas opções que consideramos interessantes a seguir são:

  • Criando explorações mais versáteis. Isso pode ser feito através da criação de explorações dinamicamente, escolhendo os dispositivos QOP relevantes de tabelas pré-fabricadas, usando funções como sqlite_version () ou sqlite_compileoption_used () .
  • Atingir primitivas de exploração mais fortes, como R / W arbitrário.
  • Procure outros cenários em que o consultor não pode verificar a confiabilidade do banco de dados.

Conclusão

Estabelecemos que simplesmente consultar um banco de dados pode não ser tão seguro quanto o esperado. Usando nossas técnicas inovadoras de Query Hijacking e Query Oriented Programming, provamos que os problemas de corrupção de memória no SQLite agora podem ser explorados com segurança. À medida que nossas hierarquias de permissões se tornam mais segmentadas do que nunca, fica claro que devemos repensar os limites da entrada SQL confiável / não confiável. Para demonstrar esses conceitos, alcançamos a execução remota de código em um back-end ladrão de senhas executando o PHP7 e ganhamos persistência com privilégios mais altos no iOS. Acreditamos que esses são apenas alguns casos de uso no cenário infinito do SQLite.

O produto IPS da Check Point protege contra esta ameaça: “Execução remota de código do ponteiro não confiável fts3_tokenizer do SQLite (CVE-2019-8602).”

 

 

Fonte:

Traduzido e adaptado de: https://research.checkpoint.com/2019/select-code_execution-from-using-sqlite/

Aprenda mais no curso CFID

Gostou do artigo? Conheça o curso Computação Forense e Investigação Digital.

Este curso tem como objetivo apresentar os conceitos da Computação Forense e métodos de Investigação Digital, sendo baseado no conteúdo apresentado nas certificações mais conhecidas do mercado.

Hospedagem de site

digitalocean, excelente custo benefício.

Clique abaixo e aproveite!