Existem muitos riscos de segurança decorrentes do contato próximo com o hardware, em vez de usar APIs bem testadas e comprovadas em linguagens de programação de alto nível. É muito mais fácil causar um estouro de buffer em C do que em uma linguagem como Java.
Quais são os riscos ou vulnerabilidades (por exemplo, estouros de buffer) que todo programador C deve estar ciente (vulnerabilidades do IE relevantes para os programadores C)? A que problemas isso poderia levar? Como evitá-los e quais são os erros comuns que causam esses erros nos programas?
Respostas:
Os estouros de buffer são grandes. Nada em C é verificado no intervalo por padrão, por isso é muito fácil substituir um buffer. Há uma função de biblioteca padrão
gets()
, que não pode ser impedida de estourar o buffer e quase nunca deve ser usada.Existem algumas técnicas no nível de implementação para impedir a exploração, como embaralhar blocos de heap, mas isso não interrompe o estouro de buffer nos buffers locais, o que geralmente pode fazer coisas interessantes, como alterar o endereço para o qual a função retornará.
Não existe uma boa solução geral em C. Muitas funções da biblioteca possuem versões que limitarão a quantidade que serão gravadas. embora calcular isso possa ser desajeitado. Existem softwares que podem detectar estouros de buffer de heap em teste, desde que o teste apropriado seja executado, e o estouro de pilha geralmente aparece como uma falha nos testes. Fora isso, é uma questão de codificação cuidadosa e revisão de código.
Um problema relacionado é o problema de gravar em um buffer muito pequeno por um caractere, esquecendo que uma string C com n caracteres requer n + 1 caracteres na memória, devido ao
'\0'
terminador. Se o invasor conseguir armazenar uma string sem o terminador, qualquer função C que espera uma string continuará processando até atingir um byte zero, o que pode resultar em copiar ou emitir mais informações do que o desejado (ou atingir a memória protegida para um ataque do DOS) ) A solução, novamente, é a conscientização, o cuidado e as revisões de código.Há outro risco com a
printf()
família. Se você escrevechar * str; ... printf(str);
, está se preparando para problemas sestr
contiver um '%' quando impresso. A%n
diretiva de formato permiteprintf()
gravar na memória. A solução éprintf("%s", str);
ouputs(str);
. (Além disso, use o C99 emsnprintf()
vez desprintf()
.)O uso de números inteiros não assinados, principalmente como índices de loop, pode causar problemas. Se você atribuir um pequeno valor negativo a um não assinado, obterá um grande valor positivo. Isso pode prejudicar coisas como processar apenas N instâncias de algo ou funções limitadas como
strncpy()
. Examine todos os números inteiros não assinados. Você pode evitarunsigned short
, pois um grande valor em um deles será convertido em um grande valor positivo em umint
.Não esqueça que uma constante de caractere, em C, é na verdade uma
int
. Escrever algo comochar c; while((c = getchar()) != EOF) ...
pode falhar facilmente, poisEOF
não será representável em um arquivochar
.Há muitos erros característicos de C em que posso pensar, mas esses podem causar problemas de segurança.
fonte
printf("%s", str)
uma corda nua quandoputs(str)
fará o mesmo trabalho.puts
acrescenta um caractere de nova linha enquantoprintf
não.fputs(str, stdout)
, o que não.Alguns dos riscos específicos de C incluem: estouros de buffer , ataques de string de formatação e estouros de números inteiros .
fonte
Aqui está um risco fácil de perder que pode causar problemas que levarão horas para serem corrigidos.
Considere o código a seguir, que será compilado sem problemas.
Quando você verifica se
lpstr_current_state
está dentro,CONST_EMERGENCY_STATE_HOLY_CRAP
está realmente atribuindo. É melhor sempre colocar a variável constante à esquerda. Quando você coloca a constante à esquerda, o compilador falha porque você não pode atribuir um valor a uma variável.Então você pode facilmente dizer para si mesmo: "Caramba, isso poderia ter sido ruim", enquanto corrigia o código para ler ...
fonte
=
e==
.Há apenas um risco de segurança: o fato de haver pessoas de fora que farão o possível para capturar qualquer vulnerabilidade no seu software e explorá-la para seu próprio benefício. Tudo o resto segue a partir daí.
Então, quando você pensa que "ninguém em sã consciência faria ...", precisará pensar imediatamente "exceto que alguém que queira invadir os computadores de outras pessoas faria exatamente isso".
A maior consequência é que sempre que você reage a eventos externos (por exemplo, processando dados fornecidos de fora), você deve assumir que esses dados estavam sob controle de seu pior inimigo.
fonte