Milhões de binários depois. Como o Linux se fortaleceu

Milhões de binários depois. Como o Linux se fortaleceuTL;DRNeste artigo, exploramos os esquemas de proteção (hardening schemes) que funcionam por padrão em cinco distribuições populares do Linux. Para cada uma, utilizamos a configuração padrão do kernel, carregamos todos os pacotes e analisamos os esquemas de proteção nos binários incorporados. As distribuições consideradas são OpenSUSE 12.4, Debian 9, CentOS, RHEL 6.10 e 7, além do Ubuntu 14.04, 12.04 e 18.04 LTS.

Os resultados confirmam que até mesmo os esquemas básicos, como canários de pilha e código independente de posição, ainda não são amplamente utilizados. A situação é ainda pior entre os compiladores quando se trata de proteção contra vulnerabilidades como o stack clash, que ganhou destaque em janeiro após a divulgação de informações sobre vulnerabilidades no systemd.Mas nem tudo está perdido. Uma parte significativa dos binários implementa métodos básicos de proteção, e esse número está crescendo a cada versão.

A verificação mostrou que a maior quantidade de métodos de proteção foi implementada no Ubuntu 18.04 a nível de sistema operacional e aplicativos, seguido pelo Debian 9. Por outro lado, no OpenSUSE 12.4, CentOS 7 e RHEL 7, também foram implementados esquemas básicos de proteção, e a proteção contra o stack clash é ainda mais abrangente em um conjunto de pacotes por padrão consideravelmente mais denso.

Introdução

É difícil garantir a alta qualidade do software. Apesar da enorme quantidade de ferramentas avançadas para análise estática de código e análise dinâmica em tempo de execução, além do progresso significativo no desenvolvimento de compiladores e linguagens de programação, o software moderno ainda sofre de vulnerabilidades que são constantemente exploradas por criminosos. A situação é ainda pior em ecossistemas que incluem código legado. Nesses casos, não apenas enfrentamos o eterno problema de encontrar erros potencialmente exploráveis, mas também estamos limitados por rígidos limites de compatibilidade que frequentemente exigem a manutenção de código restrito, e ainda pior, vulnerável ou com falhas.

É aqui que entram os métodos de proteção ou hardening. Alguns tipos de erros não conseguimos evitar, mas podemos dificultar a vida do criminoso e parcialmente resolver o problema, prevenindo ou interferindo. operação esses erros. Essa proteção é utilizada em todos os sistemas operacionais modernos, no entanto, os métodos diferem significativamente em complexidade, eficácia e desempenho: desde canários de pilha (stack canaries) até ASLR proteções completas CFI e ROP. Neste artigo, veremos quais métodos de proteção são aplicados nas distribuições Linux mais populares na configuração padrão, além de examinarmos as propriedades dos binários que são distribuídos através dos sistemas de gerenciamento de pacotes de cada distribuição.

CVE e segurança

Todos nós já vimos artigos com títulos como "Os aplicativos mais vulneráveis do ano" ou "Os sistemas operacionais mais vulneráveis". Geralmente, são apresentadas estatísticas sobre o número total de registros de vulnerabilidades do tipo CVE (Common Vulnerability and Exposures), obtidas a partir de Banco Nacional de Vulnerabilidades (NVD) de NIST e outras fontes. Posteriormente, esses aplicativos ou sistemas operacionais são classificados de acordo com o número de CVEs. Infelizmente, embora os CVEs sejam muito úteis para rastrear problemas e informar fornecedores e usuários, eles oferecem poucas informações sobre a segurança real do software.

Para ilustrar, vejamos o número total de CVEs nos últimos quatro anos para o kernel Linux e cinco das distribuições de servidores mais populares, ou seja, Ubuntu, Debian, Red Hat Enterprise Linux e OpenSUSE.

Milhões de binários depois. Como o Linux se fortaleceu
Fig. 1

