¿Cómo puede el saneamiento que escapa a las comillas simples ser derrotado por la inyección SQL en SQL Server?


Para empezar, soy muy consciente de que las consultas parametrizadas son la mejor opción, pero me pregunto qué hace que la estrategia que presento a continuación sea vulnerable. La gente insiste en que la solución a continuación no funciona, así que estoy buscando un ejemplo de por qué no lo haría.

Si SQL dinámico está construido en código usando el siguiente escape antes de ser enviado a un servidor SQL, ¿qué tipo de inyección puede derrotar esto?

string userInput= "N'" + userInput.Replace("'", "''") + "'"

Una pregunta similar fue respondida aquí, pero no creo que ninguno de los las respuestas son aplicables aquí.

Escapar de la comilla simple con un "\" no es posible en SQL Server.

Creo que El contrabando SQLcon Unicode (descrito aquí) se vería frustrado por el hecho de que la cadena que se produce está marcada como Unicode por la N que precede a la comilla simple. Por lo que sé, no hay otros conjuntos de caracteres que SQL Server traduzca automáticamente a una sola comilla. Sin una sola cita sin escapar, no creo que la inyección es posible.

No creo que el Truncamiento de cadena sea un vector viable tampoco. SQL Server ciertamente no hará el truncamiento ya que el tamaño máximo para un nvarchar es de 2 GB según microsoft. Una cadena de 2 GB es inviable en la mayoría de las situaciones, e imposible en la mía.

La inyección de segundo orden podría ser posible, pero es posible si:

  1. Todos los datos que entran en la base de datos se desinfectan utilizando el método anterior
  2. Valores de la las bases de datos nunca se agregan a SQL dinámico (¿por qué haría eso de todos modos, cuando solo puede hacer referencia al valor de la tabla en la parte estática de cualquier cadena SQL dinámica?).

No estoy sugiriendo que esto sea mejor o una alternativa al uso de consultas parametrizadas, pero quiero saber cómo lo que he descrito es vulnerable. Alguna idea?

Author: Community, 2013-03-21

6 answers

Hay algunos casos en los que esta función de escape fallará. Lo más obvio es cuando no se usa una comilla simple:

string table= "\"" + table.Replace("'", "''") + "\""
string var= "`" + var.Replace("'", "''") + "`"
string index= " " + index.Replace("'", "''") + " "
string query = "select * from `"+table+"` where name=\""+var+"\" or id="+index

En este caso, puede "romper" usando una comilla doble, una marca de retroceso. En el último caso no hay nada que" romper", por lo que solo puede escribir 1 union select password from users-- o cualquier carga sql que el atacante desee.

La siguiente condición en la que esta función de escape fallará es si se toma una sub-cadena después de que se escape la cadena (y Tengo vulnerabilidades encontradas como esta en la naturaleza):

string userPassword= userPassword.Replace("'", "''")
string userName= userInput.Replace("'", "''")
userName = substr(userName,0,10)
string query = "select * from users where name='"+userName+"' and password='"+userPassword+"'";

En este caso, un nombre de usuario de abcdefgji' se convertirá en abcdefgji'' mediante la función escape y luego se convertirá en abcdefgji' tomando la sub-cadena. Esto se puede explotar estableciendo el valor de la contraseña a cualquier instrucción sql, en este caso or 1=1-- se interpretaría como sql y el nombre de usuario se interpretaría como abcdefgji'' and password=. La consulta resultante es la siguiente:

select * from users where name='abcdefgji'' and password=' or 1=1-- 

T-SQL y otras técnicas avanzadas de inyección sql donde ya indicado. Advanced SQL Injection In SQL Server Applications es un gran documento y debería leerlo si aún no lo ha hecho.

El problema final son los ataques unicode. Esta clase de vulnerabilidades surge porque la función escape no es consciente de la codificación mulit-byte, y esto puede ser utilizado por un atacante para "consumir" el carácter de escape. Anteponer una " N " a la cadena no ayudará, ya que esto no afecta el valor de los caracteres multi-byte más adelante en la cadena. Sin embargo, este tipo de ataque es muy poco común porque la base de datos debe estar configurada para aceptar cadenas GBK unicode (y no estoy seguro de que MS-SQL pueda hacer esto).

