Códigos de baixa qualidade levam a comportamentos imprevisíveis. Da perspectiva do usuário, isso normalmente se manifesta como usabilidade ruim. Para um invasor, trata-se de uma oportunidade para atacar o sistema de formas imprevistas.
free()
duas vezes no mesmo endereço de memória pode resultar em um buffer overflow.free()
é chamado mais de uma vez com o mesmo endereço de memória que um argumento.free()
duas vezes no mesmo valor pode resultar em um buffer overflow. Quando um programa chama free()
duas vezes com o mesmo argumento, as estruturas de dados de gerenciamento de memória desse programa se tornam corrompidas. Essa corrupção pode fazer com que o programa trave ou, em algumas circunstâncias, com que duas chamadas posteriores para malloc()
retornem o mesmo apontador. Se malloc()
retornar o mesmo valor duas vezes, e, mais tarde, o programa der ao invasor controle sobre os dados que são gravados nessa memória duplamente alocada, o programa se tornará vulnerável a um ataque de buffer overflow.
char* ptr = (char*)malloc (SIZE);
...
if (abrt) {
free(ptr);
}
...
free(ptr);
#include <stdio.h>
int main() {
/* Nothing to see here; newline RLI /*/ return 0 ;
printf("Do we get here?\n");
return 0;
}
Example 1
, faz com que o código seja visto como o seguinte:
#include <stdio.h>
int main() {
/* Nothing to see here; newline; return 0 /*/
printf("Do we get here?\n");
return 0;
}
strncpy()
, podem causar vulnerabilidades quando usadas incorretamente. A combinação entre manipulação de memória e suposições equivocadas sobre o tamanho ou a composição de um determinado dado é a causa raiz da maioria dos estouros de buffer.
void wrongNumberArgs(char *s, float f, int d) {
char buf[1024];
sprintf(buf, "Wrong number of %.512s");
}
strncpy()
, podem causar vulnerabilidades quando usadas incorretamente. A combinação entre manipulação de memória e suposições equivocadas sobre o tamanho ou a composição de um determinado dado é a causa raiz da maioria dos estouros de buffer.f
de um flutuador usando um especificador de formato %d
.
void ArgTypeMismatch(float f, int d, char *s, wchar *ws) {
char buf[1024];
sprintf(buf, "Wrong type of %d", f);
...
}
Intent
interna implícita foi detectada. Intenções internas implícitas podem expor o sistema a ataques do tipo man-in-the-middle em componentes internos.Intent
interna usa uma ação personalizada conforme definido por um componente interno. Intenções implícitas podem facilitar a chamada de intenções de qualquer componente externo sem o conhecimento do componente específico. A combinação das duas permite que um aplicativo acesse intenções especificadas para um uso interno específico fora do contexto do aplicativo desejado.Intent
interna de um aplicativo externo pode permitir uma ampla variedade de explorações man-in-the-middle que variam em gravidade desde vazamento de informações e negação de serviço até execução remota de código, dependendo da capacidade de ação interna especificada pela Intent
.Intent
interna implícita.
...
val imp_internal_intent_action = Intent("INTERNAL_ACTION_HERE")
startActivity(imp_internal_intent_action)
...
PendingIntent
implícita foi detectada. Intenções pendentes implícitas podem resultar em vulnerabilidades de segurança, como negação de serviço, vazamento de informações privadas e do sistema e escalonamento de privilégios.Intent
posteriormente. As intenções implícitas facilitam a chamada de intenções de qualquer componente externo, usando um nome geral e um filtro para determinar a execução.Intent
implícita é criada como uma PendingIntent
, isso pode permitir que Intent
seja enviada para um componente não intencional que é executado fora do contexto temporal pretendido, deixando o sistema vulnerável a explorar vetores como negação de serviço, vazamento de informações privadas e do sistema e escalonamento de privilégios.PendingIntent
implícita.
...
val imp_intent = Intent()
val flag_mut = PendingIntent.FLAG_MUTABLE
val pi_flagmutable_impintintent = PendingIntent.getService(
this,
0,
imp_intent,
flag_mut
)
...
PendingIntent
foi detectada com seu valor de sinalizador definido como FLAG_MUTABLE
. Intenções pendentes criadas com o valor do sinalizador de FLAG_MUTABLE
são suscetíveis a ter campos não especificados Intent
definido a jusante, que pode modificar a capacidade da Intent
e deixar o sistema aberto a vulnerabilidades.Intent
subjacente de uma PendingIntent
após sua criação pode deixar um sistema aberto a ataques. Isso depende principalmente da capacidade geral da Intent
subjacente. Na maioria dos casos, é uma prática recomendada evitar possíveis problemas definindo o sinalizador PendingIntent
como FLAG_IMMUTABLE
.PendingIntent
criada com um valor de sinalizador de FLAG_MUTABLE
.
...
val intent_flag_mut = Intent(Intent.ACTION_GTALK_SERVICE_DISCONNECTED, Uri.EMPTY, this, DownloadService::class.java)
val flag_mut = PendingIntent.FLAG_MUTABLE
val pi_flagmutable = PendingIntent.getService(
this,
0,
intent_flag_mut,
flag_mut
)
...
read()
não consegue retornar o número esperado de bytes:
char* getBlock(int fd) {
char* buf = (char*) malloc(BLOCK_SIZE);
if (!buf) {
return NULL;
}
if (read(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) {
return NULL;
}
return buf;
}
CALL "CBL_ALLOC_MEM"
USING mem-pointer
BY VALUE mem-size
BY VALUE flags
RETURNING status-code
END-CALL
IF status-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
SET ADDRESS OF mem TO mem-pointer
END-IF
PERFORM write-data
IF ws-status-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
DISPLAY "Success!"
END-IF
CALL "CBL_FREE_MEM"
USING BY VALUE mem-pointer
RETURNING status-code
END-CALL
GOBACK
.
dealloc()
.init()
mas falha em liberá-la no método deallocate()
resultando em um vazamento de memória:
- (void)init
{
myVar = [NSString alloc] init];
...
}
- (void)dealloc
{
[otherVar release];
}
realloc()
não consegue redimensionar a alocação original.
char* getBlocks(int fd) {
int amt;
int request = BLOCK_SIZE;
char* buf = (char*) malloc(BLOCK_SIZE + 1);
if (!buf) {
goto ERR;
}
amt = read(fd, buf, request);
while ((amt % BLOCK_SIZE) != 0) {
if (amt < request) {
goto ERR;
}
request = request + BLOCK_SIZE;
buf = realloc(buf, request);
if (!buf) {
goto ERR;
}
amt = read(fd, buf, request);
}
return buf;
ERR:
if (buf) {
free(buf);
}
return NULL;
}
realloc()
não redimensionar a alocação original.
CALL "malloc" USING
BY VALUE mem-size
RETURNING mem-pointer
END-CALL
ADD 1000 TO mem-size
CALL "realloc" USING
BY VALUE mem-pointer
BY VALUE mem-size
RETURNING mem-pointer
END-CALL
IF mem-pointer <> null
CALL "free" USING
BY VALUE mem-pointer
END-CALL
END-IF
NullException
.cmd
" definida. Se um invasor puder controlar o ambiente do programa de forma que "cmd
" não seja definido, o programa lançará uma exceção de ponteiro nulo quando tentar chamar o método Trim()
.
string cmd = null;
...
cmd = Environment.GetEnvironmentVariable("cmd");
cmd = cmd.Trim();
null
antes que seja verificado se ele é realmente null
. Erros de desreferência após a verificação ocorrem quando um programa faz uma verificação explícita em busca de valores null
, mas prossegue para desreferenciar o ponteiro quando se sabe que ele é null
. Erros desse tipo são frequentemente o resultado de um erro de digitação ou de uma desatenção do programador. Um erro de desreferência após o armazenamento ocorre quando um programa define explicitamente um ponteiro como null
e o desreferencia mais tarde. Esse erro é frequentemente o resultado de um programador inicializar uma variável como null
quando ela é declarada.ptr
não seja NULL
. Essa suposição se torna explícita quando o programador desreferencia o ponteiro. Mais tarde, essa suposição é contrariada quando o programador verifica ptr
contra NULL
. Se a variável ptr
puder ser NULL
quando for verificada na instrução if
, ela também poderá ser NULL
quando desreferenciada, podendo causar uma falha de segmentação.Exemplo 2: No código a seguir, o programador confirma que a variável
ptr->field = val;
...
if (ptr != NULL) {
...
}
ptr
é NULL
e depois a desreferencia erroneamente. Se a variável ptr
for NULL
quando for verificada na instrução if
, ocorrerá uma desreferência null
, causando assim uma falha de segmentação.Exemplo 3: No código a seguir, o programador se esquece de que a cadeia de caracteres
if (ptr == null) {
ptr->field = val;
...
}
'\0'
é, na verdade, 0 ou NULL
, desreferenciando assim um ponteiro nulo e provocando uma falha de segmentação.Exemplo 4: No código a seguir, o programador define explicitamente a variável
if (ptr == '\0') {
*ptr = val;
...
}
ptr
como NULL
. Mais tarde, o programador desreferencia ptr
antes de verificar o objeto em busca de um valor null
.
*ptr = NULL;
...
ptr->field = val;
...
}
NullPointerException
.cmd
" definida. Se um invasor puder controlar o ambiente do programa de forma que "cmd
" não seja definido, o programa lançará uma exceção de ponteiro nulo quando tentar chamar o método trim()
.
String val = null;
...
cmd = System.getProperty("cmd");
if (cmd)
val = util.translateCommand(cmd);
...
cmd = val.trim();
SqlClientPermission
que regula como os usuários podem se conectar a um banco de dados. Neste exemplo, o programa transmite false
como o segundo parâmetro para o construtor, que controla se os usuários têm permissão para se conectarem com senhas em branco. A transmissão de "false" para esse parâmetro indica que senhas em branco não devem ser permitidas.
...
SCP = new SqlClientPermission(pstate, false);
...
PermissionState
transmitido como o primeiro parâmetro substitui qualquer valor transmitido ao segundo parâmetro, o construtor permite senhas em branco para conexões de banco de dados, o que contradiz o segundo argumento. Para proibir senhas em branco, o programa deve transmitir PermissionState.None
ao primeiro parâmetro do construtor. Devido à ambiguidade na sua funcionalidade, a versão de dois parâmetros do construtor SqlClientPermission
foi preterida a favor da versão de parâmetro único, que transmite o mesmo grau de informações sem o risco de má interpretação.getpw()
para verificar se a senha de texto sem formatação corresponde à senha criptografada de um usuário. Se a senha for válida, a função definirá result
como 1; caso contrário, ele será definido como 0.
...
getpw(uid, pwdline);
for (i=0; i<3; i++){
cryptpw=strtok(pwdline, ":");
pwdline=0;
}
result = strcmp(crypt(plainpw,cryptpw), cryptpw) == 0;
...
getpw(
) pode ser uma estratégia problemática sob o ponto de vista da segurança, pois pode estourar o buffer transmitido para seu segundo parâmetro. Devido a essa vulnerabilidade, getpw()
foi suplantado por getpwuid()
, que executa a mesma pesquisa que getpw()
, mas retorna um ponteiro para uma estrutura estaticamente alocada a fim de atenuar o risco.
...
String name = new String(nameBytes, highByte);
...
nameBytes
. Devido à evolução dos charsets utilizados para codificar strings, este construtor foi descontinuado e substituído por um construtor que aceita como um de seus parâmetros o nome do charset
usado para codificar os bytes para conversão.Digest::HMAC
, cujo uso é explicitamente desencorajado na documentação devido ao envolvimento acidental em uma versão.
require 'digest/hmac'
hmac = Digest::HMAC.new("foo", Digest::RMD160)
...
hmac.update(buf)
...
Digest::HMAC
foi preterida imediatamente após o envolvimento devido à inclusão acidental em uma versão. Devido à possibilidade de ela não funcionar como o esperado por causa de um código experimental e não testado apropriadamente, a utilização é extremamente desencorajada, especialmente considerando-se a relação que os HMACs têm com a funcionalidade criptográfica.IsBadXXXPtr()
. Essas funções:IsBadWritePtr()
em uma tentativa de impedir gravações de memória inválidas.
if (IsBadWritePtr(ptr, length))
{
[handle error]
}
public class Totaller {
private int total;
public int total() {
...
}
}
synchronized(this) { }
int un$afe;
r
e, em seguida, substitui o valor sem usá-lo.
int r = getNum();
r = getNewNum(buf);
r
e, em seguida, substitui o valor sem usá-lo.
int r = getNum();
r = getNewNum(buf);
r
e, em seguida, substitui o valor sem usá-lo.
r = getName();
r = getNewBuffer(buf);
r
e, em seguida, substitui o valor sem usá-lo.
r = getName();
r = getNewBuffer(buf);
i
) fosse usado duas vezes. A variável j
nunca é usada.
int i,j;
for (i=0; i < outer; i++) {
for (i=0; i < inner; i++) {
...