O que este gráfico nos diz? Um maior número de CVEs significa que uma distribuição é mais vulnerável que outra? A resposta é não. Por exemplo, neste artigo, você verá que o Debian aplica mecanismos de proteção mais rigorosos em comparação, digamos, com OpenSUSE ou RedHat Linux, e mesmo assim, o Debian possui mais CVEs. No entanto, isso não necessariamente indica uma segurança enfraquecida: mesmo a presença de CVEs não significa que a vulnerabilidade é explorável. As pontuações de gravidade dão uma ideia de quão provável é a exploração da vulnerabilidade, mas, no final das contas, a explorabilidade depende em grande parte das proteções presentes nos sistemas afetados, assim como dos recursos e capacidades dos invasores. Além disso, a ausência de relatórios de CVEs não diz nada sobre outras vulnerabilidades não registradas ou desconhecidas vulnerabilidades. A diferença em CVE pode ser explicada não pela qualidade do software, mas por outros fatores, incluindo os recursos alocados para teste ou o tamanho da base de usuários. No nosso exemplo, o maior número de CVEs no Debian pode simplesmente indicar que o Debian fornece mais pacotes de software.

Certamente, o sistema CVE oferece informações úteis que permitem criar as devidas proteções. Quanto melhor entendemos as causas de falha do programa, mais fácil é identificar possíveis maneiras de exploração e desenvolver os mecanismos adequados de detecção e resposta. Na Fig. 2, estão mostradas as categorias de vulnerabilidades para todas as distribuições nos últimos quatro anos (fonte). É imediatamente evidente que a maioria dos CVEs se enquadra nas seguintes categorias: negação de serviço (DoS), execução de código, estouro de buffer, corrupção de memória, vazamento (exfiltração) de informações e escalada de privilégios. Embora muitos CVEs sejam contabilizados várias vezes em diferentes categorias, no geral, os mesmos problemas persistem ano após ano. Na próxima parte do artigo, avaliaremos o uso de diferentes esquemas de proteção para evitar a exploração das vulnerabilidades citadas.

Milhões de binários depois. Como o Linux se fortaleceu
Fig. 2

Tarefas

Neste artigo, pretendemos responder às seguintes perguntas:

  • Qual é a segurança das diversas distribuições Linux? Quais mecanismos de proteção existem no núcleo e nas aplicações do espaço do usuário?
  • Como a aceitação dos mecanismos de proteção mudou ao longo do tempo para diferentes distribuições?
  • Quais são as dependências médias de pacotes e bibliotecas de cada distribuição?
  • Quais proteções estão implementadas para cada binário?

Escolha das distribuições

Aparentemente, é difícil encontrar estatísticas precisas sobre as instalações das distribuições, uma vez que, na maioria das vezes, o número de downloads não indica o número real de instalações. No entanto, as opções Unix representam a maioria dos sistemas de servidores (em servidores web, 69,2%, conforme estatísticas W3techs e outras fontes), e sua participação está em constante crescimento. Assim, para nossa pesquisa, concentramos-nos nas distribuições disponíveis 'prontas para uso' na plataforma Google Cloud. Em particular, escolhemos os seguintes sistemas operacionais:

Distribuição/versão
Kernel
Build

OpenSUSE 12.4
4.12.14-95.3-default
#1 SMP Wed Dec 5 06:00:48 UTC 2018 (63a8d29)

Debian 9 (stretch)
4.9.0-8-amd64
#1 SMP Debian 4.9.130-2 (2018-10-27)

CentOS 6.10
2.6.32-754.10.1.el6.x86_64
#1 SMP Tue Jan 15 17:07:28 UTC 2019

CentOS 7
3.10.0-957.5.1.el7.x86_64
#1 SMP Fri Feb 1 14:54:57 UTC 2019

Red Hat Enterprise Linux Server 6.10 (Santiago)
2.6.32-754.9.1.el6.x86_64
#1 SMP Wed Nov 21 15:08:21 EST 2018

