3.4 Primitivas de Segurança
3.4.6 Controlo de Acessos
Para além das capacidades já disponíveis no Docker e no núcleo Linux, é possível proteger ainda mais um contentor através da implementação de ferramenta adicionais de controlo de acessos, como o SELinux e AppArmor.
O SELinux permite controlar o nível de acesso ao núcleo do sistema hospedeiro baseado no tipo de processo a correr no contentor ou no nível de privilégios do mesmo [13]. De uma forma simples, o SELinux é uma camada extra de segurança, que adiciona mais um nível de verificação ao processo de controlo de acessos. Não é nada mais que uma flag adicional conferida a um recurso, processo ou ficheiro para além das normais Read-Write-Execute (RWE). Para um contentor tirar partido do SELinux este tem que primeiro estar disponível no hospedeiro.
O AppArmor anexa um perfil a cada processo que corre no hospedeiro. Este perfil define, em tempo de execução, que recursos esse processo pode utilizar como a quantidade de memória ou núcleos do processador disponíveis. Pode ser visto como um mecanismo mais simples em comparação com o SELinux e seccomp, embora também menos eficiente [13].
CAPÍTULO
4
Ameaças em Contentores
Para as empresas e organizações que utilizam contentores, ou que implementam plataformas como serviços, a segurança em contentores é quase sempre uma prioridade. Isto é de esperar, visto que estas tecnologias são algo recentes e relativamente imaturas em comparação com a virtualização com recurso a hipervisores. Os riscos associados à partilha do núcleo do sistema operativo não podem ser ignorados ou menosprezados.
Os contentores são alvo de uma panóplia de ameaças, podendo ter origem em más configurações, má utilização, ou problemas mais profundos, como falhas no sistema operativo partilhado e consequentes subsistemas. Neste capítulo, serão analisadas e expostas as causas concretas destas vulnerabilidades, assim como os resultados da sua exploração.
Para sensibilizar o leitor para a severidade destas falhas, serão apresentadas algumas provas de conceito, em que são exploradas falhas em contentores vulneráveis. De salientar que maior parte dessas vulnerabilidades estão agora corrigidas, mas que até essa altura eram desconhecidas. É fácil desapreciar a severidade destas vulnerabilidades, mas a realidade é que, até estarem corrigidas, muitos sistemas e contentores podem ter sido – e certamente foram – comprometidos.
4.1 Vulnerabilidades do Linux
Ao contrário das máquinas virtuais tradicionais, que têm uma faixa de hardware virtualizado para separar os sistemas em funcionamento, os contentores apenas contam com uma fina camada providenciada pelo núcleo do sistema Linux. Este aspeto, que torna os contentores tão leves e portáveis, gera também problemas de segurança profundos. Quase semanalmente, são descobertas novas vulnerabilidades no Linux que afetam vários sistemas que utilizam o núcleo deste sistema operativo, como é o caso de dispositivos móveis com sistemas embebidos. Estas vulnerabilidades são normalmente exploradas para realizar jailbreaking em aparelhos como telemóveis ou televisões que são vendidos quase sempre com o sistema operativo trancado, sem privilégios elevados, e com funcionalidades reduzidas. O jailbreaking, que consiste na fuga
de dentro de um sistema isolado, resulta, normalmente, na obtenção do controlo total sobre o sistema. Em contentores é normalmente chamado de breakout.
Das cerca de 400 syscalls disponibilizadas pelo Linux, um número elevado contém vul- nerabilidades que resultam quase sempre em aumento de privilégios e execução remota de código, como o caso do mremap, unmap e splice. Outros problemas têm, no entanto, origem em código antigo, obsoleto e descontinuado, que inclui funções como SCTP, IPX, AppleTalk e NETLINK, tendo estes contribuído para vários casos de aumento de privilégios. Um exemplo histórico de falhas é o subsistema responsável pela monitorizaram de desempenho perf, que consistentemente é alvo de vulnerabilidades, como a CVE-2013-20941 [16].
Figura 4.1: Excerto de um email do criador do Linux, Linus Torvalds.
Grande parte da culpa pela segurança menos desejável do núcleo Linux vai para a própria equipa de desenvolvimento, que tem bastante má reputação no que toca a priorizar problemas de segurança2. À medida que os desenvolvedores adicionam novas funcionalidades ao Linux, também aumentam a sua complexidade e superfície de ataque. O próprio criador do Linux, Linus Torvalds, tem opiniões que, muitas vezes, vão contra os princípios fundamentais de segurança, chegando até ao ponto de afirmar que os especialistas de segurança são malucos, e que os bugs de segurança são menos importantes que os bugs normais [28].
4.1.1 User namespaces
Os user namespaces são uma funcionalidade adicionada recentemente e o exemplo perfeito, pelas piores razões, da introdução inadvertida de vulnerabilidades no núcleo Linux. Um componente que tinha o objetivo de reduzir os privilégios num contentor e aumentar a sua segurança, teve o efeito completamente oposto. Enquanto que, quando usados corretamente, a eficácia dos user namespaces é evidente, a presença de uma vulnerabilidade neste componente resulta quase sempre num ataque de aumento de privilégios. A introdução destas vulnera-
1https://nvd.nist.gov/vuln/detail/CVE-2013-2094 2https://lwn.net/Articles/313765/
bilidades é, provavelmente, o resultado do desenvolvimento desta funcionalidade como um
“add-on” para os namespaces originais, em vez de ter sido desenvolvido desde o início.
Apesar da sua recente implementação, já foram descobertas várias vulnerabilidades, quase sempre relacionadas unicamente com os user namespaces. Estas vulnerabilidades são ex- ploradas na maior parte das vezes por ataques locais, imagens envenenadas ou aplicações comprometidas. Um exemplo de uma vulnerabilidade é a CVE-2013-19593, presente direta- mente nos namespaces do núcleo Linux. Esta vulnerabilidade permite o aumento de privilégios de um utilizador através da movimentação de um ficheiro entre um processo não privilegiado e um processo privilegiado. Embora agora corrigida, uma prova de conceito pode ser encontrada facilmente4.
4.1.2 Container Runtime
Os container runtimes não fazem propriamente parte do núcleo do Linux, mas como são utilizados para lançar os contentores ao nível mais baixo, foram também incluídos neste tópico. Os runtimes de alto nível, como o Docker, comunicam com estes runtimes de mais baixo nível, que são responsáveis por gerir e interligar todos os componentes do núcleo necessários à execução de um contentor e, por isso, interagem diretamente com o núcleo Linux.
Apesar de serem desenvolvidos com segurança em mente, como é o caso do runC, têm sido regularmente alvo de falhas e vulnerabilidades. Um exemplo destas vulnerabilidades é a CVE- 2019-57365, que permite a um ator malicioso reescrever o ficheiro binário do runC presente no hospedeiro, levando assim a um ataque de aumento de privilégios. Esta vulnerabilidade irá ser explorada num capítulo seguinte, para ganhar controlo total sobre o contentor e estabelecer uma presença douradora no mesmo. Por serem de tão baixo nível, tornam-se extremamente difíceis de detetar, para além de resultarem quase sempre na execução remota de código.
4.2 Recursos Comprometidos
Para um atacante conseguir cumprir com o seu objetivo, seja ele distúrbio de serviços ou obtenção de informação, tem primeiro de tomar controlo de um contentor. Após conseguir acesso privilegiado, pode então tentar atacar outros contentores, o hospedeiro ou mesmo tentar escapar do próprio contentor. Este tipo de ataques tem origem normalmente não em falhas do próprio contentor ou do núcleo do Linux, mas sim em recursos comprometidos, como vulnerabilidades nas aplicações utilizadas ou imagens envenenadas.
A obtenção do controlo do contentor é um passo importante, e muitas vezes necessário, para realizar um ataque bem-sucedido, ao permitir obter uma permanência duradoura no sistema e possibilitar o lançamento de uma reverse shell (aprofundado no capítulo 5). Adicionalmente, pode dar ao atacante a possibilidade de utilizar o contentor comprometido como pivot, para lançar ataques e comprometer sistemas vizinhos, e para realizar banner grabbing e
fingerprinting (obter informação sobre software, protocolos, sistemas operativos e até mesmo hardware através da análise de serviços e portas abertas no sistema e na rede).
3https://nvd.nist.gov/vuln/detail/CVE-2013-1959 4https://pastebin.com/8vQnNtfZ
4.2.1 Aplicações Vulneráveis
Uma das principais causas da presença de vulnerabilidades nas aplicações é a utilização de versões não atualizadas ou obsoletas, em que falhas descobertas ainda não estão corrigidas. Estas vulnerabilidades permitem ao atacante ganhar controlo sobre o contentor sem ter de realizar nenhum ataque adicional, ou pior, se a aplicação que estiver comprometida tiver privilégios elevados.
Outro problema é a utilização de imagens intencionalmente comprometidas pelos atacantes, uma realidade cada vez mais presente, numa altura em que se assiste a um aumento de projetos completamente open-source, baseados no GitHub, em que atacantes podem fazer contribuições de código maliciosas.
As aplicações que estão contidas nos contentores não introduzem necessariamente novas vulnerabilidades, mas são um vetor adicional de ataque. Este vetor de ataque é essencialmente um dos meios de eleição para atacar contentores. Ao comprometer um contentor que contenha uma aplicação vulnerável, torna-se trivial atacar outros sistemas que disponham de uma configuração idêntica ou a mesma combinação de versão do contentor e aplicação.
4.2.2 Imagens envenenadas
Um problema mais profundo é o caso da utilização de imagens envenenadas. Estas imagens contêm intencionalmente vulnerabilidades, ou backdoors, que são difíceis – ou até mesmo impossíveis – de detetar. A maior parte dos utilizadores descarrega e utiliza imagens de fontes desconhecidas, sem se questionar sobre a origem ou fiabilidade destas, colocando os seus contentores e infraestruturas à mercê do atacante. Mesmo os profissionais mais experientes que apenas utilizam imagens de fontes oficias, e que realizam verificações de integridade, não estão livres deste problema.
Figura 4.2: Excerto das imagens mais descarregadas.
Jerry Gamblin, um engenheiro de cibersegurança a trabalhar para a Kenna Security, uma empresa de segurança norte americana, realizou uma análise [41] sobre as 1.000 imagens de contentores Docker mais populares e fez uma descoberta surpreendente. As imagens oficiais mais descarregadas estavam repletas de vulnerabilidades, chegando por vezes às centenas, como por exemplo as imagens oficiais da Microsoft para ASP.NET.
Muitas das imagens descarregadas continham a vulnerabilidade crítica CVE-2019-50216, em que uma distribuição oficial do Alpine Linux incluía uma password com valor NULL para o utilizador root, o que permitia obter controlo total sobre o contentor.
4.3 Problemas de Configuração
A fuga de um contentor é provavelmente o pior cenário em termos de segurança. Embora as vulnerabilidades discutidas anteriormente contribuam para a fuga de dentro de um contentor, é quase sempre necessária uma falha adicional. Esta falha manifesta-se na maior parte das vezes como erros de configuração do contentor, como isolamento impróprio, capacidades em excesso e configuração de rede fracas.
Na realidade, este ataque não necessita de utilizar diretamente vulnerabilidades. A falta de configuração de um contentor pode ser suficiente para atacar o hospedeiro ou outros sistemas na mesma rede local que estejam mais propícios a conter vulnerabilidades. A captura de pacotes da rede que contenham credenciais para outro contentor ou base de dados é um exemplo de uma fuga de contentor, sem ser necessário explorar diretamente uma falha.
4.3.1 Isolamento Impróprio
Quando devidamente configurados, os user namespaces eliminam por completo a maioria das ameaças a contentores. No entanto, e devido às vulnerabilidades inerentes a esta componente, é recomendado a utilização em conjunto com um mecanismo de acesso obrigatório, como é o caso do SELinux e Apparmor. Por outro lado, a falta de configuração de user namespaces remove por completo a maioria do robustecimento e proteções implementadas no contentor. Um contentor com definições inseguras por omissão, ou que está mal – ou inseguramente – configurado por um administrador, tem uma grande probabilidade de expor vulnerabilidades que facilitam ataques e consequentes fugas do contentor. Estas podem ir desde permitir privilégios elevados ou fracas restrições de cgroups, até à exposição de informação do sistema hospedeiro. Por exemplo, restrições fracas de cgroups podem facilitar o acesso ao disco físico do sistema através da syscall mknod (que serve para criar ficheiros que representam dispositivos), mesmo com user namespaces.
4.3.2 Capacidades em Excesso
Uma das formas mais fáceis de permitir a fuga de um contentor é permitir a utilização de capacidades privilegiadas, ou em excesso, como a sys_admin. Esta capacidade é extremamente poderosa e perigosa, porque é considerada como a capacidade “catch all” do núcleo Linux. À medida que se adicionam novas funcionalidades, estas vão sendo inseridas numa das 32 capacidades nativas do Linux. No entanto, quando não existe uma capacidade ideal onde ser colada, é simplesmente adicionada a esta “catch all”.
A capacidade net_raw é um exemplo concreto que, quando usada indevidamente, permite realizar ataques à rede. Esta operação está disponível por omissão em todas as plataformas de contentorização, devido a ser necessária para a utilização do comando ping. Muitas capacidades bastante poderosas continuam disponíveis por omissão, devido à presumível falta de ameaça (uma funcionalidade sem ameaça não é uma vulnerabilidade, porque não gera risco).