Segurança no Android



Documentos relacionados
3 SERVIÇOS IP. 3.1 Serviços IP e alguns aspectos de segurança

Manual do PolicyKit-kde. Daniel Nicoletti Tradução: Luiz Fernando Ranghetti

2 Diagrama de Caso de Uso

5 Mecanismo de seleção de componentes

Manual do Usuário Android Neocontrol

IFPE. Disciplina: Sistemas Operacionais. Prof. Anderson Luiz Moreira

VM Card. Referência das Definições Web das Funções Avançadas. Manuais do Utilizador

Guia de instalação do Player Displr Windows 7, 8.1 e 10

Manual de Utilizador Documentos de Transporte. TOConline. Suporte. Página - 1

Como funciona a MEO Cloud?

Programa de Atualização de Pontos do Lince GPS

Google Drive. Passos. Configurando o Google Drive

Entendendo como funciona o NAT

Introdução ao Modelos de Duas Camadas Cliente Servidor

Documento de ajuda para utilizadores de Office 2010/2007

ESTUDO DE CASO WINDOWS VISTA

ZS Rest. Manual Avançado. Ementas : e SMS. v2011

Sistemas Distribuídos

Programa de Instalação do Lince GPS

Internet e no Akropole. Internet e no Akropole

Sistemas Distribuídos. Professora: Ana Paula Couto DCC 064

Suporte Técnico de Software HP

Hardware (Nível 0) Organização. Interface de Máquina (IM) Interface Interna de Microprogramação (IIMP)

CRIAÇÃO E MANUTENÇÃO DE BLOGUES

Manual de Utilização de Certificados Digitais. Microsoft Word 2003

KF2.4 MANUAL DE UTILIZADOR

MANUAL DE INSTALAÇÃO

Aplicações de Escritório Electrónico

PHC dteamcontrol Externo

SYNCING.NET 2.0 Instalação & Configuração

O Manual do Desktop Sharing. Brad Hards Tradução: Pedro Morais

FERRAMENTAS DE COLABORAÇÃO CORPORATIVA

Orientação a Objetos

UNIVERSIDADE FEDERAL DE PELOTAS

Manual de Instalação PIMSConnector em Windows

MANUAL DO UTILIZADOR

TCEnet e TCELogin Manual Técnico

Pesquisa e organização de informação

Hardware & Software. SOS Digital: Tópico 2

Operador de Computador. Informática Básica

Pingwin Android Como instalar

SISTEMAS OPERACIONAIS ABERTOS Prof. Ricardo Rodrigues Barcelar

Prof. Marcos Ribeiro Quinet de Andrade Universidade Federal Fluminense - UFF Pólo Universitário de Rio das Ostras - PURO

Mapas e Localização. Programação de Dispositivos Móveis. Mauro Lopes Carvalho Silva

O que é a assinatura digital?... 3