Red Hat Enterprise Linux Server 7.6 (Maipo)
3.10.0-957.1.3.el7.x86_64
#1 SMP Thu Nov 15 17:36:42 UTC 2018

Ubuntu 14.04 (Trusty Tahr)
4.4.0–140-generic

#166~14.04.1-Ubuntu SMP Sat Nov 17 01:52:43 UTC 20…

Ubuntu 16.04 (Xenial Xerus)
4.15.0–1026-gcp
#27~16.04.1-Ubuntu SMP Fri Dec 7 09:59:47 UTC 2018

Ubuntu 18.04 (Bionic Beaver)
4.15.0–1026-gcp
#27-Ubuntu SMP Thu Dec 6 18:27:01 UTC 2018

Tabela 1

Análise

Vamos estudar a configuração do kernel padrão, bem como as propriedades dos pacotes disponíveis através do gerenciador de pacotes de cada distribuição 'out of the box'. Assim, estaremos considerando apenas pacotes dos espelhos padrão de cada distribuição, ignorando pacotes de repositórios instáveis (como os espelhos 'testing' no Debian) e pacotes de terceiros (como os pacotes da Nvidia dos espelhos padrão). Além disso, não consideraremos compilações de kernels personalizadas ou configurações com segurança aprimorada.

Análise da configuração do kernel

Aplicamos um script de análise com base no verificador de kconfig livre. Consideramos os parâmetros de segurança padrão nas distribuições mencionadas e os comparamos com a lista de Projeto de Autoproteção do Kernel (KSPP). Para cada parâmetro de configuração, a tabela 2 descreve a configuração desejada: a marca está presente para distribuições que atendem às recomendações do KSSP (explicações dos termos podem ser encontradas em aqui; em artigos futuros, contaremos como muitos desses métodos de proteção surgiram e como comprometer um sistema na ausência deles).

Milhões de binários depois. Como o Linux se fortaleceu

Milhões de binários depois. Como o Linux se fortaleceu

De modo geral, os novos kernels têm configurações padrão mais rigorosas. Por exemplo, o CentOS 6.10 e o RHEL 6.10 com kernel 2.6.32 não apresentam a maioria das funcionalidades críticas implementadas em novos kernels, como SMAP, permissões estritas RWX, randomização de endereços ou proteção copy2usr. É importante notar que muitas das opções de configuração da tabela estão ausentes em versões mais antigas do kernel e não se aplicam na prática — na tabela, isso ainda é indicado como a ausência de proteção adequada. Da mesma forma, se um parâmetro de configuração estiver ausente nesta versão, e para segurança esse parâmetro precisar ser desativado, isso é considerado uma configuração razoável.

Mais um ponto a ser considerado na interpretação dos resultados: algumas configurações do núcleo que aumentam a superfície de ataque também podem ser usadas para segurança. Exemplos incluem uprobes e kprobes, módulos do núcleo e BPF/eBPF. Nossa recomendação é usar os mecanismos mencionados acima para garantir proteção real, já que eles não são triviais de usar, e sua exploração pressupõe que agentes maliciosos já estão consolidados no sistema. Mas se essas opções forem habilitadas, o administrador do sistema deve monitorar ativamente abusos.

Ao revisar as entradas da tabela 2, vemos que os núcleos modernos oferecem várias opções para se proteger contra a exploração de vulnerabilidades, como vazamento de informações e estouro de pilha/montão. No entanto, notamos que até mesmo as distribuições mais recentes e populares ainda não implementaram proteções mais complexas (por exemplo, com patches grsecurity) ou proteções modernas contra ataques de reutilização de código (por exemplo, uma combinação de randomização com esquemas do tipo R^X para código). O que é ainda pior, mesmo essas ferramentas de proteção mais avançadas não protegem contra o espectro completo de ataques. Assim, é crucial que os administradores do sistema complementem configurações razoáveis com soluções que ofereçam detecção e prevenção de exploits em tempo de execução.

