Transbordamento de dados: diferenças entre revisões

Origem: Wikipédia, a enciclopédia livre.
Conteúdo apagado Conteúdo adicionado
Etiqueta: Remoção considerável de conteúdo
Linha 1: Linha 1:
{{
{{Sem-fontes|data=abril de 2012| angola=| arte=| Brasil=| ciência=| geografia=| música=| Portugal=| sociedade=|1=|2=|3=|4=|5=|6=}}
Em [[Segurança da Informação e Comunicações|segurança computacional]] e [[Programação de computadores|programação]], um '''transbordamento de dados''' ou '''estouro de''' '''''[[Buffer (ciência da computação)|buffer]]''''' (do [[Língua inglesa|inglês]] ''buffer overflow'' ou ''buffer overrun'') é uma anomalia onde um programa, ao escrever dados em um ''buffer'', ultrapassa os limites do ''buffer'' e sobrescreve a memória adjacente. Esse é um caso especial de violação de segurança de memória.

Estouros de ''buffer'' podem ser disparados por entradas que são projetadas para executar código, ou alterar o modo como o programa funciona. Isso pode resultar em comportamento errado do programa, incluindo erros de acesso à memória, resultados incorretos, parada total do sistema, ou uma brecha num sistema de segurança. Portanto, eles são a base de muitas vulnerabilidade de ''software'' e pode ser explorados maliciosamente.

[[Linguagem de programação|Linguagens de programação]] comumente associadas com transbordamentos de dados incluem [[C (linguagem de programação)|C]] e [[C++]], as quais não proveem proteção contra acesso ou sobrescrita de dados em qualquer parte da memória e não checam automaticamente se dados escritos em um ''[[array]]'' (cadeia de elementos – o tipo de ''buffer'' dessas linguagens) estão nos limites do ''array''. Checagem de limites pode prevenir transbordamentos de dados.

== Descrição técnica ==
Um estouro de ''buffer'' ocorre quando dados escritos em um ''buffer'', devido a checagem de limites insuficiente, corrompe valores de dados no endereço de memória adjacente ao ''buffer'' alocado. Isso ocorre mais comumente quando se copiam ''[[string]]s'' (cadeias de caracteres) de um ''buffer'' para outro.
=== Exemplo básico ===
No exemplo a seguir, um programa define dois itens de dados que são adjacentes na memória: um ''buffer'' de ''strings'' A de tamanho de 8 ''bytes'', e um inteiro B de tamanho de 2 bytes. Inicialmente, A não contém nada além de ''bytes'' zero, e B contém o número 1 979. O tamanho dos caracteres é 1 ''byte''.

{| class="wikitable" style="width:30em; text-align:center;"
! style="white-space:nowrap;" | variable name
! colspan="8" style="background:#ddf;" | A
! colspan="2" style="background:#fdd;" | B
|- style="background:#ddf; font-family:monospace;"
! style="font-family:sans;" | value
| colspan="8" style="font-size:smaller; font-family:sans;" | [<nowiki/>[[null string]]<nowiki/>]
| colspan="2" style="background:#fdd;" | 1979
|- style="background:#ddf; font-family:monospace;"
! style="font-family:sans;" | hex value
| 00 || 00 || 00 || 00 || 00 || 00 || 00 || 00
| 00 || 00 || 00 || 00 || 00 || 00 || 00 || 00
| ASCII, "e" seguido por um ''byte'' zero se tornam o número 25 856. Se B fosse a única outra variável definida pelo programa, escrever uma ''string'' aente, elas não checam se um dado escrito em um ''buffer'' está nos limites do ''buffer''. Entretanto, as bibliotecas de C++ padrão proveemzem checagem de limites, como gets, scanf e strcpy. O ''[[worm]]'' de Morris explorou uma chamada de gets no fingerd.
| style="background:#fdd;" | 07 || style="background:#fdd;" | BB
|}

Agora, o programa tenta guardar a ''string'' terminada em nulo ''excessive'' no ''buffer'' A. Ao falhar em checar o comprimento da ''string'', ele sobrescreve o valor de B.

{| class="wikitable" style="width:30em; text-align:center;"
! style="white-space:nowrap;" | variable name
! colspan="8" style="background:#ddf;" | A
! colspan="2" style="background:#fdd;" | B
|- style="background:#ffd; font-family:monospace;"
! style="font-family:sans;" | value
| 'e' || 'x' || 'c' || 'e' || 's' || 's' || 'i' || 'v'
| colspan="2" style="background:#dbd;" | 25856
|- style="background:#ddf; font-family:monospace;"
! style="font-family:sans;" | hex
| 65 || 78 || 63 || 65 || 73 || 73 || 69 || 76
| style="background:#dbd;" | 65 || style="background:#dbd;" | 00
|}

Embora o programador não tenha intenção alguma de mudar B, o valor de B foi substituído pelo número formado por parte de uma cadeia de caracteres. Neste exemplo, em um sistema ''[[Extremidade (ordenação)|big-endian]]'' que usa ASCII, "e" seguido por um ''byte'' zero se tornam o número 25 856. Se B fosse a única outra variável definida pelo programa, escrever uma ''string'' ainda maior que ultrapassasse B poderia causar um erro como uma falha de segmentação, terminando o processo.

== Exploração ==
As técnicas para se explorar uma vulnerabilidade de estouro de ''buffer'' podem variar de acordo com a arquitetura, sistema operacional e região da memória. Por exemplo, explorar um ''[[heap]]'' (usado para alocar memória dinamicamente) é muito diferente de explorar uma [[Pilha (informática)|pilha]] de chamadas.

=== Exploração baseada em pilha ===
Um usuário malicioso e com habilidades técnicas pode explorar estouro de ''buffer'' em pilhas para manipular o programa de uma das seguintes maneiras:
* Sobrescrever uma variável local que está próxima do ''buffer'' na memória da pilha para mudar o comportamento do programa de modo a beneficiar o atacante.
* Sobrescrever o endereço de retorno da pilha. Uma vez que a função retorna, a execução irá continuar no endereço de retorno especificado pelo atacante, geralmente um ''buffer'' preenchido por entrada do usuário.
* Sobrescrever um ponteiro de função, ou tratador de exceção, que é posteriormente executado.
Com um método chamado ''trampolining'', se um endereço de um dado fornecido pelo usuário é desconhecido, mas a sua localização é guardada em um registrador, então o endereço de retorno pode ser sobrescrito com um ''[[opcode]]'' que fará a execução saltar para os dados fornecidos pelo usuário. Se a localização é guardada num registrador R, então um salto de execução para a localização contendo o ''opcode'' para um salto para R, chamada para R ou uma instrução similar, causará a execução de dados fornecidos pelo usuário. A localização de ''opcodes'' adequados, ou ''bytes'' na memória, podem ser encontradas em DLLs ou no próprio executável. Entretanto, o endereçamento de ''opcodes'' tipicamente não pode conter nenhum caractere nulo e as localizações desses ''opcodes'' podem mudar entre aplicações e versões do sistema operacional. O Projeto Metasploit é um banco de dados de ''opcodes'', apesar de apenas os ''opcodes'' encontrados nos sistemas Windows estarem listados.
Não se deve confundir estouro de ''buffer'' baseado em pilha com estouro de pilha.
Essas vulnerabilidade são descobertas geralmente com uso de um ''[[Fuzzing|fuzzer]]''.

=== Exploração baseada em ''heap'' ===
Um estouro de ''buffer'' que ocorre na área de dados da ''heap'' é chamado de estouro de ''heap'' e é explorado de forma diferente do estouro de ''buffer'' baseado em pilha. A memória na ''heap'' é alocada dinamicamente pela aplicação em tempo de execução e contem tipicamente dados do programa. A exploração se dá corrompendo-se esses dados de modos específicos para fazer a aplicação sobrescrever estruturas internas como listas encadeadas e ponteiros. A técnica de estouro de ''heap'' canônica sobrescreve a lincagem de alocação de memória dinâmica (como o ''malloc'') e usa a troca de ponteiro resultante para sobrescrever um ponteiro de função do programa.
A vulnerabilidade do GDI+ da Microsoft em tratar JPEGs é um exemplo do perigo que um estouro de ''heap'' pode apresentar.

=== Barreiras à exploração ===
Manipulação do ''buffer'', que ocorre antes que ele seja lido ou executado, pode levar à falha de uma tentativa de exploração. Essas manipulações podem mitigar a ameaça de exploração, mas não pode fazê-la se tornar impossível. Manipulação pode incluir conversão de maiúscula em minúscula, remoção de caracteres especiais e filtragem de strings não alfanuméricas. Entretanto, existem técnicas para burlar esses filtros e manipulações: códigos alfanuméricos, códigos polimórficos, códigos autodeslocáveis, e ataques ''return-to-libc''. Os mesmo métodos podem ser usado para evitar detecção em sistemas de detecção de invasão. Em alguns casos, incluindo onde o código é convertido para Unicode, a ameaça da vulnerabilidade tem sido erroneamente confundida pelos divulgadores como apenas negação de serviço, quando de fato a execução remota de código arbitrário é possível.

=== Aspectos práticos da exploração ===
Em explorações do mundo real, existe uma variedade de desafios que precisam ser superados para as explorações operarem de fato. Esses fatores incluem ''bytes'' nulos em endereços, variação na localização do ''shellcode'', diferenças entre ambientes e várias contramedidas em operação.

== Medidas de proteção ==
Várias técnicas foram utilizadas para detectar ou prevenir estouros de ''buffer'', com vantagens e desvantagens. O modo mais confiável de evitar ou prevenir estouros de ''buffer'' é usar proteção automática a nível de linguagem. Esse tipo de proteção, entretanto, não pode ser aplicado a códigos legados. As seguintes seções descrevem as opções e implementações disponíveis.

=== Escolha de linguagem de programação ===
A escolha da linguagem de programação pode ter um efeito profundo na ocorrência de estouros de buffer. Como em 2008, entre as linguagens mais populares estão C e sua derivativa C++, com uma ampla gama de ''softwares'' sendo escritos nessas linguagens. C e C++ não proveem proteção embutida contra acesso indevido ou sobrescrita de qualquer parte da memória. Mais especificadamente, elas não checam se um dado escrito em um ''buffer'' está nos limites do ''buffer''. Entretanto, as bibliotecas de C++ padrão proveem muitas maneiras de copiar dados para um ''buffer'' de forma segura, e técnicas para evitar estouros de ''buffer'' também existem em C.

Muitas outras linguagens de programação proveem checagem em tempo de execução e em alguns casos até checagens em tempo de compilação, que enviam um alerta um lançam uma exceção quando C ou C++ iriam sobrescrever os dados e continuar a executar instruções até que resultados errados fossem obtidos, os quais poderiam ou não fazer o programa parar. Exemplos de tais linguagens incluem Ada, Eiffel, Lisp, Modula-2, Smalltalck, Objective Caml e derivadas de C como Cyclone e D. Os ambientes de bytecodes de Java e do .Net Framework também requerem checagem de limites em todos os arrays. Quase todas as linguagens interpretadas irão proteger contra estouros de buffer, sinalizando uma condição de erro bem definida.

Na maioria das vezes, quando uma linguagem prove informação de tipos suficiente para se fazer checagem de limites de ''arrays'', é dada a opção de habilitar ou desabilitar a checagem. Análise de código estática pode remover muitas checagens de limites e tipos dinâmicas, mas implementações pobres e casos estranhos podem diminuir significativamente o desempenho. Engenheiros de ''software'' devem considerar cuidadosamente os ganhos e perdas de segurança versus custos de desempenho ao decidirem qual linguagem e configuração de compilador utilizar.

=== Uso de bibliotecas seguras ===
O problema de estouro de ''buffer'' é comum em C e C++ porque elas expõem detalhes de baixo nível de implementação dos ''buffers'' como conteúdos e tipos de dados. Estouros de ''buffer'' devem ser evitados para se manter um alto nível de correção no código que executa o gerenciamento de buffer. Também é recomendado há muito tempo que se evitem as funções de bibliotecas padrão que não fazem checagem de limites, como gets, scanf e strcpy. O ''[[worm]]'' de Morris explorou uma chamada de gets no fingerd.


Bibliotecas de tipos de dados abstratos bem escritas e testadas que centralizam e checam automaticamente o gerenciamento de ''buffer'', incluindo checar os limites, podem reduzir a ocorrência e impacto de estouros de ''buffer''. Os dois principais tipos de dados básicos nessas linguagens nos quais estouros de ''buffer'' geralmente ocorrem são strings e arrays. Então, bibliotecas que previnem estouro de ''buffer'' nesses tipos podem prover a grande maioria da segurança necessária. Ainda assim, falhas em se usar bibliotecas seguras podem resultar em estouros de ''buffer'' e outras vulnerabilidades, e naturalmente, qualquer erro na própria biblioteca é uma vulnerabilidade em potencial. Implementações "seguras" de bibliotecas incluem ''The Better String Library'', Vstr e Erwin. A biblioteca C do sistema operacional OpenBSD provê as funções strlcpy e strlcat, mas elas são mais limitadas que a implementação completa da biblioteca segura.
Bibliotecas de tipos de dados abstratos bem escritas e testadas que centralizam e checam automaticamente o gerenciamento de ''buffer'', incluindo checar os limites, podem reduzir a ocorrência e impacto de estouros de ''buffer''. Os dois principais tipos de dados básicos nessas linguagens nos quais estouros de ''buffer'' geralmente ocorrem são strings e arrays. Então, bibliotecas que previnem estouro de ''buffer'' nesses tipos podem prover a grande maioria da segurança necessária. Ainda assim, falhas em se usar bibliotecas seguras podem resultar em estouros de ''buffer'' e outras vulnerabilidades, e naturalmente, qualquer erro na própria biblioteca é uma vulnerabilidade em potencial. Implementações "seguras" de bibliotecas incluem ''The Better String Library'', Vstr e Erwin. A biblioteca C do sistema operacional OpenBSD provê as funções strlcpy e strlcat, mas elas são mais limitadas que a implementação completa da biblioteca segura.
Linha 84: Linha 9:


A primeira exploração hostil documentada de um estouro de ''buffer'' foi em 1988. Era uma de várias explorações usadas pelo ''worm'' criado por Morris para se propagar pela internet. O programa explorado era um serviço do Unix chamado finger. Depois, em 1995, Thomas Lopatic redescobriu independentemente o estouro de ''buffer'' e publicou suas descobertas na lista de mensagens de segurança Bugtraq. Um ano depois, em 1996, Elias Levy (também conhecido como Aleph One) publicou na revista Phrack o artigo "Destruindo a Pilha por Diversão e Lucro", uma introdução passo a passo para explorar vulnerabilidades de estouro de ''buffer'' baseado em pilha.
A primeira exploração hostil documentada de um estouro de ''buffer'' foi em 1988. Era uma de várias explorações usadas pelo ''worm'' criado por Morris para se propagar pela internet. O programa explorado era um serviço do Unix chamado finger. Depois, em 1995, Thomas Lopatic redescobriu independentemente o estouro de ''buffer'' e publicou suas descobertas na lista de mensagens de segurança Bugtraq. Um ano depois, em 1996, Elias Levy (também conhecido como Aleph One) publicou na revista Phrack o artigo "Destruindo a Pilha por Diversão e Lucro", uma introdução passo a passo para explorar vulnerabilidades de estouro de ''buffer'' baseado em pilha.

Desde então, no mínimo dois grandes ''worms'' de internet exploraram estouro de ''buffer'' para comprometer um grande número de sistemas. Em 2001, o ''worm'' Code Red explorou um estouro de buffer no Internet Information Services (ISS) 5.0 da Microsoft e em 2003 o ''worm'' SQL Slammer comprometeu máquinas rodando o Microsoft SQL Server 2000. Em 2003, estouros de ''buffer'' presentes em jogos licenciados do Xbox foram explorados para permitir que ''softwares'' não licenciados, incluindo jogos caseiros, rodassem no console sem a necessidade de modificações de ''hardware'', também conhecidas como ''[[modchip]]s''. O PS2 Indepentence Exploit também usou um estouro de ''buffer'' para fazer o mesmo com o Playstation 2. O hack Twilight conseguiu o mesmo no [[Wii]] usando um estouro de ''buffer'' no jogo [[The Legend of Zelda: Twilight Princess]].


== Ver também ==
== Ver também ==

Revisão das 09h50min de 6 de janeiro de 2016

{{ | 00 || 00 || 00 || 00 || 00 || 00 || 00 || 00 | ASCII, "e" seguido por um byte zero se tornam o número 25 856. Se B fosse a única outra variável definida pelo programa, escrever uma string aente, elas não checam se um dado escrito em um buffer está nos limites do buffer. Entretanto, as bibliotecas de C++ padrão proveemzem checagem de limites, como gets, scanf e strcpy. O worm de Morris explorou uma chamada de gets no fingerd.

Bibliotecas de tipos de dados abstratos bem escritas e testadas que centralizam e checam automaticamente o gerenciamento de buffer, incluindo checar os limites, podem reduzir a ocorrência e impacto de estouros de buffer. Os dois principais tipos de dados básicos nessas linguagens nos quais estouros de buffer geralmente ocorrem são strings e arrays. Então, bibliotecas que previnem estouro de buffer nesses tipos podem prover a grande maioria da segurança necessária. Ainda assim, falhas em se usar bibliotecas seguras podem resultar em estouros de buffer e outras vulnerabilidades, e naturalmente, qualquer erro na própria biblioteca é uma vulnerabilidade em potencial. Implementações "seguras" de bibliotecas incluem The Better String Library, Vstr e Erwin. A biblioteca C do sistema operacional OpenBSD provê as funções strlcpy e strlcat, mas elas são mais limitadas que a implementação completa da biblioteca segura.

História

Estouros de buffer foram entendido e parcialmente documentados publicamente em 1972, quando o Computer Security Technology Planning Study divulgou a técnica: "O código que executa essa função não checa os endereços de origem e destino devidamente, permitido que porções do monitor sejam sobrepostas pelo usuário. Isto pode ser usado para injetar código no monitor que permitirá ao usuário tomar controle da máquina." (Página 61) Hoje, o monitor seria chamado de kernel.

A primeira exploração hostil documentada de um estouro de buffer foi em 1988. Era uma de várias explorações usadas pelo worm criado por Morris para se propagar pela internet. O programa explorado era um serviço do Unix chamado finger. Depois, em 1995, Thomas Lopatic redescobriu independentemente o estouro de buffer e publicou suas descobertas na lista de mensagens de segurança Bugtraq. Um ano depois, em 1996, Elias Levy (também conhecido como Aleph One) publicou na revista Phrack o artigo "Destruindo a Pilha por Diversão e Lucro", uma introdução passo a passo para explorar vulnerabilidades de estouro de buffer baseado em pilha.

Ver também

Ícone de esboço Este artigo sobre informática é um esboço. Você pode ajudar a Wikipédia expandindo-o.