Algoritmos e Programação (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br

UNIVERSIDADE FEDERAL DE GOIÁS CERCOMP (CENTRO DE RECURSOS COMPUTACIONAIS) TUTORIAL DE USO DO WEBMAIL - UFG

ACRONIS BACKUP AND RECOVERY 10 SERVER FOR LINUX

Manual de Utilização. Site Manager. Tecnologia ao serviço do Mundo Rural

Programação para Android. Aula 07: Persistência de dados Shared Preferences, Internal e External Storage

Integração de Sistemas Embebidos MECom :: 5º ano

SAFT para siscom. Manual do Utilizador. Data última versão: Versão: Data criação:

Manual de Utilização de Certificados Digitais. Microsoft Word 2010

Manual de Utilizador

Auxiliar de instalação (Português Brasileiro) Primeiros passos

Engenharia de Software Sistemas Distribuídos

Notas da Aula 15 - Fundamentos de Sistemas Operacionais

MÓDULO 7 Modelo OSI. 7.1 Serviços Versus Protocolos

Seu manual do usuário EPSON LQ-630

SUMÁRIO 1. AULA 6 ENDEREÇAMENTO IP:... 2

COMPETÊNCIAS BÁSICAS EM TIC NAS EB1

UNIVERSIDADE CATÓLICA PORTUGUESA DSI

Figura 01 Kernel de um Sistema Operacional

ZS Rest. Manual Avançado. Instalação em Rede. v2011

MANUAL DE UTILIZAÇÃO TERMINAL DE PORTA

Novell. Novell Teaming 1.0. novdocx (pt-br) 6 April 2007 EXPLORAR O PORTLET BEM-VINDO DESCUBRA SEU CAMINHO USANDO O NOVELL TEAMING NAVIGATOR

Guia de instalação. Configuração necessária Instalação e ativação

UM NOVO CONCEITO EM HOSPEDAGEM DE DOMÍNIO

Manual Brother Image Viewer para Android

Guia rápido de criação e gestão de um espaço no SAPO Campus

Seu manual do usuário HP SLATE 10 HD 3500EF SILVER

Projeto de Arquitetura

Capítulo 5 Métodos de Defesa

Manual do Utilizador

PLATAFORMA INFORMÁTICA DE REQUISIÇÃO DE POLICIAMENTO DE ESPETÁCULOS DESPORTIVOS (PIRPED)

DESENVOLVIMENTO DE UM APLICATIVO DO TIPO SECRETÁRIO VIRTUAL PARA A PLATAFORMA ANDROID

EM4590R1 Repetidor Sem Fios WPS

Sistemas Operacionais

EW1051 Leitor de Smart Card USB

SECUNDÁRIA DE CAMARATE Plataforma Office 365. Alojamento de ficheiros - OneDrive para Empresas

Acronis Servidor de Licença. Manual do Utilizador

Segurança Internet. Fernando Albuquerque. (061)

Motorola Phone Tools. Início Rápido

O Manual do Simond. Peter H. Grasch

Política de privacidade do Movimento Certo Ginástica Laboral Online Última atualização: 17 de março de 2015

Manual de Utilização do Zimbra

LICENCIAMENTO V14 USANDO REPRISE LICENSE MANAGER

Com o smartmessage podemos de forma muito fácil e usando um qualquer cliente de , como por exemplo:

Manual de Instalação PIMSConnector em Linux

Histórico de Revisão Data Versão Descrição Autor

Solução de Telecontagem. Gestão de Contratos. Esta solução é indicada para sistemas de contagem de caudal usando um mínimo de recursos.

FTP Protocolo de Transferência de Arquivos

Transcrição:

Segurança no Android Segurança em Sistemas Informáticos 2011/2012 Daniel Cibrão 070509149 Rui Gonçalves 070509070 1

Tabela de conteúdos 1. Introdução 2. Arquitetura de segurança 2.1. O kernel Linux 2.2. A sandbox de aplicações 2.3. Sistema de ficheiros e encriptação 2.3.1. Estrutura e permissões 2.3.2. Encriptação 2.4. Rooting de dispositivos 2.4.1. Bootloader e Recovery 2.4.2. ADB 2.4.3. Application Framework 2.4.4. Contorno dos mecanismos de segurança 3. Instalação de aplicações 3.1. Assinatura da aplicação 3.1.1. Keytool 3.1.2. Jarsigner 3.1.3. Modos de assinatura 3.2. Estratégias de assinatura 3.3. Permissões ao nível da assinatura 4. Comunicação entre processos e acesso a recursos 4.1. Comunicação entre processos 4.1.1 Intents 4.1.2 Binders 5. Autorização de operações 5.1. Modelo de permissões 5.2. Concessão explícita de permissões 5.3. Permissões de acesso a informação pessoal 6. Problemas e vulnerabilidades 6.1. Fraquezas no sistema 6.1.1. Má utilização de permissões 6.1.2. Escalamento de privilégios 6.1.3. Contorno do mecanismo de permissões 6.1.4. Persistência de aplicações 6.1.5. Considerações gerais 6.2. Exemplos de vulnerabilidades 6.2.1. Ferramentas de rooting 6.2.2. Contorno do mecanismo de permissões 7. Conclusões Bibliografia 2

1. Introdução O Android é uma plataforma móvel com uma utilização muito significativa no mercado dos smartphones. É uma plataforma presente em várias camadas de uma típica arquitetura de um sistema de software: engloba um sistema operativo, middleware e um conjunto de aplicações essenciais. Sendo um sistema aberto, com o seu código fonte disponível publicamente na íntegra, é fundamental a existência de alicerces sólidos no que toca a segurança. Este relatório é realizado no âmbito da unidade curricular de Segurança em Sistemas Informáticos (SSIN) do Mestrado Integrado em Engenharia Informática e Computação (MIEIC) na FEUP. Neste é feita uma exploração teórica do Android ao nível da segurança, desde as suas bases a um nível baixo de abstração até aos mecanismos disponíveis aos programadores de aplicações móveis e aos utilizadores finais. O objetivo final é sensibilizar os utilizadores e os programadores para os cuidados a ter no manuseamento de sistemas Android e compreender, nem que de uma forma sintetizada, como funciona o sistema em camadas inferiores de abstração. No primeiro capítulo, Arquitetura de segurança, são especificados os aspetos de baixo nível da segurança do Android. No seguinte, Instalação de aplicações, é explicado o processo de assinatura das aplicações para que possam ser instaladas nos dispositivos. No capítulo 3 é descrito como é que o sistema permite e controla a comunicação interprocessos e o acesso a recursos. O mecanismo de permissões, elemento principal da arquitetura de segurança ao nível das aplicações, é descrito no capítulo 4. No capítulo 5 são analisadas alguns pontos mais vulneráveis da plataforma e são exemplificados alguns ataques. No final, são apresentadas conclusões acerca do estudo. 3

2. Arquitetura de segurança Neste capítulo são descritos as fundações da arquitetura de segurança do Android. Qualquer sistema informático deve apresentar mecanismos de segurança em todas as camadas do sistema; são analisados aqui os mecanismos ao nível de abstração do kernel. Para que se possam compreender algumas considerações relativas a segurança, é apresentada em baixo a stack de software da plataforma Android. Em cada camada é assumido que as camadas inferiores se encontram devidamente seguras. 2.1. O kernel Linux Figura 1. Camadas de software da plataforma Android. Ao nível do sistema operativo, o Android é construído no topo do kernel do Linux, através do qual são feitos todos os acessos ao hardware do dispositivo. Este é um aspeto que confere, no mínimo, confiança a esta plataforma: este núcleo é utilizado globalmente e ativamente atualizado há vários anos, sendo uma presença quase obrigatória em ambientes computacionais em que a segurança é um requisito importante. O kernel Linux providencia ao Android um conjunto de aspetos chave no seu modelo de segurança: Um modelo de permissões baseado no utilizador - cada entidade no sistema de ficheiros tem um dono e está atribuído a um grupo. Um utilizador com permissões 4

para tal pode modificar as permissões de leitura, escrita e execução de uma entidade para o seu dono, para o grupo e para os restantes utilizadores. Existe ainda um utilizador especial (superuser) que pode violar estas permissões, tendo acesso completo ao sistema de ficheiros. 5

Isolamento de processos - Um processo em Linux funciona como uma máquina virtual: tem um espaço de endereçamento próprio, um repertório de instruções e um estado interno (i.e. estado do processador, recursos externos, etc). Um mecanismo de comunicação interprocesso segura extensível: Um processo apenas pode comunica com outros através de um conjunto de mecanismos bem definidos (que vão desde a aproximação naive de escrita de informação num ficheiro em disco até à utilização de pipes ou memória partilhada). No capítulo 4 este aspeto será descrito com mais detalhe. A hipótese de remover partes desnecessárias ou potencialmente inseguras do kernel. No papel de um sistema operativo multiutilizador, um dos objetivos de segurança do Linux é manter o isolamento e proteger os recursos dos utilizadores. Assim, o Linux garante que um utilizador não pode aceder aos ficheiros do outro, assim como também não pode monopolizar a memória RAM, os recursos do CPU e o acesso aos periféricos. Na secção seguinte será mostrada a forma peculiar como o Android faz uso do kernel Linux para conseguir um eficaz isolamento das aplicações e dos seus recursos. 2.2. A sandbox de aplicações O Android, assim como outros sistemas operativos móveis, possui características fortemente diferenciadoras relativamente a sistemas operativos tradicionais; é uma observação previsível, dado que os ambientes de utilização são bastante diferentes. Em particular, num dispositivo móvel como um smartphone, o conceito de multiutilizador não é necessário. Os sistemas operativos são então aliviados da gestão dos recursos neste sentido e podem-se focar em problemas de segurança mais emergentes, como o controlo do ambiente de execução das aplicações. A plataforma Android aproveita a gestão de utilizadores providenciada pelo kernel Linux para atacar o problema do isolamento de aplicações. O Android atribui um identificador de utilizador (UID) a cada aplicação na altura da sua instalação, não partilhado por qualquer outra aplicação por defeito. Quando uma aplicação é iniciada, é executada no contexto desse utilizador num processo separado. Esta aproximação diverge de outros sistemas operativos (incluindo o próprio Linux), em que várias aplicações correm sob o mesmo utilizador. A estratégia aplicada pelo Android assegura o isolamento das várias aplicações do sistema ao nível do kernel, utilizando para isso facilidades existentes no Linux. Uma aplicação não será autorizada, por exemplo, a aceder ao sistema de ficheiros completo, dado que cada aplicação possui uma diretoria de dados própria, cujo owner é o utilizador atribuído à própria aplicação. Isto abrange o acesso a alguns dispositivos e dados chave do telefone (e.g. uma aplicação não pode fazer chamadas ou alterar as definições do telefone, dado que estas funções são efetuadas por aplicações separadas). Observando a figura 1, podemos verificar que todo o código executável no Android (mesmo bibliotecas do sistema operativo e processos de sistema, como os serviços de SMS ou de chamadas ou ainda gestores de atividades e notificações) corre sobre o kernel. Este aspeto coloca todos os componentes do sistema sujeitos ao mesmo nível de segurança, oferecendo ao programador de Android liberdade no desenvolvimento de aplicações em qualquer nível de abstração do sistema - em outros sistemas, o programador está limitado a um conjunto limitado de APIs ou frameworks; em Android, desenvolver código nativo ou 6

interpretado é igualmente seguro. Por fim, é de notar que este sistema de sandboxing previne não só danos causados por aplicações mal intencionadas (sem que lhe tenham sido concedidas permissões para tal, como é descrito no capítulo 5), mas também exploração de vulnerabilidades nas aplicações existentes, como erros de corrupção de memória - neste caso, o possível código arbitrário executado continuaria a estar restringido ao contexto da aplicação em questão. A sandbox é simples e auditável. Como qualquer mecanismo de segurança, é passível de ter falhas. No entanto, ser baseado num kernel com décadas de utilização e popularmente acreditado como seguro confere-lhe confiança: para que uma aplicação quebre a sandbox, teria de comprometer a segurança do kernel. 2.3. Sistema de ficheiros e encriptação 2.3.1. Estrutura e permissões Os ficheiros em Android (tanto do sistema como das aplicações) estão sujeitos ao mecanismo de permissões do Linux. Cada ficheiro tem associado um owner ID, um group ID e três tuplos de permissões de leitura, escrita e execução (Read, Write and execute, rwx). A estrutura de diretorias do sistema de ficheiros (filesystem) interno do Android apresenta semelhanças em relação a um sistema baseado em Unix. Figura 2. Exemplo de estrutura normal de um sistema de ficheiros em Android. Na figura 2 podemos verificar um exemplo de estrutura geral de um sistema Android (pequenas diferenças podem existir, dependendo da versão do sistema operativo instalado e do próprio hardware), obtido através do comando Unix ls -l. Esta estrutura está criada na memória interna do dispositivo. 7

Na memória interna, as aplicações têm um local bem definido onde podem guardar os seus dados. Este é o diretório /data/data, sendo um exemplo do seu possível conteúdo apresentado na figura 3. Figura 3. Exemplo de conteúdos do diretório /data/data. Como é possível verificar e como descrito anteriormente, os ficheiros de cada aplicação são guardados com owners distintos, sendo assegurado através das permissões respetivas que apenas a aplicação em causa pode ler ou escrever nos seus próprios ficheiros (a não ser que o programador os tenha explicitamente exposto). Cada aplicação tem na diretoria /data/ data uma subdiretoria com o nome do seu package (um nome semelhante aos packages de Java, que identifica de forma única uma aplicação), que tem a liberdade de gerir da forma que entender. À semelhança de outros sistemas, os suportes de armazenamento externos são montados numa árvore de ficheiros comum através da operação de mounting. Os dispositivos mais comuns, os cartões SD, são montados em /mnt/sdcard. Um exemplo do conteúdo dessa diretoria é apresentado na figura 4. 8

Figura 4. Exemplo de conteúdos de um cartão SD. Como é possível verificar através das permissões atribuídas, qualquer utilizador pode ler os conteúdos do cartão. Isto faz do cartão de memória um local prático para depositar conteúdos que devem poder ser lidos por outras aplicações. No entanto, a escrita neste suporte está limitada ao grupo sdcard_r, que se traduz ao nível das aplicações na necessidade de uma permissão específica para tal (WRITE_EXTERNAL_STORAGE). Dada a atribuição dos ficheiros de sistema a um user ID próprio, é, em princípio, garantido que as aplicações instaladas não possam aceder aos mesmos de forma indevida. Um aspeto que reforça estas medidas de proteção é o facto de a imagem do sistema ser montada como só de leitura (read only). Todos os executáveis importantes e ficheiros de configuração estão localizados ou no ramdisk (que é também só de leitura, mas é reinicializado em cada arranque a partir de um estado conhecido) ou na imagem de sistema. Assim, um atacante que ganhe a habilidade de escrever em qualquer lado no sistema de ficheiros é ainda assim impedido de substituir ficheiros críticos. Um atacante poderia, ainda assim, aumentar a complexidade do ataque e remontar a imagem do sistema, ultrapassando essa limitação; no entanto, esta operação requer acesso root (o qual é explicado em detalhe na secção 2.4). 2.3.2. Encriptação A encriptação do sistema de ficheiros completo foi introduzida no Android na versão 3.0 da plataforma (Honeycomb). A encriptação é feita ao nível do kernel, usando a implementação do dm-crypt (um subsistema do kernel Linux para encriptação transparente do disco) de AES128 com CBC (Cipher Block Chaining) e ESSIV:SHA256 (Encrypted Salt-Sector Initialization Vector, usando SHA256 como função de hash). O ESSIV é um método criptográfico desenvolvido por Clemens Fruhwirth e integrado no kernel Linux desde a versão 2.6.10. Tem como objetivo obter o vetor de inicialização para o 9

método de CBC não só a partir de fontes previsíveis, como o número do setor do disco, mas também da hash da chave da encriptação. O vetor de inicialização (IV) é então dado por: Esta operação garante a imprevisibilidade dos vetores de inicialização, impedindo alguns tipos de ataques, como watermarking attacks. A chave do AES128 é derivada da password do utilizador (que pode ser definida para controlar o acesso às funcionalidades do dispositivo, com ou sem encriptação do sistema de ficheiros), prevenindo assim que um utilizador sem a password tenha acesso a dados guardados no dispositivo. O administrador do dispositivo (um conceito introduzido na versão 2.2 do Android) pode requerer o uso de uma password ou a concordância da password com algumas regras de complexidade. 2.4. Rooting de dispositivos Existe na comunidade Android, em particular nos utilizadores com menos conhecimentos técnicos, alguma confusão quanto ao conceito de rooting de um dispositivo móvel. Esta operação é muitas vezes confundida com a possibilidade de instalar imagens de sistema (normalmente denominadas de ROMs) modificadas, ativar funcionalidades bloqueadas como WiFi tethering ou fazer cópias de segurança das aplicações, ou instalar uma aplicação especial (como Superuser.apk). Apesar destas operações requererem efetivamente um dispositivo rooted, o termo rooting refere-se à obtenção de acesso root ao nível do kernel Linux, ganhando assim controlo completo sobre o software que corre no dispositivo. Analogamente a um sistema Linux num computador pessoal, ações que requerem acesso root, como montar e desmontar sistemas de ficheiros, correr servidores de HTTP ou SSH, terminar processos do sistema ou aceder a ficheiros de qualquer utilizador, requerem também acesso root no Android. As ROMs providenciadas pelos fabricantes não permitem, por norma, executar código arbitrário como root, oferecendo ao utilizador apenas controlo limitado sobre o sistema. Esta restrição é feita não só por questões de segurança, mas também para que as companhias de comunicações móveis possam colocar restrições no funcionamento do aparelho (por exemplo, impedindo a partilha da Internet móvel através de Wi-Fi). É, então, uma prática comum a exploração de vulnerabilidades existentes na plataforma Android com o objetivo final de fazer com que determinadas aplicações realizem o escalamento de privilégios, obtendo acesso root. Existem no Android três mecanismos de proteção que devem ser considerados: Bootloader e Recovery ADB Application Framework Nas próximas subsecções serão descritos em detalhe os três mecanismos. 2.4.1. Bootloader e Recovery O bootloader, à semelhança da BIOS nos computadores pessoais, é o primeiro bloco de código executado ao ligar o dispositivo, e está presente em qualquer dispositivo Android. 10

Este é responsável pelo arranque automático do Android OS ou, tipicamente indicado através de uma combinação específica de teclas premidas durante o arranque, aceder a um conjunto de opções do bootloader, entre os quais iniciar um programa de recuperação do sistema. O programa de recuperação do sistema (denominado recovery) é o segundo componente de baixo nível presente em qualquer dispositivo Android. É importante notar que é completamente independente, no entanto, do Android ou do Linux, estando localizado por vezes numa partição separada. É, de uma forma simples, um sistema operativo muito primitivo, onde o conceito de root não existe, que tem todo e qualquer controlo sobre o sistema e poderá realizar qualquer operação, se o código para tal estiver lá integrado. As funcionalidades implementadas do recovery por defeito variam com o fabricante; no entanto, operações comuns possíveis são a formatação da partição /data (repondo o estado de fábrica do aparelho) ou instalar uma ROM de atualização assinada digitalmente pelo próprio fabricante. Isto implica que, a não ser que a chave privada do fabricante seja comprometida, não é possível a instalação de ROMs modificadas nem obter, consequentemente, acesso root através desta via. Dado que o recovery se encontra armazenado também numa partição, como /data, /system ou /cache, uma aplicação com privilégios root pode substituir este programa por outros com funcionalidades muito mais alargadas (como o ClockworkMod Recovery, o recovery mais conhecido atualmente), que poderiam executar código com acesso total ao sistema. No entanto, é necessário para isso conseguir em primeiro lugar uma outra forma de obter acesso root. 2.4.2. ADB O ADB (Android Debug Bridge) é uma ferramenta para PC, Mac e Linux, criada pela Google, que permite a comunicação com um dispositivo Android ligado através de USB. Uma das operações possíveis é o lançamento de uma shell simples (executando o comando adb shell), onde o utilizador pode executar comandos no dispositivo usando uma interface familiar Unix (as figuras anteriores relativas ao sistema de ficheiros foram retiradas de uma instância dessa shell). A questão mais importante neste contexto é, obviamente, sob que utilizador são os comandos executados através deste método correm. Este depende de um valor de uma propriedade de sistema do Android, ro.secure. Esta é uma propriedade booleana: se ro.secure=0, o ADB executará os comandos com privilégios de root; caso ro.secure=1, estes serão executados como um utilizador sem privilégios. Como é de prever, a propriedade referida está, na maior parte dos dispositivos, definida de fábrica a 1. Esta é também uma propriedade não mutável, como é implicado pelo prefixo ro (read only). O seu valor constante é definido durante o arranque do sistema, a partir dos valores presentes no ficheiro default.prop na raiz do sistema de ficheiros que, por sua vez, é para lá copiado (também no arranque) de uma partição interna do dispositivo. Contudo, apenas é possível escrever na partição em causa com privilégios de root, o que torna este mecanismo seguro. 11

2.4.3. Application Framework Como já foi descrito na secção 2.2, todas as aplicações, com as quais o utilizador tem uma interação direta, são executadas em sandboxes como utilizadores sem privilégios sobre o resto do sistema. Como é óbvio, uma aplicação não privilegiada não pode iniciar uma outra aplicação com privilégios de root; o contrário, no entanto, é possível. Em Linux, a elevação dos privilégios de um programa é realizado através dos programas especiais su e sudo - os únicos que podem realizar a chamada do sistema setuid(0), que, como o nome dá a entender, permite mudar o utilizador que detém o programa para root (cujo UID é sempre 0). Aplicações que necessitam root são, na verdade, programas comuns que se limitam a executar outros programas através de su (como ficheiros executáveis empacotados com a própria aplicação). As ROMs incluídas nos dispositivos pelos fabricantes, sem surpresa, não providenciam o programa su na imagem do sistema. Também não é possível copiar simplesmente o programa para o sistema de ficheiros; é necessário que um bit especial, o SUID, esteja marcado, indicando ao sistema que o programa em causa pode escalar os seus privilégios durante a execução. Dado que este bit apenas pode ser marcado por uma aplicação com privilégios root, enquanto se verificar que todas as aplicações com as quais o utilizador pode interagir não têm esta capacidade, o sistema é imune a tentativas de escalamento de privilégios. 2.4.4. Contorno dos mecanismos de segurança Descritas as pontes entre a execução normal de aplicações e o acesso privilegiado existentes no Android e tendo sido mostrada a sua segurança em condições normais, é possível concluir que, para que possa ser feito efetivamente o rooting de um dispositivo, é necessária a exploração uma falha existente num dos três componentes acima. Uma vez obtido o acesso de root com um deles, é possível fazer com que qualquer um dos outros componentes possa ser usado para futuras operações com acesso root, como já descrito. No capítulo 5 são feitas algumas considerações sobre a segurança de cada mecanismo e são apresentados exploits concretos utilizados pelas ferramentas de rooting atuais. 12

3. Instalação de aplicações Qualquer aplicação instalada num sistema Android deve estar assinada por um certificado digital, em que o criador da aplicação detém a chave privada correspondente. Uma aplicação não assinada é rejeitada pelo próprio sistema Android ou pelo Android Market. Este certificado não é usado para controlar que aplicações pode o utilizador instalar; o seu propósito final é identificar o autor de uma aplicação e estabelecer relações de confiança entre as aplicações. Os certificados não precisam de ser assinados por uma autoridade de certificação. No sistema Android, é habitual que as aplicações tenham um certificado assinado pelo próprio criador. O sistema Android é suportado pelo Java Development Kit (JDK) e, no processo típico de assinatura de uma aplicação para o mesmo, estão envolvidos as ferramentas Keytool e Jarsigner. O Keytool é um administrador de certificados e chaves privadas. O Jarsigner é responsável por gerar assinaturas para pacotes Java (JAR) e verificar a integridade das assinaturas nesses mesmos ficheiros. Estas duas ferramentas são fundamentais no processo de assinatura de uma aplicação. Ao longo das secções referentes a este capítulo serão abordados os diferentes mecanismos envolvidos na assinatura da aplicação, o processo de assinatura nos dois modos permitidos (debug e release), as estratégias de assinatura e, por fim, os níveis de permissões que podem ser facultados numa aplicação relativamente à assinatura. 3.1. Assinatura da aplicação No Android, todas as aplicações devem estar assinadas por um certificado digital, que pode ser gerado pelo próprio utilizador através de um conjunto de utilidades providenciadas pelo JDK. Essas utilidades são o Keytool e o Jarsigner. Em versões anteriores do JDK, o Keytool e o Jarsigner estavam unificados numa única ferramenta, de nome Javakey. Em versões mais recentes do JDK esta ferramenta foi dividida em duas, que realizam tarefas distintas. Durante o desenvolvimento, as ferramentas referidas assinam automaticamente uma aplicação, como é explicado em detalhe na secção 3.2, não tendo o programador de se preocupar nesse sentido. No entanto, quando o criador pretende publicar a aplicação para que seja usada em outros dispositivos, deve providenciar a sua chave privada para efeitos de assinatura, ou, em alternativa, utilizar o Keytool para gerar uma chave privada. Após a definição das chaves, o Jarsigner é utilizado para assinar a aplicação Android. Em resumo, este processo envolve a geração de pares de chaves assimétricas (públicas e privadas), assim como de um certificado contendo a chave pública, e a assinatura criptográfica das aplicações. Nas próximas duas subsecções será descrito mais detalhadamente o papel de cada ferramenta na assinatura das aplicações Android. 3.1.1. Keytool O Keytool é uma ferramenta de administração de chaves e certificados. Permite aos 13

utilizadores gerir pares de chaves (públicas e privadas) e certificados associados e gerar certificados assinados por estas. O Keytool administra repositórios denominados keystores onde, tipicamente, para cada chave privada, está armazenada uma cadeia de certificados X.509 que autentica a correspondente chave pública. O Keytool trabalha sobre um repositório contido num único ficheiro, denominado keystore, onde estão armazenadas chaves e certificados. Normalmente, o tipo de chaves que são inseridas no keystore são chaves assimétricas, na forma da chave privada e uma cadeia de certificados para a respetiva chave publica. Este é o único tipo de chaves que o Keytool gere, apesar de o keystore possuir outras formas de armazenar e encriptar as chaves. Na keystore também é possível introduzir certificados de confiança, que indicam chaves públicas nas quais a ferramenta acredita (confia) corresponderem à entidade indicada. O Keytool permite aos seus utilizadores especificar o algoritmo para a geração dos pares de chaves. Se o utilizador não especificar nenhum algoritmo, o utilizado por defeito é o Digital Signature Algorithm (DSA). Quando as chaves são geradas por DSA devem ter um domínio compreendido entre 512 e 1024 bits, sendo sempre múltiplo de 64; o tamanho por defeito é 1024 bits. O RSA é outro algoritmo que pode ser usado para gerar pares de chaves. Após geradas as chaves, o algoritmo de assinatura é escolhido consoante o algoritmo usado anteriormente. Na presença de chaves DSA, o certificado é gerado usando DSA e SHA-1 como função de hash; se as chaves forem RSA, também o certificado usa RSA e a função de hash utilizada é MD5. O utilizador é livre de especificar que algoritmo pretende usar e também é livre de, se pretender, fornecer ao Keytool a sua chave privada pré-gerada, juntamente com um certificado compatível. 3.1.2. Jarsigner O Jarsigner é uma utilidade do JDK que utiliza as chaves e os certificados existentes numa keystore para assinar digitalmente ficheiros JAR. Este processo, entre outras operações, adiciona aos ficheiros JAR uma cópia do certificado autenticando a chave pública, que corresponde à chave privada usada para a assinatura. O Jarsigner apenas pode assinar ficheiros JAR que tenham sido gerados pelo JDK ou ficheiros.zip (que partilham o mesmo formato). Depois dos ficheiros estarem assinados digitalmente, o Jarsigner pode verificar a assinatura digital de cada ficheiro JAR acedendo ao bloco de assinatura do ficheiro. Este bloco contém um timestamp que permite verificar se o pacote Java foi assinado enquanto o certificado era válido. O Jarsigner utiliza um algoritmo de assinatura dependente do tipo de chaves a utilizar, da mesma forma que a criação dos certificados digitais. Se as chaves são DSA a ferramenta faz a assinatura por DSA, com o digest SHA-1. No caso das chaves serem RSA, a assinatura é feita com RSA, usando MD5 como função de hash. Quando um arquivo JAR é assinado este mantém-se inalterado, à exceção da adição de dois novos ficheiros: um com extensão.sf e um com extensão.dsa. O primeiro contém, para cada ficheiro contido no arquivo, o seu nome, o algoritmo de hashing utilizado e a hash desse ficheiro. O segundo ficheiro contém a cadeia de certificados contendo a chave pública respetiva. 14

Depois da utilização do Keytool para gerar os pares de chaves e do Jarsigner para assinar digitalmente as aplicações, o processo de assinatura termina. Apenas passando por este processo podem estas aplicações ser publicadas no Android Market. 3.1.3. Modos de assinatura Os processos descritos na secção anterior aplicam-se não só a aplicações Android, mas a qualquer arquivo Java que necessite de ser assinado digitalmente, sendo o processo tipicamente utilizado apenas para a versão final das aplicações. No caso específico do Android, cujas aplicações têm de ser assinadas para que a sua execução seja permitida, existem dois modos distintos de lançar a assinatura de uma aplicação: o modo debug e o modo release. O modo debug é utilizado para desenvolver e testar uma aplicação, para o programador poder facilmente e com um processo simples detetar os erros e defeitos existentes. Quando é feito build em modo debug, o SDK invoca o Keytool para criar automaticamente uma keystore apenas para debug. Cada vez que uma aplicação é compilada neste modo, o SDK utiliza essa keystore para assinar o pacote Java e o processo é todo feito de forma automática, usando configurações pré-definidas. O modo de release equivale a um processo típico de assinatura de aplicações Java, já descrito nas subsecções anteriores. 3.2. Estratégias de assinatura Quando um utilizador tenciona lançar múltiplas aplicações, é importante pensar nas metodologias usadas para a assinatura das aplicações. Poderá ser uma opção para os criadores assinar diferentes aplicações com diferentes chaves, com vista a reduzir os danos causados por um possível compromisso das chaves privadas (i.e. a perda de uma chave privada apenas compromete uma aplicação). No entanto, é recomendado pela Google que os programadores assinem todas as suas aplicações com o mesmo certificado, durante todo o ciclo de vida. Esta recomendação é feita pelos seguintes motivos: Atualização da aplicação: na presença de atualizações para as aplicações, enquanto estas mantiverem o mesmo certificado, é permitido que o processo de atualização seja feito automaticamente pelo sistema. Se o certificado seja diferente, é necessário dar um nome diferente aos pacotes e, tecnicamente, a atualização será tratada como uma aplicação distinta. Modularidade: O Android permite a aplicações com o mesmo certificado a possibilidade de partilharem o mesmo processo. Os criadores podem, caso utilizem o mesmo certificado, elaborar várias aplicações que funcionem como módulos de uma única aplicação geral. A vantagem nesta aproximação é a fácil atualização dos módulos em separado e o dinamismo inerente a esta arquitetura. Código e dados partilhados por permissão: O Android disponibiliza um nível de permissões ao nível da assinatura (abordado com mais detalhe na próxima subsecção), que permite que certas operações só sejam permitidas a aplicações assinadas pelo mesmo certificado que a aplicação que definiu as permissões em questão. 15

Durante a elaboração de uma aplicação, o criador terá então de ter em consideração o tempo de vida esperado, se se trata de uma aplicação independente ou parte de um conjunto de múltiplas aplicações que funcionam em conjunto e se pretende publicá-la no Android Market. Se o programador pretender fazer futuras atualizações a uma aplicação, deve garantir que o certificado associado tenha uma validade que ultrapasse o tempo de vida esperado da aplicação. Este cuidado garante que os utilizadores da aplicação terão uma experiência consistente na realização de atualizações. Se pretender realizar múltiplas e distintas aplicações com a mesma chave, então deve garantir que o certificado tenha uma validade que ultrapasse o ciclo de vida de todas as versões de todas as aplicações. Se o utilizador pretende publicar uma aplicação no Android Market, o seu certificado tem de ser válido, no mínimo, até 22 de outubro de 2033. Esta medida é tomada com vista a garantir a experiência consistente na atualização de aplicações referida anteriormente. 3.3. Permissões ao nível da assinatura No manifesto de uma aplicação Android é possível especificar um conjunto de atributos relativos à aplicação. Um desses atributos, designado protectionlevel, sugere o tipo de risco que uma aplicação apresenta e que permissões tem ao nível de acesso de recursos do sistema. Um dos valores deste atributo é a signature, este valor permite, que aplicações com o mesmo certificado, possam aceder a recursos uma da outra, sem previamente alertar o utilizador. 16

4. Comunicação entre processos e acesso a recursos Ao longo deste capítulo será analisada a segurança relativa à comunicação entre aplicações Android. Uma aplicação pode ser constituída por quatro tipos de componentes: Activities, Services, Broadcast Receivers e Content Providers. Cada um dos componentes possui diferentes pontos de entrada aos quais o sistema Android pode aceder; no entanto, nem todos os componentes são pontos de entrada para o utilizador. Cada tipo de componente tem um objetivo específico, funções distintas, e um ciclo de vida particular. Activity: todas as interfaces às quais o utilizador tem acesso numa aplicação são implementadas por Activities. Cada Activity representa uma ação singular e bem definida que o utilizador pode realizar. Por exemplo, uma aplicação de contactos poderá ter uma Activity para listar os contactos e uma outra para inserir um novo contacto. Service: um Service é um componente que corre em background no sistema para realizar operações de longa duração ou para comunicações remotas. Um serviço pode, por exemplo, reproduzir som em background enquanto o utilizador está a operar noutra aplicação. Broadcast Receivers: estes componentes respondem a broadcasts realizados por outras aplicações a todo o sistema Android. Um desses broadcasts será, por exemplo, um evento indicando que a bateria está muito fraca, permitindo às aplicações adotar comportamentos adequados à situação. Content Provider: um Content Provider administra um conjunto de dados partilhados por uma aplicação com outras aplicações, podendo os dados provir de uma base de dados local, da web ou de qualquer outro sistema de persistência. No Android existe, por exemplo, um Content Provider que gere as mensagens escritas guardadas. Um aspeto interessante do Android é o facto de qualquer aplicação poder iniciar um componente de outra aplicação. Por exemplo, se uma aplicação necessita de realizar uma chamada, esta pode chamar uma atividade (que, neste exemplo concreto, é um componente base do Android) que faça essa operação. Ao longo deste capítulo será detalhada como se processa esta comunicação entre componentes e como pode uma aplicação aceder a determinados recursos. 4.1. Comunicação entre processos O Android foi desenhado de forma a que a partilha de conteúdos entre aplicações seja um aspeto forte; as aplicações podem invocar funcionalidades implementadas e expostas por outras aplicações. Este aspeto da arquitetura do sistema ajuda a que não ocorra a necessidade de implementar aplicações repetidas (e.g. uma aplicação que, numa situação, necessite de enviar emails, pode utilizar aplicações já existentes e registadas para tal no sistema) e favorece o dinamismo e a eficiência, assim como a atualização independente de componentes (e.g. a aplicação do exemplo anterior, não tendo código específico de envio 17

de emails, beneficiaria da atualização do cliente de email pré-definido, mesmo que este fosse, por si só, uma aplicação independente). A comunicação entre processos é a chave para que tudo seja possível. Alguns dos mecanismos mais importantes implementados para o efeito são: Intents: permitem que uma aplicação identifique um componente (e.g. Activity, Service), ou uma ação que se pretende realizar e com que dados pretende operar. Os Intents funcionam como contentores de mensagens entre componentes, podendo ser passados nas duas direções, possibilitando ao programador pensar numa arquitetura de mais alto-nível. Binders: é um sistema similar ao mais conhecido sistema de remote procedure calls (RPC), que faz com que as API s sejam acedidas remotamente. Messengers: esta é uma alternativa simplificada à comunicação interprocessos em casos onde multithreading não é necessário. Não haveria necessidade do Android possuir o seu prórpio sistema de comunicação entre processos, no sistema Linux já existe um conjunto de mecanismos para o efeito. No entanto, essa decisão foi tomada dado que o Java foi desenhado de raiz com suporte a threads, e não processos, para fácil partilha de dados; foi considerado então complexo, neste contexto, a utilização destes mecanismos. Em adição, partilhar endereços de memória pode também levar à potencial exploração de vulnerabilidades e acesso a dados privados. Consequentemente, os modernos sistemas de programação, como o Android, têm movido para sistemas robustos baseado em componentes. Um aspeto importante a referir é que, em qualquer um dos mecanismos acima, o transporte de dados é sempre feito através de variáveis fortemente tipificadas e não através de mecanismos menos seguros, como streams; isto é algo que é reforçado pela linguagem Java, que não permite casts não seguros. Este aspeto, entre muitas outras vantagens trazidas pela tipificação forte nas linguagens de programação, dificulta a transferência e execução de código não autorizado. Nos próximas subsecções serão analisados com mais detalhe dois destes mecanismos de comunicação. 4.1.1 Intents Um Intent é um objeto que, como o nome indica, representa a intenção de iniciar um novo componente ou de realizar uma ação num componente já em execução, seja o componente da mesma aplicação ou de outra. No último caso são, por vezes, necessárias permissões específicas ao nível da aplicação para aceder a determinados componentes (um tema que será abordado com mais detalhe no próximo capítulo). Um Intent pode transportar tipos de dados simples (tipos de dados nativos do Java ou strings). Existem três componentes que são ativados por Intents: Activities, Services, e Broadcast Receivers. No caso dos Services e das Activities, o Intent pode ser ser explícito, indicando diretamente a classe a ativar (utilizados frequentemente entre componentes internos de uma aplicação) ou conter uma descrição abstrata da operação que pretende realizar (denominado ação), como por exemplo, realizar uma chamada (ACTION_CALL). Quanto ao Broadcast Receiver, o Intent apresenta uma descrição abstrata do evento que está a ser anunciado aos restantes componentes. 18

Os programadores podem declarar estaticamente no manifesto da aplicação - o ficheiro AndroidManifest.xml - Intent Filters, que especificam o tipo de Intents a que um componente pode responder. O Intent Filter declara as funcionalidades de um componente, isto é, que ações é que o componente pode realizar e que tipo de Broadcast Receivers são administrados. 4.1.2 Binders Os Binders são objetos remotos trocados através de um mecanismo leve de RPC (remote procedure call) desenhado para obter alta performance, quer quando utilizado entre componentes do mesmo processo, quer entre processos de diferentes aplicações. As transições realizadas com estes objetos são sincronas, de tal forma que apenas podem existir transições caso estes objetos estejam disponíveis. Este tipo de comportamento é aplicado a objetos de processos locais ou a objetos de um processo externo a aplicação. Nestas transições, os dados trocados entre os processos são designados de Parcels. Estes são buffers de dados genéricos que contêm um conjunto de meta informação sobre o seu conteúdo. O propósito desta informação é administrar as referências dos Binders existentes no buffer, de forma a que essas referências se mantenham quando o buffer é transmitido entre processos. Este mecanismo assegura que, quando um Binder é escrito num Parcel e enviado para outro processo, numa possível resposta, o Binder enviado de volta é exatamente o mesmo. A maior parte dos programadores em Android não implementa Binders diretamente (i.e. implementando a classe respetiva); optam por utilizar uma linguagem de descrição de interfaces específico do Android, o Android Interface Definition Language (AIDL), para descrever as interfaces de comunicação desejadas. O AIDL permite que um cliente e um servidor definam uma interface de programação e possam comunicar entre si. Para tal, é necessário que as aplicações e os servidores possam decompor os seus objetos em primitivas, de forma que a estrutura dos dados seja compreensível a ambos. Cumprindo este requisito, é possível serializar os objetos para poderem ser posteriormente enviados através de RPC. Apenas é necessário providenciar uma especificação AIDL se o criador da aplicação pretender permitir que clientes de diferentes aplicações tenham acesso aos seus serviços e quiser suportar multithreading. 19

5. Autorização de operações Quando uma aplicação pretende aceder a determinados recursos protegidos do sistema Android, é necessário que sejam requisitadas permissões adequadas para o efeito. Essas requisições de permissões devem ser declaradas no manifesto da aplicação - um ficheiro de controlo, uma espécie de contrato com o sistema, que indica e descreve todos os componentes existentes na aplicação. O sistema Android é constituído por um conjunto de APIs que permitem realizar operações sobre hardware, como GPS, Camera, Phone ou SMS. Para aceder a esses recursos é necessário declará-los estaticamente no manifesto da aplicação (o ficheiro AndroidManifest.xml), de forma a que, no momento em que o utilizador instale a aplicação, saiba que tipo de funções ou APIS a aplicação pretende aceder e se o utilizador, após uma profunda ponderação, considera essas permissões legítimas. Ao longo das próximas secções é abordado o funcionamento deste modelo de permissões e como aceder às APIs. É também mostrado como é que o sistema Android tenta, de forma clara e concisa, mostrar aos utilizadores que permissões determinada aplicação requer e garantir que estes vão ler e entender o que a aplicação pretende utilizar no sistema. Por fim, será abordado como é gerida a informação pessoal presente no sistema Android e que mecanismos de acesso se podem ativar para impedir o acesso por aplicações não autorizadas. 5.1. Modelo de permissões O modelo de permissões de sistema Android controla o acesso das aplicações a determinados recursos no sistema. O propósito deste modelo é restringir as capacidades das aplicações ao que estas realmente necessitam, seguindo o princípio dos privilégios mínimos. Dentro das APIs a que as aplicações podem aceder encontram-se: Câmera: fornece acesso à câmera do telemóvel, oferecendo funcionalidades como gravar um vídeo ou tirar uma ou múltiplas fotos. GPS: o GPS (Global Positioning System) permite identificar em que posição do globo se encontra o dispositivo, podendo fornecer informação sobre a nossa altitude, latitude e longitude. Bluetooth: permite aceder às funcionalidades do rádio Bluetooth, como ligar ou desligar esta ligação, ou ainda enviar e receber ficheiros através dela. Telefone: fornece acesso às diversas funcionalidades do telefone, como realizar chamadas ou atendê-las. SMS/MMS: permite enviar e ler mensagens escritas disponíveis na memória do telefone. Conetividade: esta API é relativa à gestão das ligações de dados existentes no telemóvel, como Wi-Fi e 3G. Estas APIs foram descritas de uma forma bastante sucienta e esta lista não é, de todo, 20

extensiva. Apresentando um exemplo, podemos considerar um utilizador que pretende aceder à funcionalidade de envio de mensagens. Para isso, tem de declarar no manifesto da aplicação a permissão android.permission.send_sms para que a operação seja permitida. Cada API fornece um conjunto de funcionalidades, tendo as permissões uma granularidade bastante baixa, como é possível verificar na figura 5. Figura 5. Exemplo de um ficheiro AndroidManifest.xml. Caso algum programador não declare uma permissão para aceder a uma funcionalidade de uma determinada API, a tentativa de acesso a essa funcionalidade poderá não surtir qualquer efeito ou mesmo resultar numa exceção de segurança. 5.2. Concessão explícita de permissões Quando um utilizador faz download de uma aplicação e posteriormente a instala no Android, aparece no processo de instalação um diálogo onde é apresentado o tipo de recursos a que essa aplicação pretende aceder. 21

Figura 6. Exemplo de um ecrã de instalação. O diálogo está ilustrado na figura 6, onde é discriminado a que tipo de permissões a aplicação pretende aceder. Um utilizador, após conceder estas permissões, não volta a ser questionado sobre as mesmas. Através do gestor de aplicações do Android um utilizador pode consultar que aplicações tem instaladas e verificar em qualquer altura as permissões concedidas a uma aplicação. É de notar que novas permissões não podem ser dinamicamente concedidas a uma aplicação. As permissões devem ser aceites durante a instalação e serão essas permissões que a aplicação terá até ser desinstalada ou atualizada. Uma atualização que mantenha as permissões da versão anterior pode ser feita de forma automática pelo sistema; no entanto, uma aplicação que mude o conjunto de permissões requerido passa obrigatoriamente pelo diálogo apresentado acima, para que o utilizador reveja as alterações. A revisão consciente das permissões pedidas por uma aplicação é de vital importância na manutenção da segurança do sistema, dado que qualquer aplicação pode ter um impacto negativo para o utilizador, se possuir permissões para tal. O utilizador pode contar com a informação do Android Market, onde pode verificar o feedback presente nos comentários de outros utilizadores sobre uma dada aplicação. Dessa forma, pode ter uma maior consciência de outras opiniões e experiências quando pretende instalar uma aplicação. 5.3. Permissões de acesso a informação pessoal Das permissões apresentadas acima, algumas em especial merecem destaque e alguma informação adicional. Estas são as permissões que permitem o acesso a informação sensível do utilizador ou do dispositivo. 22

Figura 7. Acesso a informação pessoal. Existe um conjunto de Content Providers que fornecem acesso a informação pessoal e sensível dos utilizadores que usam o Android. Exemplos disso são os contatos, eventos no calendário e mensagens que, tal como presente na figura 7, estão protegidos pelo mecanismo de permissões. Dado que existe uma permissão direta para cada uma destas informações pessoais (i.e. dado que a granularidade indicada é tão baixa), torna-se simples e fácil para o utilizador perceber a que tipo de informações uma aplicação pretende aceder. 23

6. Problemas e vulnerabilidades Como em qualquer sistema de média ou grande dimensão, uma plataforma como o Android está sujeita à existência de bugs e falhas de segurança, que introduzem vulnerabilidades. Em particular, a fácil instalação de aplicações da autoria de qualquer utilizador e o acesso integrado à Internet potencia a descoberta e exploração dessas vulnerabilidades. Neste capítulo pretende-se dar a conhecer quais são os componentes do sistema passíveis de ser atacados e alguns exemplos de vulnerabilidades descobertas ao longo do tempo. 6.1. Fraquezas no sistema Os casos de pontos fracos nesta secção descritos não pretendem ser, de forma alguma, uma lista completa dos aspetos inseguros do Android. Como na maior parte dos sistemas informáticos, a existência de vulnerabilidades não é algo previsível, e o bom senso deve sempre existir na utilização de um dispositivo móvel. 6.1.1. Má utilização de permissões A má utilização das permissões autorizadas será talvez uma dos pontos mais suscetíveis de ataque ao Android. Não se trata de um bug ou vulnerabilidade no sistema, mas sim da forma como o mecanismo de permissões foi desenhado; nada impede uma aplicação de requisitar permissões e nada impede o utilizador de as aprovar; no entanto, nada garante que a aplicação as use só para as funcionalidades publicitadas. Exemplificando, uma aplicação de gestão de mensagens escritas poderá requisitar permissões para a leitura, escrita e envio de mensagens (READ_SMS, WRITE_SMS, SEND_SMS) e poderá ainda requisitar CALL_PHONE caso queira, por exemplo, um botão para telefonar diretamente ao remetente das mensagens. Nestas condições, não existe forma de garantir que a aplicação enviará mensagens ou fará chamadas unicamente quando o utilizador clica no controlo associado na interface. Uma aplicação mal intencionada poderá então levar utilizadores a serem vítimas de toll fraud. Na altura da instalação, o Android responsabiliza o utilizador pelos privilégios que cada aplicação terá. É de importância fulcral que o utilizador leia a lista das permissões requisitadas pelas aplicações com a máxima atenção e procure compreender a razão do pedido de todas. No entanto, mesmo com esse cuidado, é recomendado bom senso na instalação de aplicações de autores não conhecidos, à semelhança dos computadores pessoais. 6.1.2. Escalamento de privilégios Entende-se por escalamento de privilégios o ato de explorar um bug, uma falha de desenho, ou uma má configuração no sistema operativo ou numa aplicação com o objetivo de ganhar acesso a recursos que, em condições normais, estariam vedados. Um escalamento bem sucedido resulta numa aplicação com mais privilégios do que os pretendidos pelo administrador, o que pode levar à execução de operações não autorizadas. No Android, o escalamento de privilégios está normalmente associado à obtenção de acesso root no sistema. Uma explicação detalhada dos componentes do Android passíveis de ser atacados encontra-se na secção 2.4. 24

Se o dispositivo tiver um bootloader e recovery desbloqueado (i.e. que permita a instalação de ROMs modificadas), o processo é bastante direto - um utilizador poderia fazer dump da imagem do sistema, adicionar-lhe o su, empacotá-la de novo e instalar no dispostivo a nova ROM. O processo é ainda mais simples se o dispositivo não possuir originalmente a flag ro.secure a 1 (são raros os casos, mas existem). Através do ADB pode obter-se uma shell com privilégios de root. A partir de lá, é possível montar a partição /system com acesso de leitura e escrita, e bastaria de seguida copiar o su para a mesma. O caso mais complexo acontece quando os dois componentes acima estão devidamente protegidos. Nesse caso, a solução passa pelo facto de um conjunto limitado de serviços de baixo nível do sistema necessitam, mesmo no Android, de correr com privilégios de root, de forma a poder controlar sem restrições o acesso ao hardware. A lista dos processos em execução com privilégios root num dado momento pode ser consultada facilmente através de uma shell. Figura 8. Lista de processos iniciados diretamente pelo processo init (tendo todos eles privilégios root). De notar que esta lista não apresenta todos os processos ativos com root. O objetivo seria, então, fazer com que um desses processos execute código arbitrário fornecido pelo utilizador. Este é o método de funcionamento de todas as ferramentas de one-click-root existentes na Internet, sendo o código arbitrário quase sempre um pedaço de código que monta /system em modo de escrita e instala uma cópia permanente de su, para que as futuras operações elevadas não necessitem de passar por todo o processo. Sendo o Android, assim como o Linux, uma plataforma aberta, os hackers limitam-se a navegar pelo código fonte dos vários serviços de sistema até encontrar uma falha que os permita escalar processos. A Google tem vindo a corrigir todas essas falhas quando são descobertas; no entanto, como em qualquer outro sistema informático, novas falhas exploráveis vão sempre aparecendo num sistema que seja regularmente atualizado, como é o caso do Android. É importante notar que, apesar de fazer rooting de um dispositivo ser normalmente 25

considerado uma operação benéfica (e, na realidade, traz muitas vantagens e liberdade ao utilizador), abre também um buraco na sua segurança, permitindo a aplicações maliciosas controlo completo sobre o sistema, pelo que o utilizador deve ter completa noção dos riscos associados. 6.1.3. Contorno do mecanismo de permissões Como foi descrito no capítulo 5, a instalação de aplicações está sujeita a um mecanismo de permissões que apresenta ao utilizador uma mensagem de confirmação. No entanto, o processo interno de instalação de aplicações não é representativo dessa segurança. É importante percebê-lo para perceber como pode representar uma fraqueza. Figura 9. Processo de instalação de aplicações percecionado pelo utilizador: procurar, instalar, aprovar e utilizar. Figura 10. Processo interno de instalação de aplicações. A figura 10 mostra as interações entre componentes necessárias na instalação de uma aplicação: 1. utilizador requisita a instalação e aprova as permissões da aplicação; 2. A aplicação do Market faz POST do pedido para os servidores da Google; 3. O Market informa o serviço C2DM (de push messages) do pedido; 4. O servidor faz push de uma mensagem INSTALL_ASSET para o dispositivo; 5. O GTalkService recebe a mensagem (o protocolo de push messages do Android 26

utiliza o protocolo XMPP do GTalk; o processo não está unicamente associado ao serviço de IM da Google); 27

6. O componente de vending do dispositivo vai buscar o pacote.apk e instala-o. Analisando este conjunto de passos, é possível notar que existe uma discontinuidade na responsabilidade dos componentes; é a aplicação do Market que força a aprovação das permissões, mas é o GTalkService que causa a instalação da aplicação. Um de dois ataques pode surgir daqui: Imitar o pedido realizado no passo 2; Fabricar e enviar uma mensagem INSTALL_ASSET para o dispositivo. A primeira opção é, aparentemente, mais acessível, dado que o utilizador não tem, em princípio, o endereço C2DM do dispositivo (este não é estático) nem consegue facilmente fazer-se passar pelo C2DM Service, dada a sua origem na rede. 6.1.4. Persistência de aplicações Aplicações maliciosas, à semelhança de vírus e worms nos computadores pessoais, podem instalar-se a elas mesmo em locais protegidos ou modificar os componentes do sistema que permitem a desinstalação de aplicações, considerando que ganham antes permissões para tal (root). Atualmente, este ainda não é um ataque comummente utilizado pelo malware, talvez porque fazer patches para todos os componentes que permitem a desinstalação de aplicações envolve um esforço considerável. No entanto, é sem dúvida um ataque a considerar no futuro. 6.1.5. Considerações gerais Sendo o Android um sistema operativo completo e semelhante, em vários aspetos, a complutadores pessoais, sofre também de muitos pontos fracos não específicos da plataforma, como: Limites de CPU e RAM: apesar de o kernel tratar de balançar o uso dos recursos computacionais entre aplicações, as aplicações não possuem quotas de RAM ou armazenamento. Podem também monopolizar o CPU. Navegação na Web: possuindo capacidades de navegação rica na web, o Android fica sujeito a ataques destinados a browsers típicos, como cross-site scripting (XSS), url encoding attacks e scripts maliciosos. Injeção de SQL: o SQLite é o sistema de gestão de bases de dados relacionais mais usado no Android, dado que este integra um módulo de acesso a estas bases de dados. No entanto, a API fornecida por esse módulo, não obstante ser de fácil utilização, é relativamente simplificada, não fazendo verificações de carateres especiais nos parâmetros. A prevenção de SQL injection attacks deve ser implementada do lado do cliente. Conetividade: os dispositivos móveis possuem um número consideravelmente superior de métodos de comunicação com outros dispositivos em relação aos computadores pessoais. Isto traduz-se, em termos de segurança, em mais formas para o malware se infiltrar no sistema. 6.2. Exemplos de vulnerabilidades São de seguida apresentados exemplos concretos de vulnerabilidades, já corrigidas ou não, do Android. As descrições pretendem ser um resumo muito geral; explicações mais técnicas e detalhadas podem ser encontradas nas referências. 28

6.2.1. Ferramentas de rooting Existem variadas ferramentas disponíveis na Internet que permitem o rooting de um dispositivo Android - grande parte delas ainda funcionais. Exploid e GingerBreak A base do funcionamento do Exploid e do GingerBreak é a exploração de um bug já existente no Linux no componente udev, em que este não verifica se uma mensagem NETLINK provém do kernel ou do user space (identificada no CVE - Common Vulberabilities and Exposures - com o identificador CVE-2009-1185). Uma dessas mensagens pode fazer com que o daemon init leia os conteúdos de /proc/sys/kernel/hotplug e escreva em data. Através de um uso inteligente de symlinks, o Exploid faz, no final, a invocação de hotplug leve à execução elevada do seu próprio código. O GingerBreak usa o NETLINK para explorar uma vulnerabilidade do processo vold. A sua compreensão exige uma análise de muito mais baixo nível que o anterior. Em linhas gerais, a não verificação de um índice negativo num parâmetro passado na mensagem NETLINK pode levar à execução de código arbitrário. RageAgainstTheCage e ZimperLich O RageAgainstTheCage causa a execução da shell do ADB com privilégios de root. A vulnerabilidade explorada é uma de uso geral nas tentativas de elevação de privilégios. Num bloco de código com esta forma geral: /* Code intended to run with elevated privileges */ do_stuff_as_privileged(); /* Drop privileges to unprivileged user */ setuid(uid); /* Code intended to run with lower privileges */ do_stuff_as_unprivileged(); É necessário garantir (ou, pelo menos, verificar) que a chamada a setuid é bem sucedida. Retirando de man setuid: RLIMIT_NPROC The maximum number of processes (or, more precisely on Linux, threads) that can be created for the real user ID of the calling process. Upon encountering this limit, fork(2) fails with the error EAGAIN. O daemon do ADB, que corre no dispositivo, falha precisamente essa verificação ao descer os privilégios do processo para o utilizador não privilegiado da shell. O RageAgainstTheCage limita-se a fazer fork() até ao limite de processos do utilizador shell, terminar e reiniciar o processo adb. O ZimperLich explora também essa falha, mas no processo zygote (a Dalvik Virutal Machine, que executa o código de todas as aplicações não nativas). 29

KillingInTheNameOf O KillingInTheNameOf faz uso do comando ashmem, que permite o mapeamento das propriedades do sistema para endereços de mémória. O mapeamento pode ser feito, erroneamente, com permissões de escrita, pelo que é possível alterar a flag ro.secure para 0. 6.2.2. Contorno do mecanismo de permissões No contexto do processo interno de instalação de aplicações apresentado na subsecção 6.1.3, Jon Oberheide, cofundador da startup de segurança de sistemas Duo Security, descobriu em novembro de 2010 uma vulnerabilidade, entretanto corrigida. Uma análise às comunicações efetuadas entre a aplicação do Market no dispositivo e o servidor - capturadas através de ferramentas no dispositivo, provavelmente requerendo acesso root, ou através do router ou gateway de ligação à Internet - permite facilmente dissecar as mensagens trocadas (codificadas através de Protocol Buffers, um formato de troca de dados da Google). Estas contêm um número extenso de parâmetros miscelâneos, como o idioma ou o operador de comunicações, e um authentication token, (aparentemente) mais difícil de obter. Figura 11. Formato de uma mensagem da aplicação do Market para o servidor. Este token, não é, no entanto, completamente privado para o utilizador; este pode ser requisitado a um serviço do sistema, o AccountManager, através da própria framework, caso a aplicação detenha a permissão USE_CREDENTIALS. Em suma, uma aplicação com esta permissão pode, então, forjar uma mensagem de instalação de qualquer outra aplicação, ultrapassando a aprovação explícita das permissões pelo utilizador, quaisquer que sejam elas. Esta situação representa uma falha no sistema que viola o princípio de atenuação de privilégios - é possível que uma aplicação cause a instalação de outras com 30

permissões que não possui. Foi criada uma aplicação exemplo para mostrar a falha. A aplicação, disfarçada de uma expansão de um jogo conhecido, instala três aplicações com permissões perigosas sem o conhecimento do utilizador. Figura 12. Screenshots da aplicação de contorno de permissões. 31