Análise de aplicações

Não é surpreendente que diferentes distribuições apresentem diferentes características de pacotes, opções de compilação, dependências de bibliotecas e assim por diante. Existem diferenças até mesmo para distribuições parentes e pacotes com poucas dependências (por exemplo, coreutils no Ubuntu ou Debian). Para avaliar as diferenças, baixamos todos os pacotes disponíveis, extraímos seu conteúdo e analisamos os arquivos binários e suas dependências. Para cada pacote, rastreamos outros pacotes dos quais ele depende, e para cada binário, rastreamos suas dependências. Nesta seção, resumiremos nossas conclusões.

Distribuições

No total, carregamos 361.556 pacotes para todas as distribuições, extraindo apenas pacotes dos espelhos padrão. Ignoramos pacotes sem arquivos executáveis ELF, como códigos-fonte, fontes, etc. Após a filtragem, restaram 129.569 pacotes, contendo um total de 584.457 arquivos binários. A distribuição de pacotes e arquivos por distribuições é mostrada na Fig. 3.

Milhões de binários depois. Como o Linux se fortaleceu
Fig. 3

Pode-se notar que quanto mais moderna a distribuição, maior o número de pacotes e arquivos binários, o que é lógico. Além disso, os pacotes Ubuntu e Debian contêm muito mais arquivos binários (tanto executáveis quanto módulos e bibliotecas dinâmicas) do que CentOS, SUSE e RHEL, o que potencialmente afeta a superfície de ataque do Ubuntu e do Debian (vale ressaltar que os números refletem todos os binários de todas as versões do pacote, ou seja, alguns arquivos são analisados várias vezes). Isso é especialmente importante ao considerar as dependências entre pacotes. Dessa forma, uma vulnerabilidade em um binário de um pacote pode afetar muitas partes do ecossistema, já que uma biblioteca vulnerável pode impactar todos os arquivos binários que a importam. Como ponto de partida, vamos olhar para a distribuição do número de dependências entre pacotes em diferentes sistemas operacionais:

Milhões de binários depois. Como o Linux se fortaleceu
Fig. 4

Quase em todas as distribuições, 60% dos pacotes têm pelo menos 10 dependências. Além disso, alguns pacotes têm um número significativamente maior de dependências (mais de 100). O mesmo se aplica a dependências reversas de pacotes: como esperado, vários pacotes são usados por muitos outros pacotes na distribuição, portanto, vulnerabilidades nesses poucos escolhidos têm um alto risco. Como exemplo, na tabela a seguir, estão listados 20 pacotes com o maior número de dependências reversas no SLES, CentOS 7, Debian 9 e Ubuntu 18.04 (cada célula indica o pacote e o número de dependências reversas).

Milhões de binários depois. Como o Linux se fortaleceu
Tabela 3

Um fato interessante. Embora todos os sistemas operacionais analisados sejam construídos para a arquitetura x86_64 e a maioria dos pacotes tenha a arquitetura definida como x86_64 e x86, os pacotes frequentemente contêm arquivos binários para outras arquiteturas, conforme mostrado na Fig. 5.

Milhões de binários depois. Como o Linux se fortaleceu
Fig. 5

Na próxima seção, vamos nos aprofundar nas características dos binários analisados.

Estatísticas de proteção de arquivos binários

Como mínimo absoluto, é necessário estudar um conjunto básico de variantes de proteção para os arquivos binários existentes. Vários distribuidores do Linux vêm com scripts que executam essas verificações. Por exemplo, no Debian/Ubuntu existe um script assim. Aqui está um exemplo de seu funcionamento:

$ hardening-check $(which docker)
/usr/bin/docker:
 Executável Independente de Posição: sim
 Stack protegido: sim
 Funções Fortificadas de Fonte: não, apenas funções não protegidas encontradas!
 Relações somente leitura: sim
 Ligação imediata: sim

