Como parte do nosso curso de introdução à segurança de computadores, temos uma breve unidade sobre injeções de SQL. Uma das tarefas de casa é uma página de login básica e não higienizada. A solução esperada é algo nos moldes do clássico ' or 1=1; --
, mas sempre recebemos estudantes para encontrar soluções não convencionais.
Uma dessas soluções me foi apresentada recentemente: a inserção '--'
da senha parece realizar uma injeção de SQL bem-sucedida. Isso faria com que a consulta fosse avaliada como algo como:
SELECT * FROM users WHERE name='admin' AND password=''--'';
Aqui, --'';
não é analisado como um comentário, pois o MariaDB exige que os comentários sejam seguidos de espaços. Na verdade, se o traço duplo fosse analisado como um comentário, esta consulta não retornaria nada; de forma equivalente, teríamos password=''
, que seria avaliado como falso, assumindo uma senha não vazia.
O par extra de aspas no final parece ser necessário: deixá-lo como password=''--;
ou inserir outros dados atrás dele ( password=''--1;
) faz com que a condicional seja avaliada como falsa, conforme esperado.
Alguns testes rápidos não conseguem reproduzir esse comportamento em outros bancos de dados - até onde eu sei, esse é um comportamento específico do MariaDB. A documentação confirma que dois travessões sem espaço não são analisados como um comentário, mas não detalha como são analisados. EDIT: De alguma forma, consegui ignorar o fato de que isso também acontece no MySQL. Na verdade, esse comportamento ocorre em qualquer fork do MySQL (não apenas no MariaDB).
O que --
acontece quando não é seguido por um espaço e por que faz com que as comparações sejam avaliadas como verdadeiras?
Um exemplo de brinquedo:
CREATE TABLE users (
userid INTEGER PRIMARY KEY,
username TEXT NOT NULL,
password TEXT NOT NULL
);
INSERT INTO users VALUES (0001, 'admin', 'S3cur3P4ssw0rd!');
INSERT INTO users VALUES (0002, 'generic_user', 'Password');
SELECT * FROM users WHERE username='admin' AND password=''; -- empty password, query returns no users
SELECT * FROM users WHERE username='admin' AND password=''-- ''; -- parsed as comment, equivalent to above query, returns no users
SELECT * FROM users WHERE username='admin' AND password=''--''; -- query returns admin user
SELECT * FROM users WHERE username='admin' AND password=''--; -- query returns zero users
SELECT * FROM users WHERE username='admin' AND password=''--1; -- query returns zero users
Esta injeção SQL específica usa dois aspectos:
Primeiro,
--
sem o espaço, juntamente com um valor atrás dele, é analisado como uma subtração de um número negativo. Quando você executa a consultaVocê obterá o seguinte resultado:
Então, quando você executa a consulta
Você obtém o resultado do primeiro número (
0
) menos o segundo número negativo (-0
), que resulta em0
.A segunda parte é que o MariaDB (e o MySQL) tentam converter uma string em um número quando o contexto exige que seja um número. Veja a seguinte consulta:
Isso não resulta em nada de especial:
mas quando você faz aritmética assim
você entende isso:
Isso pode ser usado contra você com a aritmética acima com um valor que resulta em
0
. A perguntamostrará os seguintes resultados (adicionei um novo usuário com um número no início da senha):
Aqui você vê, ele primeiro converterá a senha em um número, provavelmente
0
, e depois a comparará com "seu"0
valor de''--''
, resultando em uma injeção de SQL bem-sucedida.