La inyección de código de segundo orden todavía es posible, este patrón de ataque se crea confiando en las fuentes de datos controladas por el atacante. El escape se usa para representar caracteres de control como literales de caracteres. Si el desarrollador olvida escapar un valor obtenido de un select y luego usa este valor en otra consulta, entonces bam el atacante tendrá una comilla literal de carácter a su disposición.

Prueba todo, no confíes en nada.

 34
Author: rook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-06 07:19:02

Con algunas estipulaciones adicionales, su enfoque anterior no es vulnerable a la inyección SQL. El principal vector de ataque a considerar es el contrabando SQL. El contrabando SQL ocurre cuando los caracteres unicode similares se traducen de una manera inesperada (por ejemplo, ` cambiando a ' ). Hay varias ubicaciones donde una pila de aplicaciones podría ser vulnerable al contrabando de SQL.

  • ¿El lenguaje de programación maneja adecuadamente las cadenas unicode? Si el idioma no es unicode consciente, puede identificar mal un byte en un carácter unicode como una comilla simple y escapar de él.

  • ¿La biblioteca de la base de datos del cliente (por ejemplo, ODBC, etc.) maneja adecuadamente las cadenas unicode? Sistema.Datos.SqlClient en. Net framework lo hace, pero ¿qué hay de las bibliotecas antiguas de la era de Windows 95? En realidad existen bibliotecas ODBC de terceros. ¿Qué sucede si el controlador ODBC no admite unicode en la cadena de consulta?

  • La base de datos maneja la entrada correctamente? Las versiones modernas de SQL son inmunes asumiendo que estás usando N", pero ¿qué pasa con SQL 6.5? SQL 7.0? No soy consciente de ninguna vulnerabilidad en particular, sin embargo, esto no estaba en el radar para los desarrolladores en la década de 1990.

  • ¿Desbordamientos de búfer? Otra preocupación es que la cadena entre comillas es más larga que la cadena original. ¿En qué versión de Sql Server se introdujo el límite de 2 GB para la entrada? Antes de eso, ¿cuál era el límite? En versiones anteriores de SQL, lo que sucedió cuando una consulta excedió el límite? ¿Existen límites en la longitud de una consulta desde el punto de vista de la biblioteca de red? O en la longitud de la cadena en el lenguaje de programación?

  • ¿Hay alguna configuración de idioma que afecte a la comparación utilizada en la función Replace ()?. Net siempre hace una comparación binaria para la función Replace (). ¿Siempre será así? Qué sucede si una versión futura de.NET admite la anulación de ese comportamiento en la aplicación.config nivel? ¿Qué pasa si usamos una regexp en lugar de Replace() para insertar una comilla simple? ¿Afecta la configuración regional del equipo a esta comparación? Si se produjo un cambio en el comportamiento, podría no ser vulnerable a la inyección sql, sin embargo, puede haber editado inadvertidamente la cadena cambiando un carácter de código uni que parecía una comilla simple en una comilla simple antes de que llegara a la base de datos.

Entonces, asumiendo que estás usando el Sistema.Cadena.Función Replace () en C # en la actual versión de. Net con la biblioteca SqlClient incorporada en comparación con una versión actual (2005-2012) de SQL server, entonces su enfoque no es vulnerable. A medida que empiezas a cambiar las cosas, entonces no se pueden hacer promesas. El enfoque de consulta parametrizada es el enfoque correcto para la eficiencia, el rendimiento y (en algunos casos) la seguridad.

ADVERTENCIA Los comentarios anteriores no son una aprobación de esta técnica. Hay varias otras muy buenas razones por las que este es el enfoque equivocado para generando SQL. Sin embargo, detallarlos está fuera del alcance de esta pregunta.

NO UTILICE ESTA TÉCNICA PARA NUEVOS DESARROLLOS.

NO UTILICE ESTA TÉCNICA PARA NUEVOS DESARROLLOS.

NO UTILICE ESTA TÉCNICA PARA NUEVOS DESARROLLOS.

 16
Author: StrayCatDBA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-29 19:18:47

Usar parámetros de consulta es mejor, más fácil y más rápido que escapar comillas.


Con respecto a su comentario, veo que reconoció la parametrización, pero merece énfasis. ¿Por qué querría usar escape cuando podría parametrizar?

En Advanced SQL Injection In SQL Server Applications, busque la palabra "replace" en el texto y, a partir de ese momento, lea algunos ejemplos donde los desarrolladores permitieron inadvertidamente ataques de inyección SQL incluso después de escapando la entrada del usuario.


Hay un caso de borde donde escapar comillas con \ resulta en una vulnerabilidad, porque el \ se convierte en la mitad de un carácter multibyte válido en algunos conjuntos de caracteres. Pero esto no es aplicable a su caso ya que \ no es el carácter de escape.

Como otros han señalado, también puede agregar contenido dinámico a su SQL para algo que no sea un literal de cadena o un literal de fecha. Los identificadores de tabla o columna están delimitados por " en SQL, o [ ] en Microsoft / Sybase. Por supuesto, las palabras clave SQL no tienen delimitadores. Para estos casos, recomiendo incluir en la lista blanca los valores a interpolar.

La conclusión es que escapar es una defensa efectiva, si puedes asegurarte de hacerlo consistentemente. Ese es el riesgo: que uno del equipo de desarrolladores en su aplicación podría omitir un paso y hacer alguna interpolación de cadenas de forma insegura.

Por supuesto, lo mismo es cierto de otros métodos, como parametrización. Solo son efectivos si los haces constantemente. Pero encuentro que es más fácil usar parámetros más rápido que averiguar el tipo correcto de escape. Y es más probable que los desarrolladores usen un método que sea conveniente y no los ralentice.

 9
Author: Bill Karwin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-30 14:15:36

La inyección SQL se produce si las entradas suministradas por el usuario se interpretan como comandos. Aquí comando significa cualquier cosa que no se interpreta como un reconocido tipo de datos literal.

Ahora bien, si está utilizando la entrada del usuario solo en literales de datos, específicamente solo en literales de cadena, la entrada del usuario solo se interpretaría como algo diferente a los datos de cadena si pudiera dejar el contexto literal de la cadena. Para literales de cadena de caracteres o cadena Unicode, es la comilla simple la marca que encierra los datos literales mientras que las comillas simples incrustadas deben representarse con dos comillas simples.

Por lo tanto, para dejar un contexto literal de cadena, uno necesitaría proporcionar una sola comilla simple (sic) ya que dos comillas simples se interpretan como datos literales de cadena y no como el delimitador final literal de cadena.

Entonces, si está reemplazando cualquier comilla simple en los datos suministrados por el usuario por dos comillas simples, será imposible para el usuario debe dejar el contexto literal de la cadena.

 4
Author: Gumbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-21 06:27:00

La inyección SQL puede ocurrir a través de unicode. Si la aplicación web tiene una URL como esta:

Http://mywebapp/widgets/?Code = ABC

Que genera SQL like seleccione * de los widgets donde Code = ' ABC '

Pero un hacker entra en esto:

Http://mywebapp/widgets/?Code = ABC % CA % BC; drop widgets de tabla {

El SQL se verá como seleccione * de los widgets donde Code = 'ABC'; drop table widgets {'

Y SQL Server ejecutará dos sentencias SQL. Uno para hacer el select y uno para hacer el drop. Su código probablemente convierte la url codificada % CA % BC en unicode U02BC que es un "apóstrofo de letra modificador". La función Reemplazar en. Net NO tratará eso como una comilla simple. Sin embargo, Microsoft SQL Server lo trata como una comilla simple. Aquí hay un ejemplo que probablemente permitirá la inyección SQL:

string badValue = ((char)0x02BC).ToString();
badValue = badValue + ";delete from widgets--";
string sql = "SELECT * FROM WIDGETS WHERE ID=" + badValue.Replace("'","''");
TestTheSQL(sql);
 3
Author: Rob Kraft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-30 14:24:37

Probablemente no haya una forma 100% segura si está haciendo concatenación de cadenas. Lo que puede hacer es intentar verificar el tipo de datos para cada parámetro y si todos los parámetros pasan dicha validación, continúe con la ejecución. Por ejemplo, si su parámetro debe ser type int y está obteniendo algo que no se puede convertir a int, simplemente rechácelo.

Esto no funciona si estás aceptando parámetros nvarchar.

Como ya han señalado otros. La forma más segura es usar consulta parametrizada.

 2
Author: George Wesley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-21 10:14:47