O script verifica cinco funções de proteção:

  • Executável Independente de Posição (PIE): indica se é possível mover a seção de texto do programa na memória para conseguir randomização, se o ASLR estiver ativado no núcleo.
  • Stack Protegido: se canários de pilha estão habilitados para proteção contra ataques de colisão de pilha.
  • Fortify Source: se funções inseguras (como strcpy) são substituídas por suas contrapartes mais seguras, enquanto chamadas verificadas em tempo de execução são suas contrapartes não verificadas (como memcpy em vez de __memcpy_chk).
  • Relações Somente Leitura (RELRO): se as entradas da tabela de relocation estão marcadas como "somente leitura", caso tenham sido ativadas antes do início da execução.
  • Ligação imediata: se o vinculador de tempo de execução resolve todas as relocations antes do início da execução do programa (isso é equivalente ao RELRO completo).

Os mecanismos acima são suficientes? Infelizmente, não. Existem formas conhecidas de contornar todas as proteções acima, mas quanto mais rígida a proteção, maior o desafio para o atacante. Por exemplo, as técnicas de contorno RELRO são mais difíceis de aplicar se PIE e ligação imediata estiverem ativados. Da mesma forma, ASLR completo requer trabalho adicional para criar um exploit funcional. Entretanto, invasores sofisticados já estão prontos para enfrentar tais proteções: sua ausência, na verdade, acelera a invasão. Portanto, é extremamente importante que essas medidas sejam consideradas como necessárias. pelo menos.

Queríamos investigar quantos arquivos binários nos distribuidores examinados estão protegidos por essas e também por mais três métodos:

  • O bit não executável (NX) impede a execução em qualquer região que não deva ser executada, por exemplo, na pilha do heap, etc.
  • RPATH/RUNPATH designa o caminho de execução usado pelo carregador dinâmico para localizar as bibliotecas correspondentes. O primeiro é obrigatório para qualquer sistema moderno: sua ausência permite que invasores gravem arbitrariamente a carga útil na memória e a executem como está. Para o segundo, configurações incorretas do caminho de execução ajudam na introdução de código não confiável, o que pode levar a uma série de problemas (por exemplo, elevação de privilégios, além de outros problemas).
  • A proteção contra colisão de pilha garante defesa contra ataques que forçam a pilha a sobrepor-se a outras áreas de memória (por exemplo, à heap). Considerando os recentes exploits que abusam de vulnerabilidades de colisão de heap no systemd,consideramos apropriado incluir esse mecanismo em nosso conjunto de dados.

Assim, sem mais delongas, vamos aos números. As Tabelas 4 e 5 contêm um resumo da análise de arquivos executáveis e bibliotecas de várias distribuições, respectivamente.

  • Como pode ser observado, a proteção NX está implementada em quase todos os lugares, com raras exceções. Em particular, pode-se notar um uso um pouco mais baixo em distribuições Ubuntu e Debian em comparação com CentOS, RHEL e OpenSUSE.
  • Canários de pilha estão ausentes em muitos lugares, especialmente em distribuições com núcleos antigos. Algum progresso é observado nas últimas distribuições do CentOS, RHEL, Debian e Ubuntu.
  • Exceto Debian e Ubuntu 18.04, a maioria das distribuições tem um suporte ruim a PIE.
  • A proteção contra colisões de pilha é fraca no OpenSUSE, CentOS 7 e RHEL 7 e praticamente ausente nas demais.
  • Todas as distribuições com núcleos modernos têm algum suporte a RELRO, sendo que a liderança é de Ubuntu 18.04 e o segundo lugar vai para Debian.

Como já mencionado, as métricas nesta tabela são médias de todas as versões do arquivo binário. Se considerarmos apenas as últimas versões dos arquivos, os números serão diferentes (por exemplo, veja o progresso do Debian com a implementação de PIE). Além disso, a maioria das distribuições geralmente conta apenas com a proteção de algumas funções no código binário ao calcular estatísticas, e em nossa análise indicamos a verdadeira porcentagem de funções reforçadas. Portanto, se 5 das 50 funções em um binário estão protegidas, atribuímos uma pontuação de 0,1, o que corresponde a 10% de funções reforçadas.

