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.
...
var file:File = new File(directoryName + "\\" + fileName);
...
...
FileStream f = File.Create(directoryName + "\\" + fileName);
...
...
File file = new File(directoryName + "\\" + fileName);
...
...
os.open(directoryName + "\\" + fileName);
...
<script>
.
...
public String tagProcessor(String tag){
if (tag.toUpperCase().equals("SCRIPT")){
return null;
}
//does not contain SCRIPT tag, keep processing input
...
}
...
Example 1
é que java.lang.String.toUpperCase()
, quando usado sem uma localidade, aplica as regras da localidade padrão. O uso da localidade turca "title".toUpperCase()
retorna "T\u0130TLE", onde "\u0130" é o caractere "LATIN CAPITAL LETTER I WITH DOT ABOVE". Isso pode provocar resultados inesperados, como no Example 1
, em que isso impedirá que a palavra "script" seja capturada por essa validação, podendo causar uma vulnerabilidade de Cross-Site Scripting.
...
import java.sql.PreparedStatement;
import com.sap.sql.NativeSQLAccess;
String mssOnlyStmt = "...";
// variant 1
PreparedStatement ps =
NativeSQLAccess.prepareNativeStatement(
conn, mssOnlyStmt);
. . .
// variant 2
Statement stmt =
NativeSQLAccess.createNativeStatement(conn);
int result = stmt.execute(mssOnlyStmt);
. . .
// variant 3
CallableStatement cs =
NativeSQLAccess.prepareNativeCall(
conn, mssOnlyStmt);
. . .
...
public class Box{
public int area;
public static final int width = 10;
public static final Box box = new Box();
public static final int height = (int) (Math.random() * 100);
public Box(){
area = width * height;
}
...
}
...
Example 1
, o desenvolvedor esperaria que box.area
fosse um número inteiro aleatório que, por acaso, é um múltiplo de 10, já que width
é igual a 10. Porém, na realidade, isso sempre terá um valor inserido em código fixo de 0. Campos estáticos finais declarados com uma constante em tempo de compilação são inicializados primeiros e depois cada um é executado em ordem. Isso significa que, como height
não é uma constante em tempo de compilação, ela é declarada após a declaração de box
e, portanto, o construtor é chamado antes da inicialização do campo height
.
...
class Foo{
public static final int f = Bar.b - 1;
...
}
...
class Bar{
public static final int b = Foo.f + 1;
...
}
This example is perhaps easier to identify, but would be dependent on which class is loaded first by the JVM. In this exampleFoo.f
could be either -1 or 0, andBar.b
could be either 0 or 1.
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.foo
é null
e depois o desreferencia erroneamente. Se foo
for null
quando for verificado na instrução if
, ocorrerá um cancelamento de referência null
, o que causa uma exceção de ponteiro nulo.Exemplo 2: No código a seguir, o programador supõe que a variável
if (foo is null) {
foo.SetBar(val);
...
}
foo
não seja null
e confirma essa suposição desfazendo a referência ao objeto. No entanto, o programador mais tarde contradiz a suposição, verificando foo
com base em null
. Se a variável foo
puder ser null
quando for verificada na instrução if
, ela também poderá ser null
quando sua referência for desfeita, podendo causar uma exceção de ponteiro nulo. Ou o cancelamento de referência não é seguro, ou a verificação subsequente é desnecessária.Exemplo 3: No código a seguir, o programador define explicitamente a variável
foo.SetBar(val);
...
if (foo is not null) {
...
}
foo
como null
. Mais tarde, o programador desreferencia foo
antes de verificar o objeto em busca de um valor null
.
Foo foo = null;
...
foo.SetBar(val);
...
}
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;
...
}
null
, mas prossegue para cancelar a referência ao objeto 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.foo
é null
e depois a desreferencia erroneamente. Se a variável foo
for null
quando for verificada na instrução if
, ocorrerá um cancelamento de referência null
, provocando assim uma exceção de ponteiro nulo.
if (foo == null) {
foo.setBar(val);
...
}
unsigned char
convertido em int
, mas o valor de retorno é atribuído a um tipo char
.EOF
.EOF
.
char c;
while ( (c = getchar()) != '\n' && c != EOF ) {
...
}
getchar()
é convertido em char
e comparado com EOF
(um int
). Supondo que c
seja um valor de 8 bits com sinal e EOF
seja um valor de 32 bits com sinal, se getchar()
retornar um caractere representado por 0xFF, o valor de c
será o sinal estendido para 0xFFFFFFFF em comparação com EOF
. Como EOF
é normalmente definido como -1 (0xFFFFFFFF), o loop terminará erroneamente.amount
pode conter um valor negativo ao ser retornada. Como a função é declarada para retornar um inteiro sem sinal, amount
será implicitamente convertido em um valor sem sinal.
unsigned int readdata () {
int amount = 0;
...
if (result == ERROR)
amount = -1;
...
return amount;
}
Example 1
for atendida, o valor de retorno de readdata()
será 4.294.967.295 em um sistema que usa inteiros de 32 bits.accecssmainframe()
, a variável amount
pode conter um valor negativo ao ser retornada. Como a função é declarada para retornar um valor sem sinal, amount
será implicitamente convertido em um número sem sinal.
unsigned int readdata () {
int amount = 0;
...
amount = accessmainframe();
...
return amount;
}
accessmainframe()
for -1, o valor de retorno de readdata()
será 4.294.967.295 em um sistema que usa inteiros de 32 bits.1
sempre deve ser transmitido ao primeiro parâmetro (o número de versão) da seguinte função do sistema de arquivos:
__xmknod
2
sempre deve ser transmitido ao terceiro parâmetro (o argumento de grupo) das seguintes funções de cadeia de caracteres largos:
__wcstod_internal
__wcstof_internal
_wcstol_internal
__wcstold_internal
__wcstoul_internal
3
sempre deve ser transmitido como o primeiro parâmetro (o número de versão) das seguintes funções do sistema de arquivos:
__xstat
__lxstat
__fxstat
__xstat64
__lxstat64
__fxstat64
FILE *sysfile = fopen(test.file, "w+");
FILE insecureFile = *sysfile;
sysfile
é desreferenciado na atribuição de insecureFile
, o uso de insecureFile
pode resultar em uma ampla variedade de problemas.
FILE *sysfile = fopen(test.file, "r+");
res = fclose(sysfile);
if(res == 0){
printf("%c", getc(sysfile));
}
getc()
é executada após o fluxo de arquivo para sysfile
ser fechado, getc()
resulta em comportamento indefinido e pode causar uma falha no sistema ou possível modificação ou leitura do mesmo arquivo ou de um arquivo diferente.
std::auto_ptr<foo> p(new foo);
foo* rawFoo = p.get();
delete rawFoo;
delete
, essa classe não saberá mais usar o ponteiro.int a = (Int32)i + (Int32)j;
a seguir lança uma exceção sem tratamento e trava o aplicativo em tempo de execução.
class Program
{
static int? i = j;
static int? j;
static void Main(string[] args)
{
j = 100;
int a = (Int32)i + (Int32)j;
Console.WriteLine(i);
Console.WriteLine(j);
Console.WriteLine(a);
}
}
aN
ebN
, mas no caso padrão, o programador definiu acidentalmente o valor de aN
duas vezes.
switch (ctl) {
case -1:
aN = 0; bN = 0;
break;
case 0:
aN = i; bN = -i;
break;
case 1:
aN = i + NEXT_SZ; bN = i - NEXT_SZ;
break;
default:
aN = -1; aN = -1;
break;
}
Finalize()
para StreamReader
chama Close()
eventualmente, mas não há nenhuma garantia de quanto tempo será necessário antes que o método Finalize()
seja invocado. Na verdade, não há nenhuma garantia de que Finalize()
nunca será invocado. Em um ambiente muito ativo, isso pode fazer com que a VM use todos os seus identificadores de arquivo disponíveis.Exemplo 2: Em condições normais, o código a seguir executa uma consulta de banco de dados, processa os resultados retornados pelo banco de dados e fecha o objeto
private void processFile(string fName) {
StreamWriter sw = new StreamWriter(fName);
string line;
while ((line = sr.ReadLine()) != null)
processLine(line);
}
SqlConnection
alocado. Porém, se ocorrer uma exceção durante a execução do SQL ou o processamento dos resultados, o objeto SqlConnection
não será fechado. Se isso acontecer com frequência suficiente, o banco de dados ficará sem cursores disponíveis e não poderá executar mais consultas SQL.
...
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(queryString);
cmd.Connection = conn;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
HarvestResults(rdr);
conn.Connection.Close();
...
int decodeFile(char* fName)
{
char buf[BUF_SZ];
FILE* f = fopen(fName, "r");
if (!f) {
printf("cannot open %s\n", fName);
return DECODE_FAIL;
} else {
while (fgets(buf, BUF_SZ, f)) {
if (!checkChecksum(buf)) {
return DECODE_FAIL;
} else {
decodeBlock(buf);
}
}
}
fclose(f);
return DECODE_SUCCESS;
}
CALL "CBL_CREATE_FILE"
USING filename
access-mode
deny-mode
device
file-handle
END-CALL
IF return-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
PERFORM write-data
IF ws-status-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
DISPLAY "Success!"
END-IF
END-IF
CALL "CBL_CLOSE_FILE"
USING file-handle
END-CALL
GOBACK
.
New()
estabelece uma nova conexão com o daemon de log do sistema. Faz parte do pacote log.syslog. Cada gravação para o gravador retornado envia uma mensagem de log com a prioridade fornecida (uma combinação do recurso e gravidade do syslog) e a tag de prefixo. Em um ambiente ocupado, isso pode fazer com que o sistema use todos os seus soquetes.Exemplo 2: Nesse exemplo, o método
func TestNew() {
s, err := New(syslog.LOG_INFO|syslog.LOG_USER, "the_tag")
if err != nil {
if err.Error() == "Unix syslog delivery error" {
fmt.Println("skipping: syslogd not running")
}
fmt.Println("New() failed: %s", err)
}
}
Dial()
do pacote net/smtp
retorna um novo cliente conectado a um servidor SMTP no localhost. Os recursos de conexão são alocados, mas nunca são liberados chamando a função Close()
.
func testDial() {
client, _ := smtp.Dial("127.0.0.1")
client.Hello("")
}
Arena.ofConfined()
não está fechado.
...
Arena offHeap = Arena.ofConfined()
MemorySegment str = offHeap.allocateUtf8String("data");
...
//offHeap is never closed
BEGIN
...
F1 := UTL_FILE.FOPEN('user_dir','u12345.tmp','R',256);
UTL_FILE.GET_LINE(F1,V1,32767);
...
END;
Camera
em seus manipuladores de eventos onPause()
, onStop()
ou onDestroy()
.Camera
que não é liberada em um retorno de chamada onPause()
, onStop()
ou onDestroy()
. O sistema operacional Android invoca esses retornos de chamada sempre que precisa enviar a atividade atual para segundo plano ou quando precisa destruir a atividade temporariamente nos casos em que o sistema está com poucos recursos. Ao não liberar o objeto Camera
corretamente, a atividade impede que outros aplicativos (ou até mesmo instâncias futuras do mesmo aplicativo) acessem a câmara. Além disso, manter a posse da instância de Camera
enquanto a atividade está pausada pode afetar negativamente a experiência do usuário por meio do esgotamento desnecessário da bateria.onPause()
base, que deve ser usado para liberar o objeto Camera
, nem o libera corretamente durante sua sequência de desligamento.
public class UnreleasedCameraActivity extends Activity {
private Camera cam;
@Override
public void onCreate(Bundle state) {
...
}
@Override
public void onRestart() {
...
}
@Override
public void onStop() {
cam.stopPreview();
}
}
MediaRecorder
, MediaPlayer
ou AudioRecord
em seus manipuladores de eventos onPause()
, onStop()
ou onDestroy()
.onPause()
, onStop()
ou onDestroy()
. O sistema operacional Android invoca esses retornos de chamada sempre que precisa enviar a atividade atual para segundo plano ou quando precisa destruir a atividade temporariamente nos casos em que o sistema está com poucos recursos. Ao não liberar o objeto de mídia corretamente, a atividade faz com que acessos subsequentes ao hardware de mídia do Android (por outros aplicativos ou até mesmo pelo mesmo aplicativo) retrocedam para as implementações de software ou até mesmo falhem completamente. Deixar abertas muitas instâncias de mídia não liberadas pode fazer com que o Android lance exceções, causando efetivamente uma negação de serviço. Além disso, manter a posse da instância de mídia enquanto a atividade está pausada pode afetar negativamente a experiência do usuário por meio do esgotamento desnecessário da bateria.onPause()
base, que deve ser usado para liberar o objeto de mídia, nem o libera corretamente durante sua sequência de desligamento.
public class UnreleasedMediaActivity extends Activity {
private MediaPlayer mp;
@Override
public void onCreate(Bundle state) {
...
}
@Override
public void onRestart() {
...
}
@Override
public void onStop() {
mp.stop();
}
}
onPause()
, onStop()
ou onDestroy()
.onPause()
, onStop()
ou onDestroy()
. O sistema operacional Android invoca esses retornos de chamada sempre que precisa enviar a atividade atual para segundo plano ou quando precisa destruir a atividade temporariamente nos casos em que o sistema está com poucos recursos. Ao não fechar o banco de dados corretamente, a atividade poderá esgotar cursores disponíveis do dispositivo se for reiniciada constantemente. Além disso, dependendo da implementação, o sistema operacional Android também pode lançar DatabaseObjectNotClosedException
, que travará o aplicativo se a exceção não for detectada.onPause()
base, que deve ser usado para liberar o objeto de banco de dados, nem o libera corretamente durante sua sequência de desligamento.
public class MyDBHelper extends SQLiteOpenHelper {
...
}
public class UnreleasedDBActivity extends Activity {
private myDBHelper dbHelper;
private SQLiteDatabase db;
@Override
public void onCreate(Bundle state) {
...
db = dbHelper.getWritableDatabase();
...
}
@Override
public void onRestart() {
...
}
@Override
public void onStop() {
db.insert(cached_data); // flush cached data
}
}
PWD_COMPARE
pode ser usado por um código que não tem acesso a sys.dba_users
para verificar a senha do usuário.
CREATE or REPLACE procedure PWD_COMPARE(p_user VARCHAR, p_pwd VARCHAR)
AUTHID DEFINED
IS
cursor INTEGER;
...
BEGIN
IF p_user != 'SYS' THEN
cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cursor, 'SELECT password FROM SYS.DBA_USERS WHERE username = :u', DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(cursor, ':u', p_user);
...
END IF;
END PWD_COMPARE;
sys
. Uma maneira de provocar uma exceção é transmitindo um argumento muito longo para p_user
. Depois que o invasor souber que o cursor vazou, ele só terá que adivinhar o cursor e atribuir novas variáveis de vínculo.
DECLARE
x VARCHAR(32000);
i INTEGER;
j INTEGER;
r INTEGER;
password VARCHAR2(30);
BEGIN
FOR i IN 1..10000 LOOP
x:='b' || x;
END LOOP;
SYS.PWD_COMPARE(x,'password');
EXCEPTION WHEN OTHERs THEN
FOR j IN 1..10000
DBMS_SQL.BIND_VARIABLE(j, ':u', 'SYS');
DBMS_SQL.DEFINE_COLUMN(j, 1, password, 30);
r := DBMS_SQL.EXECUTE(j);
IF DBMS_SQL.FETCH_ROWS(j) > 0 THEN
DBMS_SQL.COLUMN_VALUE(j, 1, password);
EXIT;
END IF;
END LOOP;
...
END;
DATA: result TYPE demo_update,
request TYPE REF TO IF_HTTP_REQUEST,
obj TYPE REF TO CL_SQL_CONNECTION.
TRY.
...
obj = cl_sql_connection=>get_connection( `R/3*my_conn`).
FINAL(sql) = NEW cl_sql_prepared_statement(
statement = `INSERT INTO demo_update VALUES( ?, ?, ?, ?, ?, ? )`).
CATCH cx_sql_exception INTO FINAL(exc).
...
ENDTRY.
SqlConnection
alocado. Mas, se ocorrer uma exceção durante a execução do SQL ou o processamento dos resultados, o objeto SqlConnection
não será fechado. Se isso acontecer com frequência suficiente, o banco de dados ficará sem cursores disponíveis e não poderá executar mais consultas SQL.
...
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(queryString);
cmd.Connection = conn;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
HarvestResults(rdr);
conn.Connection.Close();
...
- void insertUser:(NSString *)name {
...
sqlite3_stmt *insertStatement = nil;
NSString *insertSQL = [NSString stringWithFormat:@INSERT INTO users (name, age) VALUES (?, ?)];
const char *insert_stmt = [insertSQL UTF8String];
...
if ((result = sqlite3_prepare_v2(database, insert_stmt,-1, &insertStatement, NULL)) != SQLITE_OK) {
MyLog(@"%s: sqlite3_prepare error: %s (%d)", __FUNCTION__, sqlite3_errmsg(database), result);
return;
}
if ((result = sqlite3_step(insertStatement)) != SQLITE_DONE) {
MyLog(@"%s: step error: %s (%d)", __FUNCTION__, sqlite3_errmsg(database), result);
return;
}
...
}
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(CXN_SQL);
harvestResults(rs);
stmt.close();
func insertUser(name:String, age:int) {
let dbPath = URL(fileURLWithPath: Bundle.main.resourcePath ?? "").appendingPathComponent("test.sqlite").absoluteString
var db: OpaquePointer?
var stmt: OpaquePointer?
if sqlite3_open(dbPath, &db) != SQLITE_OK {
print("Error opening articles database.")
return
}
let queryString = "INSERT INTO users (name, age) VALUES (?,?)"
if sqlite3_prepare(db, queryString, -1, &stmt, nil) != SQLITE_OK{
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("error preparing insert: \(errmsg)")
return
}
if sqlite3_bind_text(stmt, 1, name, -1, nil) != SQLITE_OK{
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("failure binding name: \(errmsg)")
return
}
if sqlite3_bind_int(stmt, 2, age) != SQLITE_OK{
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("failure binding name: \(errmsg)")
return
}
if sqlite3_step(stmt) != SQLITE_DONE {
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("failure inserting user: \(errmsg)")
return
}
}
finalize()
para ZipFile
chama close()
por fim, mas não há nenhuma garantia de quanto tempo será necessário antes que o método finalize()
seja invocado. Em um ambiente muito ativo, isso pode fazer com que a JVM use todos os seus identificadores de arquivo.Exemplo 2: Em condições normais, a seguinte correção fecha corretamente o identificador de arquivo após a impressão de todas as entradas do arquivo zip. Porém, se uma exceção ocorrer durante a iteração através das entradas, o identificador de arquivo zip não será fechado. Se isso acontece com bastante frequência, a JVM ainda poderá ficar sem identificadores de arquivos disponíveis.
public void printZipContents(String fName) throws ZipException, IOException, SecurityException, IllegalStateException, NoSuchElementException {
ZipFile zf = new ZipFile(fName);
Enumeration<ZipEntry> e = zf.entries();
while (e.hasMoreElements()) {
printFileInfo(e.nextElement());
}
}
public void printZipContents(String fName) throws ZipException, IOException, SecurityException, IllegalStateException, NoSuchElementException {
ZipFile zf = new ZipFile(fName);
Enumeration<ZipEntry> e = zf.entries();
while (e.hasMoreElements()) {
printFileInfo(e.nextElement());
}
zf.close();
}