Log Parser es una herramienta que permite analizar gran cantidad de datos de forma muy eficiente utilizando una sintaxis similar a SQL. Log Parser soporta una serie de formatos de entrada y de salida, estos son algunos:
FORMATOS DE ENTRADA
(W3C) - Logs de IIS
(HTTPERR) - Logs de HTTP.sys
(EVT) - Logs de eventos NT
(ETW) - Logs de ETW
(URLSCAN) - Logs de URLSCAN
(NETMON) - Trazas de Network Monitor
(XML) - Ficheros XML genéricos
(TEXTWORD) – Ficheros TXT genéricos
Etc.
FORMATOS DE SALIDA
(NAT) - Columnas Tabuladas
(CSV) - Comma Separated Value
(TSV) - Tab Separated Value
(XML) - XML
Para el análisis de logs de IIS, una de las grandes cualidades de Log Parser es que se pueden realizar consultas sobre múltiples ficheros de log simultáneamente (por ejemplo, la carpeta entera de logs de IIS) de forma que podemos filtrar y agregar varios GB de datos y obtener sólo la información que nos interesa.
A mí personalmente me resulta más cómodo guardar las queries de Log Parser en ficheros *.bat dado que habitualmente hay que hacer pequeñas modificaciones y es fácil que se nos cuele algún error de sintaxis, y localizarlo y corregirlo en una consola de comandos CMD.EXE puede ser un poco tedioso.
A continuación os muestro algunos ejemplos de consultas de Log Parser que me han resultado útiles en alguna ocasión analizando logs de IIS. Dado que Log Parser no permite incluir retornos de carro en la cadena que contiene la query, las consultas se hacen menos legibles. Espero que aún así, los ejemplos sean los suficientemente claros.
¿Qué paginas tardan más tiempo en ejecutarse?
CONSULTA:
C:\program files\log parser 2.2>logparser.exe "SELECT COUNT(*) As Hits, AVG(time-taken) As AverageTimeTaken, MAX(time-taken) As MaxTimeTaken, TO_LOWERCASE(cs-uri-stem), sc-status, sc-substatus INTO [nombre_fichero_salida].txt FROM [ruta_completa_logs_IIS]\ex*.log GROUP BY TO_LOWERCASE(cs-uri-stem), sc-status, sc-substatus HAVING Hits > 10 ORDER BY AverageTimeTaken DESC" -i:IISW3C -o:NAT -rtp:-1
RESULTADO:
Hits AverageTimeTaken MaxTimeTaken TO_LOWERCASE(cs-uri-stem) sc-status sc-substatus
---- ---------------- ------------ ----------------------------------- --------- ------------
13 58496 388546 /index.html 401 5
60 2860 35577 /delegconfig/default.aspx 200 0
28 1481 10874 /delegconfig/default.aspx 401 5
13 1328 1328 / 401 2
13 299 734 /delegconfig 401 2
26 35 578 /delegconfig/default.aspx 401 2
12 33 78 /index.html 200 0
13 29 93 /delegconfig/wrkstainfo.dll 200 0
14 26 62 /delegconfig/images/information.gif 200 0
13 22 109 /delegconfig/scripts/images.js 200 0
…
Extraer todos los errores HTTP registrados
C:\program files\log parser 2.2>logparser.exe "SELECT cs-uri-stem, cs-method As meth, sc-status As stat, sc-substatus As substat, WIN32_ERROR_DESCRIPTION(sc-win32-status) as sc-win32-desc INTO [nombre_fichero_salida].txt FROM [ruta_completa_logs_IIS]\ex*.log WHERE sc-status BETWEEN 400 AND 599" -i:IISW3C -o:NAT -rtp:-1
cs-uri-stem meth stat substat sc-win32-desc
------------------------- ---- ---- ------- ---------------------------------------------------
/DelegConfig/Default.aspx GET 401 2 No credentials are available in the security pack…
/DelegConfig/Default.aspx GET 401 1 The operation completed successfully.
/DelegConfig/SetSPN.aspx POST 401 1 The operation completed successfully.
/prueba/ GET 403 14 Access is denied.
/DelegConfig GET 401 2 No credentials are available in the security pack…
/DelegConfig GET 401 1 The operation completed successfully.
/iisadmpwd/anot3.asp GET 404 0 The operation completed successfully.
/DelegConfig/Default.aspx GET 404 2 The operation completed successfully.
Extraer todas las peticiones que se han realizado desde una IP específica
C:\program files\log parser 2.2>logparser.exe "SELECT date, time, time-taken, c-ip, cs-uri-stem, sc-status INTO [nombre_fichero_salida].txt FROM [ruta_completa_logs_IIS]\ex*.log WHERE c-ip = '157.58.114.46'" -i:IISW3C -o:NAT -rtp:-1
date time time-taken c-ip cs-uri-stem sc-status
---------- -------- ---------- ------------- -------------------------------------- ---------
2007-08-21 13:19:20 15 157.58.114.46 /DelegConfig/Images/Information.gif 200
2007-08-21 13:19:21 15 157.58.114.46 /DelegConfig/Images/Warning.gif 200
2007-12-14 12:06:35 593 157.58.114.46 / 401
2007-12-14 12:06:42 390 157.58.114.46 /iisadmpwd/anot3.asp 404
2007-12-14 12:08:07 31 157.58.114.46 /index.html 200
2007-12-14 12:08:15 62 157.58.114.46 /index.html 200
2007-12-14 13:07:31 11858 157.58.114.46 /DelegConfig/Default.aspx 200
2007-12-14 13:07:31 15 157.58.114.46 /DelegConfig/Scripts/StyleSheet.css 200
2007-12-14 13:07:38 0 157.58.114.46 /iexplore.exe.config 404
2007-12-14 13:07:41 2390 157.58.114.46 /DelegConfig/Default.aspx 200
Extraer todos los intentos de ataque de inyección de SQL a mi sitio web
C:\program files\log parser 2.2>logparser.exe "SELECT * INTO [nombre_fichero_salida].txt FROM [ruta_completa_logs_IIS]\ex*.log WHERE cs-uri-query LIKE '%CAST(%' OR cs-uri-query LIKE '%DECLARE%'" -i:IISW3C -o:NAT -rtp:-1
Espero que estos ejemplos os den una idea del tipo de información que podemos sacar de los logs de IIS. En cuanto a los temas de seguridad, como el ejemplo de inyección de SQL, aclarar que la query es meramente un ejemplo. El hecho de que dicha query no de resultados, no significa que el sitio web no haya sido atacado o sea susceptible a un ataque.
Para ampliar la información sobre los ataques de inyección de SQL, como detectarlos y prevenirlos, consultad los siguientes enlaces:
Filtering SQL injection from Classic ASP
http://blogs.iis.net/nazim/archive/2008/04/28/filtering-sql-injection-from-classic-asp.aspx
Anatomy of a SQL Injection Incident
http://blogs.technet.com/neilcar/archive/2008/03/14/anatomy-of-a-sql-injection-incident.aspx
SQLInjectionFinder.exe: herramienta para detección automática de ataques de inyección de SQL
http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=WSUS&ReleaseId=13436
En el momento de escribir este post la versión actual es Log Parser 2.2 y se puede descargar desde aquí.
Espero que os haya sido de utilidad. Hasta la próxima.
- Daniel Mossberg
Recientemente estuve trabajando en un caso que presentaba los siguientes síntomas: tras actualizar el sistema operativo de un servidor pasando de Windows Server 2003 RTM a SP2, el cliente observaba que al realizar peticiones a la aplicación web, el servidor siempre respondía con un error HTTP 503 - Service Unavailable. El log de eventos de sistema mostraba el siguiente evento indicando que el worker process de IIS (W3WP.EXE) finalizaba inesperadamente y devolvía el código de salida 0xffffffff:
Event Type: Warning
Event Source: W3SVC
Event Category: None
Event ID: 1009
Date: 17/04/2009
Time: 14:30:45
User: N/A
Computer: MYSERVER
Description: A process serving application pool 'DefaultAppPool' terminated unexpectedly. The process id was '1234'. The process exit code was '0xffffffff'.
El código de salida 0xffffffff es un código genérico que se puede dar por diversos motivos al inicializar el proceso W3WP.EXE (las más comunes son problemas al inicializar COM y problemas al cargar una DLL). Esta es su definición:
// the worker process exited due to a fatal error#define ERROR_WORKER_PROCESS_EXIT_CODE 0xFFFFFFFF
Una de las primeras pruebas que hicimos fue cambiar la identidad del application pool de NETWORK SERVICE a LOCAL SYSTEM. Haciendo esto vimos que el worker process se levantaba correctamente y la aplicación web servía peticiones correctamente. Por lo tanto estaba claro que era un problema de permisos, ¿pero cuál era el permiso que faltaba y porqué funcionaba sin problemas antes de actualizar a SP2?
Capturamos unas trazas con Process Monitor (configurando de nuevo la identidad del application pool como NETWORK SERVICE) que nos mostraban que se producía un acceso denegado en la rama del registro HKLM\System\CurrentControlSet\Services\W3SVC\Parameters poco antes de finalizar el proceso. Tras proporcionar permisos de lectura a la cuenta NETWORK SERVICE en dicha clave del registro, el acceso denegado ya no se producía, pero el problema original seguía ocurriendo.
Verificamos todos los permisos de las cuentas de servicio de IIS 6.0 tal y como vienen documentados en el KB Default permissions and user rights for IIS 6.0, pero todos los permisos mencionados en el artículo estaban configurados correctamente.
Finalmente, revisando los permisos de DCOM, observamos que el grupo de seguridad Everyone (Todos) no tenía los permisos DCOM predeterminados de Local Launch y Local Activation, tal y como viene indicado en el artículo DCOM Security Enhancements. Añadiendo el grupo de seguridad Everyone y proporcionando dichos permisos, el problema quedaba resuelto y logramos levantar el application pool con la identidad NETWORK SERVICE.
El motivo por el que esta configuración funcionaba en Windows Server 2003 RTM es debido a que como parte de SP1 se introdujeron mejoras en la seguridad de COM que incluyen comprobaciones adicionales para cada llamada, activación o inicio de cualquier servidor COM del equipo. Dichos cambios vienen documentados en el enlace al que hacía referencia antes (DCOM Security Enhancements).
Por último, si os encontráis con este problema y no fuera debido a la misma causa, podéis consultar el blog de Brian Murphy, ingeniero de escalación de IIS, donde hay un excelente post con otras posibles causas y soluciones para el evento 1009 de IIS: http://blogs.iis.net/brian-murphy-booth/archive/2007/03/22/how-to-troubleshoot-an-iis-event-id-1009-error.aspx.
Actualización (21 de diciembre de 2009): Recientemente se ha manifestado un problema con algunas instalaciones de IIS 6.0, en las que tras instalar la actualización KB973917 el worker process no arranca y en los logs de eventos vemos el evento 1009. Este problema se soluciona reinstalando el SP2 de Windows Server 2003. Más información sobre este problema en el siguiente KB:
Internet Information Services 6.0 may not function correctly after installing KB973917
http://support.microsoft.com/?kbid=2009746
Hasta el próximo post.
Con cierta frecuencia tenemos casos de soporte de aplicaciones ASP.NET que dan problemas debido al uso de las clases de System.Drawing. El uso de del namespace System.Drawing no está soportado desde una aplicación ASP.NET (o cualquier otro servicio de Windows), lo cual pilla por sorpresa a más de uno. El motivo es que System.Drawing utiliza las APIs de GDI/GDI+ que no han sido diseñadas para ejecutarse en un entorno de alta concurrencia y además requieren ejecutarse una sesión de Windows interactiva. Esta limitación está documentada en la referencia de MSDN para System.Drawing y GDI+.
En Windows Server 2003, Windows XP y anteriores, podíamos utilizar parte de la funcionalidad de GDI desde una aplicación ASP.NET siempre y cuando no se produjera interacción con el monitor ni con ningún driver de video. Es decir, se podían utilizar objetos simples (líneas, formas en 2D, colores sólidos, etc.) de forma soportada. Gráficos más complejos (por ejemplo gráficos en 3D) que utilizan GDI+ no estaban soportados en ningún caso, al margen de que la aplicación ASP.NET aparentemente pudiera llegar a funcionar. En todo caso mi recomendación es que si no sabes exactamente lo que estás haciendo, no utilices System.Drawing en tus aplicaciones ASP.NET nunca.
En Windows Server 2008 y Windows Vista, dado que los servicios ahora corren en la sesión 0 donde no se permite el acceso al driver de video (por diseño del sistema operativo), toda la funcionalidad de GDI+ deja de funcionar por completo ya que requiere acceso a dicho driver. En cierto modo esto es una ventaja ya que así no tenemos la falsa percepción de que nuestra aplicación está funcionando correctamente cuando no es así.
¿Pero entonces cuál es la forma correcta de crear/manipular gráficos desde una aplicación ASP.NET? No existe una respuesta sencilla, estas son algunas alternativas que se me ocurren:
· Desarrollar un ejecutable separado que corra en una sesión interactiva de Windows. Este proceso será el encargado de la generación/manipulación de gráficos, y se comunicará con el proceso de IIS mediante IPC (interprocess communication).
· Migrar la lógica de generación de gráficos a una aplicación Silverlight (particularmente interesante en este aspecto es Silverlight 3, que está actualmente en Beta 1).
Adicionalmente, y aunque no manipulemos gráficos en nuestra aplicación ASP.NET, todo el código de servidor relacionado con la interfaz gráfica de nuestra aplicación web debe moverse a su equivalente en HTML/CSS en lugar de utilizar código de servidor. Es decir, por ejemplo es aconsejable sustituir este tipo de código de servidor:
MyBase.BackColor = Drawing.Color.FromArgb(255, 255, 255)
Por su equivalente en HTML/CSS combinado con código de servidor:
<style type="text/css">
.whitebackground { background-color:#ffffff;}
</style>
MyBase.CssClass = "whitebackground";
Lo dicho, evitad System.Drawing en vuestras aplicaciones ASP.NET. Hasta la próxima.
El otro día leí un artículo que aseguraba que más de la mitad de las vulnerabilidades de software detectadas entre 2006 y 2008 eran relativas a aplicaciones Web. Dicho artículo no desvelaba la fuente de ese dato, por lo que no puedo asegurar su veracidad, pero me dió que pensar. En Microsoft llevamos tiempo desarrollando varias herramientas para ayudar a los desarrolladores a escribir código más seguro, especialmente código de aplicaciones web. Os invito a que os descarguéis y probéis estas herramientas para mejorar la seguridad de vuestras aplicaciones web (y de paso que visitéis el blog del grupo dentro de Microsoft que las desarrolla: Connected Information Security Group - http://blogs.msdn.com/cisg).
Microsoft Threat Analysis & Modeling v2.1.2Esta herramienta nos permite identificar amenazas en la arquitectura y diseño de nuestras aplicaciones, sin necesidad de tener ningún conocimiento previo en temas de seguridad. La aplicación recaba datos sobre los componentes, roles de usuarios, casos de uso, dependencias externas, etc. de la aplicación, y a partir de estos datos identifica amenazas y proporciona recomendaciones sobre cómo definir una estrategia de seguridad adecuada a nuestro entorno.
Microsoft Code Analysis Tool .NET (CAT.NET) v1 CTP - 32 bit
CAT.NET es una herramienta de análisis de código .NET (realmente es un snap-in para Visual Studio 2005 y 2008) que nos ayuda identificar vulnerabilidades de Cross-Site Scripting y otros tipos de ataques relacionados con inyección de datos (SQL Injection, LDAP injection, etc.).
Microsoft Anti-Cross Site Scripting Library V3.0 Beta
Microsoft Anti-Cross Site Scripting (AntiXSS) ha sido diseñada para ayudar a desarrolladores a proteger sus aplicaciones de ataques de Cross-Site Scripting mediante validación de parámetros de entrada y codificación de la salida. Tal y como revela OWASP (Open Web Application Security Project) en su ranking Top 10 web application vulnerabilities, el Cross-Site Scripting es la vulnerabilidad más frecuente en aplicaciones web.
Microsoft Source Code Analyzer for SQL Injection
Esta herramienta analiza el código de nuestras aplicaciones ASP en busca de vulnerabilidades de inyección de SQL.
Failed Request Tracing (también conocido como FREB) es una nueva característica de IIS 7.0 que nos permite generar trazas granulares de peticiones HTTP fallidas. Las principales ventajas que nos aporta FREB son las siguientes:
· Nos permite definir las condiciones bajo las que una petición se considera “fallida”
§ Errores HTTP: p. ej., siempre que se produzca un error HTTP 403.13, o un error entre el rango HTTP 401-599.
§ Tiempo en ejecución: p. ej., todas las peticiones que tarden más de 5 segundos en ejecutarse.
§ Severidad del evento: p. ej., warning, error o critical error.
· Nos da total flexibilidad para configurar el tracing para una única URL específica, para un directorio virtual, para una aplicación o para un sitio web entero.
· Nos permite definir acciones personalizadas (p. ej. ejecutar un script) cuando se da una situación de error.
FREB resulta especialmente útil para capturar trazas de errores (o situaciones) que ocurren “aleatoriamente” y que no podemos reproducir con facilidad. La gran ventaja es que las trazas están habilitadas en todo momento, pero los datos sólo se guardan cuando se cumplen las condiciones que queremos investigar. Para configurar FREB, podéis leer este post del grupo de producto de IIS, que es un excelente tutorial para iniciarse con esta funcionalidad de IIS 7.0.
Una de las características más potentes de FREB es la posibilidad de realizar acciones personalizadas cuando se da una condición de error. Por ejemplo, podemos utilizar FREB para generar volcados de memoria con adplus.vbs cuando las peticiones HTTP tarden más de 5 segundos en ejecutarse.
Para ello tendríamos que hacer lo siguiente:
1) En el applicationHost.config tenemos que habilitar FREB y las acciones personalizadas. Esto lo podemos hacer editando directamente el fichero applicationHost.config (no aconsejado) o ejecutando el siguiente comando de appcmd.exe (en el ejemplo para el sitio web Default Web Site). Para habilitar FREB ejecutaremos el siguiente comando:
C:\Windows\System32\inetsrv> appcmd set config /section:system.applicationHost/sites "-[name='Default Web Site'].traceFailedRequestsLogging.enabled:true"
Y para habilitar las acciones personalizadas, ejecutaremos el siguiente:
C:\Windows\System32\inetsrv> appcmd set config /section:system.applicationHost/sites "-[name='Default Web Site'].traceFailedRequestsLogging.customActionsEnabled:true"
2) Posteriormente declaramos la regla de FREB, lo cual podemos hacer en el applicationHost.config o en el web.config de la aplicación web en cuestión. Los parámetros customActionExe, customActionParams y customActionTriggerLimit no se pueden configurar desde la interfaz gráfica del IIS Manager.
<configuration>
<system.webServer>
<tracing>
<traceFailedRequests>
<remove path="*" />
<add path="*"
customActionExe="C:\windows\system32\cscript.exe"
customActionParams="C:\debugger\adplus.vbs -hang
-pn w3wp.exe -o C:\MyDumps -quiet"
customActionTriggerLimit="10">
<traceAreas>
<add provider="WWW Server"
areas="RequestNotifications"
verbosity="Verbose" />
</traceAreas>
<failureDefinitions timeTaken="00:00:05" />
</add>
</traceFailedRequests>
</tracing>
</system.webServer>
</configuration>
Hasta el próximo post,
Una de las novedades que introduce IIS 7.0 en la autenticación de Windows (NTLM o Kerberos) es que ahora se realiza en modo Kernel por defecto. Este cambio se introdujo principalmente por dos motivos:
1) El cambio supone significativas mejoras de rendimiento.
2) Se simplifica el despliegue del protocolo de autenticación Kerberos.
Precisamente sobre el segundo punto es sobre el que os quería hablar. Para los que alguna vez os hayáis peleado con la configuración Kerberos, sabréis que requiere realizar una serie de pasos no necesariamente triviales como:
· Verificar que IIS está configurado para soportar autenticación por Kerberos (W3SVC/…/NTAuthenticationProviders = “Negotiate,NTLM”)
· Registrar los Service Principal Names (SPNs) para las cuentas de servicio
· Configurar las cuentas de servicio como Trusted for Delegation en directorio activo (si vamos a hacer delegación de credenciales)
· Etc.
Podéis encontrar una referencia más completa sobre configuración de Kerberos en el siguiente artículo:
How to use SPNs when you configure Web applications that are hosted on IIS 6.0
http://support.microsoft.com/kb/929650/en-us
En IIS 6.0 (y anteriores versiones) debíamos registrar dos SPNs para cada sitio web, un SPN para el nombre NetBios del servidor y otro para el FQDN (Fully Qualified Domain Name), ambos asociados a la cuenta bajo la que corre el servicio (la identidad del application pool en IIS 6.0):
setspn.exe –a HTTP/webServer DOMAIN\AppPoolAccount
setspn.exe –a HTTP/webServer.domain.com DOMAIN\AppPoolAccount
De esta forma, cuando un cliente (por ejemplo Internet Explorer) pida un ticket de Kerberos al KDC (Key Distribution Center) para autenticarse contra nuestro servidor web, dicho ticket irá cifrado con la clave de la cuenta DOMAIN\AppPoolAccount, y únicamente dicho servicio será capaz de descifrar el ticket. Estas claves simétricas en las que se basa Kerberos se obtienen a partir de las contraseñas de la cuentas (tanto para cuentas de usuario como cuentas de máquina) pasándolas por un algoritmo criptográfico.
En IIS 7.0 (configurado por defecto) ya no se utilizará la clave de la cuenta de servicio para descifrar el ticket de Kerberos que recibe de Internet Explorer (continuando con el ejemplo anterior). Ahora se utilizará la clave de la cuenta de máquina del servidor (DOMAIN\webServer$) puesto que la autenticación se realiza en modo Kernel. Por lo tanto, debemos o bien registrar los SPNs asociados a la cuenta de máquina, o simplemente no registrarlos.
setspn.exe –a HTTP/webServer DOMAIN\webServer$
setspn.exe –a HTTP/webServer.domain.com DOMAIN\webServer$
Si no registramos los SPNs específicos para el service class de HTTP, el KDC utilizará el SPN de HOST para crear los tickets. Dicho SPN siempre existe puesto que se crea cuando se agrega la máquina al dominio.
Por lo tanto, y con esto enlazo con el principio del post, un sitio web alojado de IIS 7.0 autenticaría mediante Kerberos por defecto sin necesidad de configurar los SPNs. En este sentido se ha facilitado el despliegue considerablemente, y se espera que reduzcan gran parte de los incidentes de soporte relacionados con Kerberos.
Por compatibilidad hacia atrás, tenemos dos opciones para que Kerberos se comporte de la misma manera en IIS 7.0 que en anteriores versiones:
1) Deshabilitar la autenticación en modo Kernel (no recomendado)
2) Habilitar el atributo useAppPoolCredentials en la configuración de IIS 7.0
Con el atributo useAppPoolCredentials habilitado, la autenticación se realiza en modo Kernel pero se utiliza la clave de la cuenta de servicio para descifrar el ticket de Kerberos. Para habilitar dicho atributo podemos ejecutar el siguiente comando:
C:\Windows\System32\inetsrv>appcmd set config -section:windowsauthentication /useAppPoolCredentials:true
Podemos comprobar la configuración de la autenticación de un sitio web específico ejecutando el siguiente comando:
C:\Windows\System32\inetsrv>appcmd list config "Default Web Site" -section:windowsauthentication
<security>
<authentication>
<windowsAuthentication enabled="true" useAppPoolCredentials="true">
<providers>
<add value="Negotiate" />
<add value="NTLM" />
</providers>
</windowsAuthentication>
</authentication>
</security>
Hasta la próxima,