Milhões de binários depois. Como o Linux se fortaleceu
Tabela 4. Características de proteção para arquivos executáveis, mostrados na Fig. 3 (implementação das funções correspondentes em porcentagem do total de arquivos executáveis)

Milhões de binários depois. Como o Linux se fortaleceu
Tabela 5. Características de proteção para bibliotecas mostradas na Fig. 3 (implementação das funções correspondentes em porcentagem do total de bibliotecas)

Então, existe progresso? Definitivamente existe: isso é evidente nas estatísticas de distribuições individuais (por exemplo, Debian), assim como nas tabelas apresentadas acima. Como exemplo, a Fig. 6 mostra a implementação de mecanismos de proteção em três distribuições consecutivas do Ubuntu LTS 5 (omitimos a estatística sobre proteção contra colisões de pilha). Notamos que de versão para versão, cada vez mais arquivos suportam canários de pilha, e gradativamente, um número maior de arquivos binários é fornecido com proteção completa RELRO.

Milhões de binários depois. Como o Linux se fortaleceu
Fig. 6

Infelizmente, vários arquivos executáveis em diferentes distribuições ainda não possuem nenhuma das proteções mencionadas acima. Por exemplo, ao observar o Ubuntu 18.04, podemos notar o binário ngetty (substituto do getty), assim como os shells mksh e lksh, o interpretador picolisp, os pacotes nvidia-cuda-toolkit (pacote popular para aplicações com aceleração por GPU, como frameworks de aprendizado de máquina) e klibc-utils. Da mesma forma, o binário mandos-client (ferramenta administrativa que permite reiniciar automaticamente máquinas com sistemas de arquivos criptografados), assim como o rsh-redone-client (implementação revisada do rsh e rlogin) são fornecidos sem a proteção NX, embora possuam direitos SUID :(. Além disso, vários binários SUID não possuem proteção básica, como canários de pilha (por exemplo, o arquivo binário Xorg.wrap do pacote Xorg).

Resumo e considerações finais

Neste artigo, destacamos algumas características de segurança das distribuições modernas do Linux. A análise mostrou que a versão mais recente do Ubuntu LTS (18.04) implementa, em média, a proteção mais forte em nível de sistema operacional e aplicativos entre distribuições com núcleos relativamente novos, como o Ubuntu 14.04, 12.04 e Debian 9. No entanto, as distribuições analisadas, como CentOS, RHEL e OpenSUSE, em nosso conjunto de dados, oferecem por padrão um conjunto mais robusto de pacotes e, nas versões mais recentes (CentOS e RHEL), têm uma porcentagem mais alta de implementação de proteção contra estouro de pilha, em comparação com os concorrentes baseados em Debian (Debian e Ubuntu). Ao comparar as versões do CentOS e RedHat, notamos grandes melhorias na implementação de canários de pilha e RELRO das versões 6 para 7, mas, em média, o CentOS tem mais recursos implementados do que o RHEL. De modo geral, todas as distribuições devem prestar especial atenção à proteção PIE, que, exceto no Debian 9 e Ubuntu 18.04, está implementada em menos de 10% dos arquivos binários do nosso conjunto de dados.

Por fim, é importante notar: embora tenhamos realizado a pesquisa manualmente, existem várias ferramentas de segurança (como Lynis, Tiger, Hubble), que realizam análises e ajudam a evitar configurações inseguras. Infelizmente, mesmo com forte proteção em configurações razoáveis, não há garantia de ausência de exploits. É por isso que estamos firmemente convencidos de que é vital garantir monitoramento confiável e prevenção de ataques em tempo real, concentrando-se em padrões de exploração e prevenindo-os.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster