XSS por todos lados!
Ufff hace tiempo que no publico news, más que nada porque existen muchos sites de news. Pero esta vez encontré varias noticias juntas relacionadas a un mismo tema y que justamente es uno de mis fuertes en hacking web, es decir, el XSS!
Si bien estas news ya no son tan news (algunas datan de hace un mes), me pareció interesante comentarlas.

Por un lado me encuentro con dos ataques bastante "locos". El otro día leo un artículo donde un usuario utilizaba las imágenes JPEG para realizar XSS! sisisi, no se refrieguen los ojos, leyeron bien, archivos JPEG!!!
Cómo es esto posible? gracias a la magia de la Web (3.0?). En Firefox 3.6 se implementó la File API diseñada por la W3C para permitir a los desarrolladores acceder a los archivos como objetos, seleccionándolos y accediendo a sus datos.
El caso que expone Michael en su blog es un parser Exif que permite acceder a los metadatos de una imagen. Michael presupone (acertadamente) que el programador seguramente lee los metadatos y no los valida, utilizándolos directamente en la página... como siempre recalco en el blog: ERROR!, nunca se debe confiar en los datos ingresados por un usuario!
Michael simplemente agrega un iframe apuntando a otro site en los comentarios de una imagen y luego la carga en la aplicación Web. Cuando la aplicación lee los datos y los muestra: BAM! XSS!

Unos días después de leer este artículo, Emiliano me comenta sobre éste otro artículo, donde muestran justamente qué otras cosas se pueden hacer con meta-información leída y mostrada sin previa validación. El artículo habla sobre un paper donde describen el ataque llamándolo miXSS. Si bien el paper no parece hablar de nada nuevo (ya había leído otro paper que trata este tipo de ataques), resulta interesante citar el ejemplo que expone.
Básicamente cualquier herramienta que utilice el formato Web para mostrar los resultados es susceptible a XSS. El ejemplo del caso viene dado por las herramientas de consulta DNS. Existen varias páginas que permiten a un usuario realizar una consulta a un servidor de DNS. Ahora, qué pasa si un usuario malicioso coloca en su servidor de DNS un registro TXT que contenga un tag del estilo <script>alert('xss');</script>? cuando la herramienta muestre el resultado en su página BAM! XSS!

Luego de esto, hace un par de días me encuentro con una de las tantas contradicciones graciosas de Microsoft. El título de la vulnerabilidad es gracioso en si por la contradicción que supone: "Microsoft Internet Explorer 8 Cross-Site Scripting Filter Cross-Site Scripting Vulnerability". Osea, el filtro XSS diseñado para filtrar XSS tiene una vulnerabilidad de XSS!!! Esto es, una página que tal vez no es vulnerable a XSS, gracias al filtro de IE8, ahora sí lo es! una locura!
Si bien esta no es la primer vulnerabilidad que se presenta en el "filtro", siempre es gracioso (y triste) encontrar una nueva.
No encontré detalles sobre cómo realizar el ataque, pero al parecer en el último Black Hat Europe demostraron cómo hacerlo.

Ya que estoy agrego una referencia a un demo que publicó RSnake en su página hace ya un par de meses. RSnake demostró cómo es posible robar las contraseñas almacenadas en Firefox (utilidad "recordar contraseña") utilizando XSS. Pueden hecharle un vistazo aquí.

Para finalizar, una vez más quiero remarcar el peligro que representa el XSS, porque muchos aún siguen subestimándolo. Si te parece que el XSS no representa un gran peligro, preguntale a la gente de apache.org! Hace unos días la página apache.org fue hackeada (nuevamente), y esta vez utilizando XSS!

También es importante remarcar que nadie está a salvo. Esto lo demostró Nir Goldshlager quien descubrió bugs XSS en Twitter, Google Calendar y más recientemente en PayPal! Imaginense XSS en PayPal, cuánto dinero en riesgo!
Firmando una CA propia
En estos días me di a la tarea de averiguar la posibilidad de firmar nuestra CA (Certificate Authority). Por si no tienen fresco el tema de certificados digitales, pueden releer el artículo Certificados Digitales que publiqué hace casi un año.

Una autoridad certificante, conocida por sus iniciales CA, es una entidad que firma certificados digitales. Recuerden que un certificado no vale de nada si no está firmado por una CA de confianza. Existe una lista de CAs consideradas de confianza e incluidas en la mayoría de los browsers u otro software que trabaje con certificados. Hay CAs comerciales que cobran por firmar certificados y otras CAs que lo hacen de manera gratuita, pero respetando algunas consideraciones.

En una red interna, como la que poseemos en la empresa que trabajo, suele utilizarse una CA propia, no confiable por el resto del mundo. Lo que se hace es montar una CA con algún programa como Microsoft CA u openSSL y firmar certificados que se utilicen internamente. Para que los certificados sean confiables, primero debe agregarse el certificado de la CA interna en los browsers y/o todo programa que necesite certificados. En Becoming a X.509 Certificate Authority y howto create an intermediate Certificate Authority (CA) using openssl pueden encontrar información sobre cómo crear sus propias CAs utilizando openSSL.

Ahora, qué sucede si queremos que los certificados firmados con nuestra CA sean confiables por todos los browsers/aplicaciones? tenemos dos opciones:
- Nos volvemos una CA root, para lo cual deberemos convencer de que somos confiables a todos los programas importantes que utilicen certificados. Esta opción es casi imposible, a menos que realmente obtengamos un muy gran respaldo. Algunas de las CA root son VeriSign, Thawte, y GlobalSign.
- Hacemos que nuestra CA se convierta en una CA intermedia. Esto es, pedimos a una CA root que firme el certificado de nuestra CA, con lo cual, por la cadena de confianza, todo certificado que expida nuestra CA será confiable.

Obviamente en mi búsqueda apunté a la segunda opción, así que comencé a consultar las CAs root más importantes para saber si se puede realizar tal acción. Envié la consulta a VeriSign, Thawte, Entrust y GlobalSign. De estas, en un plazo de dos días, sólo contestaron dos, Thawte y GlobalSign. Por su parte Thawte respondió no proveer tal servicio, mientras que GlobalSign si. Debido a que VeriSign posee representantes en distintos lugares del mundo, contacté a CertiSur, los encargados en Latinoamérica. Por suerte CertiSur contestó bastante rápido y me ofreció su versión Autoridad Certificante Administrada (Managed PKI), pero que no es para firmar CAs externas, sino que expiden certificados a nombre de tu empresa, firmados por VeriSign.

El único que me ofreció el servicio que yo buscaba es GlobalSign. Quedé muy contento con la atención al cliente, respondiendo mis preguntas rápidamente y explicándome cómo funciona el servicio (a pesar de que mi ingles no debe ser el mejor). El servicio de GlobalSign consiste en 3 piezas. Por un lado está el setup inicial donde ellos firman nuestra CA con un costo de u$s12,500. La segunda pieza es el hardware donde se almacenan las claves privadas, que cuesta entre u$s6k y u$s20k. Por último, tenemos el pago por los certificados que vamos a otorgar anualmente. Mientras más certificados firmemos, menor será el costo. Claro está que es mucho más barato pagar estos certificados que los que emite GlobalSign directamente.
Como podrán observar, poner una CA propia no es para nada económico... nosotros desistimos luego de observar estos precios.

Igualmente fue una experiencia muy interesante, contactando empresas grandes en busca de un objetivo bastante especial. Ojalá algún día pueda poseer una CA propia =P
Proyecto de software
Hoy le comentaba al sensei que me encanta trabajar en una empresa grande por lo que me enriquece en experiencia, no solamente concerniente a la seguridad, sino también al manejo de proyectos, trato con proveedores, programadores, con los jefes, otros empleados, etc.

El caso que me lleva a escribir estas líneas es, una vez más, el trato con los programadores/proveedores. Si bien la pelea suele ser porque no desarrollan correctamente la seguridad, hoy fue más bien un problema en el manejo del proyecto. Concretamente, el problema fue falla en el presupuesto, falla en cálculo de tiempos y falla en la comunicación... problemas clásicos.

Si bien existen libros completos sobre cómo manejar un proyecto, me interesa compartir lo que aprendí. Lo que describiré son cosas totalmente lógicas, pero muchas veces uno las termina obviando y ahí es cuando surgen los problemas.

Por un lado tenemos el grave problema de comunicación. La comunicación entre el proveedor y el cliente debe ser lo más fluida posible, a través de los interlocutores correctos, y durante toda la vida del proyecto.
La definición inicial es la parte más importante y el proveedor debe entender lo más cercano posible lo que el cliente desea... lo se, es difícil, pero es preferible invertir un poco más de tiempo modelando o esquematizando para que todos estén seguros que se entienden. Si la definición no está bien, resulta en pérdida de tiempo, usuarios furiosos y lo más importante... pérdida de dinero.
Luego es importante la comunicación durante el desarrollo y testeo. El proveedor debe molestar lo menos posible al cliente... si hay algo para probar, primero debe funcionar! Parece una pavada total lo que escribo, pero pasa, y seguido. El proveedor entrega un programa atado con alambres, y cuando el cliente comienza a probarlo, explota por todos lados, luego se arreglan algunas cosas, se vuelve pedir al cliente que testee, explota mil veces más, así que se arregla uno q otro problema y se vuelve a pedir al usuario que pruebe.... NO! ese no es el camino! El proveedor debe contar con una etapa de testing interna antes de molestar continuamente al usuario. Esto llega a enfurecer tremendamente al usuario, el cual tiene SU trabajo y no puede estar continuamente ayudando a los programadores a hacer algo que deberían hacer bien antes de entregarlo.
Más allá del problema arreglo-prueba-arreglo-prueba-... debe estar bien definido el interlocutor, y cuando se hacen las pruebas, la definición de los problemas encontrados debe estar armada correctamente. El interlocutor debe entender un poco de cada mundo, algo de parte de los programadores y algo de parte del cliente (aka funcionales). En proyectos chicos no suele haber funcionales y la comunicación es un caos. En estos casos, el proveedor debe explicar al cliente cómo debe documentar las pruebas realizadas. Si bien los programadores esperan una descripción correcta de lo que sucedió, los usuarios no suelen tener ni idea, y entregan datos casi inútiles. Por ello, el proveedor debe explicar al cliente que cuando encuentra un problema detalle qué fue lo que probó y cuál fue el resultado obtenido, si se incluye un screenshot, mejor.

Pasemos al tema presupuestario. En este caso la falla estuvo en no prever viajes. El proveedor se encuentra en una ciudad alejada y pensaba que podía realizar todo el trabajo sin hacer viajes... ERROR! Siempre es necesario realizar algún viaje, ya sea para hablar en vivo con el cliente, como para conocer el entorno donde se ejecutará su aplicación. Algo que anda sin problemas en el entorno de desarrollo, puede (por diversos factores) no funcionar en el entorno del cliente. El relevamiento del entorno en este caso conllevó perdida de tiempo y enfurecimiento del pobre administrador de dominio que tuvo que pelear para que las cosas anden.

Muy relacionado con el presupuesto está el tema "tiempos". Algo que se cree poder realizar en 6 meses no cuesta (hablando de dinero/estado mental) lo mismo que algo realizado en 2 años. Los plazos se escapan y no se gana lo que se esperaba. En el cálculo tiempo/precio se debe tener en cuenta la familiarización con el entorno del cliente, capacitación, testing, y viajes, entre otras cosas. También es necesario planificar la asignación de programadores, los cuales pueden estar abocados a más de un proyecto a la vez. El cliente no debe esperar, si se programa una fecha, se debe cumplir.


Si bien parece que son todas críticas al proveedor, la realidad es que el cliente siempre tiene la razón... sisi ok ok, los clientes tienen graves (por no decir GRAVES) problemas para describir que quieren, así como también para realizar y documentar las pruebas. El cliente también debe cumplir con su parte, en eso estamos de acuerdo.

El mayor problema con los proyectos chicos es que los mismos programadores hacen de diseñadores, funcionales y líderes de proyecto. Son muchos cargos juntos, realizar todos a la vez requiere de mucha experiencia (y desarrollar un estado mental superior...). Un programador que está hablando con el cliente es un programador que no está programando, y programador que está diseñando, no está programando... todo esto es tiempo, es decir, dinero y se debe prever muy bien, algo que es muy difícil.

Como la mayoría de los que leen este blog probablemente sean programadores, seguramente me insultarán con energía, pero mi único objetivo es plantear una experiencia de vida que puede ahorrarles problemas y salvar mucho dinero =)
curiosidades: OpenDNS anti-phishing
Hoy me encontré con una de esas cosas que llaman la atención.
Hace un tiempo que utilizo OpenDNS porque los DNS de speedy no son confiables, más de una vez se cayeron mientras intentaba navegar, además no me gusta que speedy gane plata redirigiendome a sus sites con propaganda cada vez que escribo una dirección que no existe...
Si, OpenDNS también redirige a su site cuando nos encontramos con una dirección que no existe, y también contesta los pings como si dichas direcciones fueran de ellos... todos hacen cosas feas. Pero bueno, entre dos males, me quedo con OpenDNS, speedy ya me roba demasiado por mes =P

Como decía al principio, me topé con una nueva característica interesante de OpenDNS y esta es la capacidad de detectar sites de phishing y devolvernos una página de ellos con el mensaje "Phishing Site Blocked"... pueden ver la imagen a continuación.



El site en cuestión es uno de los clásicos "fijate quién te admite, o quien te bloquea en el MSN" que la gente sigue accediendo. Recibo al menos dos links por mes de este estilo, de amigos o conocidos... muy triste, pero bueno, la gente sigue cayendo. Igual este es otro tema.

Volviendo a OpenDNS, si bien me parece que la iniciativa está buena para advertir a los usuarios sobre este tipo de ataques, me molesta soberanamente que me impongan algo. La gente de OpenDNS ni siquiera da la posibilidad de que accedamos igual al server, no nos devuelve en ninguna opción la IP! La advertencia está bien, pero de ahí a que no te permitan acceder bajo tu propio riesgo no me gusta para nada. Me gusta entrar en este tipo de sites para ver el formato y qué hacen, siempre me intrigan las formas que inventan los atacantes o los métodos que usan.

En fin, otra de las tantas imposiciones que uno suele encontrar. Tendría que probar los DNS de google, pero ya les regalo demasiada info por día como para que también revisen las direcciones que visito...
humor: The Upgrade
Desde que inicié el blog que tengo la intención de generar una sección de humor, pero por una cosa o por otra no lo hice.
Hoy leyendo el blog de F-Secure me encontré con este gracioso chiste sobre cómo sienten los usuarios la actualización XP -> Vista.
Lo sé, no suelo publicar cosas en inglés, pero bueno, está interesante. Espero que les guste!

Inyeccion mortal: SQL Injeciton
Probablemente el ataque más temido por todo dueño de una web sea el que les robe/destruya/modifique información de la misma. SQL Injection es uno de los ataques más graves que puede sufrir un site (o aplicación en general), debido a las implicaciones del mismo.
Un ataque llevado a cabo con paciencia puede permitir al invasor obtener lo que desee de una base de datos. Debido a que la mayoría de los sites actuales son dinámicos o tienen algún sistema de login, el rango de ataques es muy grande.

Si bien es un ataque muy difundido, es increíble la cantidad de sites vulnerables. Realmente se muestra que existe muy poco conocimiento en la comunidad de programadores, porque existen muchas soluciones para este problema.

Un uso que se le está dando últimamente al resultado de inyecciones es en las botnets. Es gracioso (y triste a la vez) como mediante una demostración de SQL Injection en una empresa, el analista descubrió que el site ya había sido atacado y que este formaba parte de una botnet... pueden leer el artículo aquí.

Quizás muchos de los lectores del blog conozcan al menos el concepto más básico de SQL Injection, pero debido a que últimamente me ha tocado tratar con varios programadores que no tenían conocimiento del tema, creo que es un buen momento para hacer una serie de informes sobre este ataque.

El problema con el SQL Injection es que es un ataque bastante elaborado, no es tan simple como realizar un XSS. Si bien el concepto básico se aplica a todas las bases de datos, cada DBMS aporta diferentes herramientas para obtener/manipular los datos. Así que, comencemos por el principio...


Erase una vez SQL Injection

SQL Injection es un ataque donde el perpetrador inyecta sentencias SQL en un formulario para poder acceder/manipular los datos en la base de datos. Dependiendo la gravedad de la vulnerabilidad, el atacante podrá ejecutar diferentes sentencias SQL, incluyendo insert, update, delete, select, etc.

La falla, como de costumbre, es una mala (o inexistente) validación de los datos ingresados por el usuario. Una vez que el usuario ingresa valores, el programa los toma y los envía tal cual los recibe al DBMS, abriendo la posibilidad para que el usuario acceda directamente a la base de datos.

Hay que aclarar que SQL Injection no es sólo un ataque web, también es posible realizarlo en aplicaciones ejecutables. Toda aplicación donde se acceda a una base de datos y no se valide la entrada será vulnerable a este ataque.


' or '1'='1

Para demostrar cómo funciona una inyección, nunca mejor ejemplo que el ultra clásico ' or '1'='1. Casi todos los libros/artículos utilizan este ejemplo para explicar el ataque, y como muestra bien el funcionamiento, haré uso del mismo una vez más.

Supongan que tenemos un sistema de autenticación con usuario y password. Si la autenticación se realiza contra datos almacenados en una base de datos, la consulta puede ser algo así:
$query = "SELECT * FROM users WHERE name='".$_POST['name']"' AND password='".$_POST['password']."'";

$result = consutar_DBMS($query);

if($result)
login();
else
reject();
Por si no conocen PHP, la variable $_POST nos devuelve variables ingresadas por el usuario usando el método POST (algo clásico en formularios web). Si la base de datos nos devuelve una fila, quiere decir que el usuario existe y lo podemos dejar entrar.
Una consulta sin inyección, donde el usuario es demasiadovivo y el password es 123456, podría ser:
SELECT * FROM users WHERE name='demasiadovivo' AND password='123456'
Ahora viene la parte buena. Supongan que en lugar de ingresar como password 123456, ingresamos ' or '1'='1. La cosulta quedaría:
SELECT * FROM users WHERE name='demasiadovivo' AND password='' or '1'='1'
Esta consulta siempre retorna un resultado (or 1=1 siempre es true), sin importar si el usuario existe o no. Como resultado, el usuario logra ingresar al site bypasseando el control de login... gracias al SQL Injection.


Ataques?

Como se imaginarán, si tenemos acceso a una variable no validada, podremos ejecutar en la base de datos todo lo que el DBMS nos permita.
Para el ejemplo anterior, podríamos tal vez inyectar cosas como:
- '; drop table users -- borramos la tabla users
- '; insert into users values('hacker', 'mipass'); -- insertamos el usuario hacker con password mipass
- '; insert into contenido values('te hackie la página'); -- insertamos el contenido "te hackie la página" (site defacement)
Si accedemos a una variable utilizada para mostrar contenido, como suele ser el caso de páginas dinámicas, podemos robar información. Por ejemplo, supongamos que tenemos un código como el siguiente:
$query = "SELECT * FROM contenido WHERE id = '".$_GET['id']."'";
$result = consutar_DBMS($query);
print($result)
es decir, utilizamos la variable id, pasada por GET para obtener el contenido (recurso muy utilizado en las páginas). En este caso, podríamos hacer cosas como:
- -1' union select usuario, password from users -- nos robamos la tabla de usuarios
- -1' union select datos from informacion_financiera -- nos robamos la info financiera
solo por citar algunos ejemplos.

El operador UNION nos permite concatenar resultados de varias consultas. Lo que hago en el ejemplo es concatenar el resultado de la consulta original con el resultado de una consulta armada por mi. La vida no es tan fácil, y para poder utilizar UNION debemos saber cuántos campos se están obteniendo en la consulta original. La unión sólo tendrá éxito si la cantidad de campos seleccionados por nuestra consulta coincide con la cantidad de campos seleccionados en la consulta original.

Dependiendo el DBMS, se puede lograr incluso obtener una shell remota en el servidor! Por ejemplo, MS SQL Server provee el store procedure xp_cmdshell, con el cual podemos ejecutar comandos en el sistema operativo:
- '; exec master..xp_cmdshell 'dir' -- nos lista el contenido del directorio


Blind

Existen dos tipos de ataque SQL Injection. En el más simple, el atacante obtiene respuesta del DBMS en caso de error, orientándolo sobre cómo armar una consulta válida, pero en otros casos (cuando el programador se acuerda de capturar las excepciones), el site no nos revela ninguna información sobre lo que sucedió en el DBMS. En el último caso, el atacante trabaja "a ciegas" y al tipo de ataque se lo llama Blind SQL Injection.

Es claro que es mucho más difícil atacar a ciegas porque el atacante debe descubrir cómo se están ejecutando las transacciones sin mucha ayuda. Por ejemplo, no es lo mismo ingresar una comilla en un campo y obtener un error como:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''''' at line 1
que no ver ningún error y que la página retorna como si nada.

Seguramente se preguntarán, si no me entero que sucede detrás, cómo puedo saber si una página es vulnerable a SQL Injection? La técnica utilizada para encontrar la vulnerabilidad en estos casos es observar la respuesta del servidor. En muchos casos el site responderá de forma sutilmente distinta cuando una consulta es inválida. Además el atacante puede hacer pruebas true/false con consultas conocidas por retornar siempre true o siempre false.

Por ejemplo, tomemos el código anterior, donde se obtiene el contenido de la sección usando la variable id. Ahora supongamos que el programador captura las excepciones y no vemos respuesta en caso de consultas inválidas. El atacante puede saber que el site es vulnerable utilizando las consultas:
- 1' and '1'='0
- 1' and '1'='1
asumo en este caso que existe el contenido con id 1 (lo obtenemos de la misma página). Como pueden ver, la primer consulta no retorna contenido, mientras que la segunda si lo hace. Esta diferencia entre respuestas hace que el atacante sepa que el site es vulnerable.

Los ataques blind son muy complejos porque cuesta mucho obtener datos como nombres de tablas, cantidad de columnas, nombre de las columnas, etc, aunque no son imposibles. Un atacante decidido, con el tiempo necesario, los puede realizar.


Continuará...

Este artículo es una breve introducción al SQL Injection y los tipos de inyección, e intenta demostrar lo peligroso que es el ataque. Necesitaba esta introducción para poder explicar ataques grandes y más complejos. Espero dejarlos lo suficientemente interesados para lo que vendrá.

SQL Injection es un ataque con muchas posibilidades. Si bien todo lo que podamos hacer por SQL es estándar para todos los DBMSs, existen ataques dependientes del DBMS subyacente. Obtener nombres de tablas en SQL Server no se realiza da la misma forma que en MySQL, y así para todos los DBMS. El tema da para mucho y espero contar con el tiempo suficiente para contarles todo =)

La idea es hacer con SQL Injection una serie de artículos como el de XSS, contando con un artículo destinado a cómo protegernos (si, recuerden que trabajamos en seguridad, no todo es hacking...).


Referencias

- SQL Injection (wiki)
- SQL Injection (OWASP)
Macros en OOo Calc: ¿Cómo crear tus propias funciones?
Una vez más me encuentro colaborando con este excelente blog de IT. Actualmente estoy capacitando a personal de una importante empresa con casa central en bahía blanca en el uso de OpenOffice. Esta empresa está migrando todos sus sistemas a GNU/Linux y como un aficionado a OOo tuve la oportunidad de dictar seminarios y cursos acerca de esta maravillosa suite de oficina open-source.

Esto también me sirvió para incorporar conocimientos avanzados de estas aplicaciones, principalmente en Calc, por ejemplo en temas como funciones, vincular datos de diferentes libros, piloto de datos (tablas dinámicas de Excel), filtros y áreas de bases de datos, etc. Pero en esta ocasión voy a escribir sobre lo que me resultó más interesante: macros y como crear funciones.

Para comenzar, una macro es una secuencia de comandos guardada para uso posterior. Las macros de OOo se escriben en un lenguaje de programación llamado OpenOffice.org Basic, esto implica que estas macros no funcionan en Excel así como tampoco funcionan las macros de Excel en Calc. Las macros de OOo se organizan en diferentes contenedores de librerías: "Mis macros" contiene macros creadas por el usuario; "Macros de OpenOffice.org" contiene macros incluidas en OOo y no deben modificarse; el resto de los contenedores son los archivos actualmente abiertos. Las macros incluidas en contenedores de documentos abiertos son sólo visibles por los archivos a los que pertenecen, mientras que las macros incluidas en "Mis Macros" y "Macros de OpenOffice.org" son visibles por todos los archivos.

Dentro de cada contenedor, las macros se organizan en librerías de macros. Las librerías incluidas en el contenedor "Macros de OpenOffice.org" y las librerías "Standard" se cargan en memoria automáticamente cuando inicia OOo. El resto de las librerías creadas por el usuario deben cargarse en memoria explícitamente como explicaré más adelante.

La forma más sencilla de crear una macro es utilizando el grabador de macros. Iniciamos el grabador desde "Herramientas > Macros > Grabar macro" el cual abre un cuadro de diálogo para detener el proceso de grabación. Una vez que terminamos de grabar la secuencia de comandos, pulsamos "Finalizar grabación" y se abre el cuadro de diálogo del organizador de macros. Bajo la librería "Standard" en el contenedor "Mis macros" creamos un nuevo módulo llamado "Modulo1" y guardamos la macro con el nombre "miNuevaMacro". Luego podemos ejecutar la macro desde "Herramientas > Macros > Ejecutar macro...".


Este método para crear macros es sencillo, aunque es limitado, ya que por ejemplo las macros grabadas no aceptan parámetros y además el grabador de macros suele tener problemas. Por lo tanto lo mejor es crear y escribir nuevas macros directamente desde el organizador de macros ("Herramientas > Macros > Organizar macros > OpenOffice.org Basic..."). Esto además nos permite escribir nuevas funciones para utilizar luego dentro de las fórmulas.


Manos a la obra...

NOTA: Para los ejemplos se utilizará OpenOffice.org versión 3.0.1.

Primero vamos a crear un nuevo documento llamado "testMacros.ods".

Abrimos el cuadro de diálogo de macros desde "Herramientas > Macros > Organizar macros > OpenOffice.org Basic..." donde se listan los contenedores de librerías y presionamos el botón "Administrar...". En la pestaña "librerías" seleccionamos el documento que creamos como contenedor y presionamos el botón "Nuevo..." para crear una nueva librería llamada "libTestMacros".


A continuación seleccionamos la nueva librería y presionamos "Editar", Calc automáticamente crea un nuevo módulo llamado "Module1" y una macro llamada "Main".


Modificamos el código para incorporar una nueva función:

REM ***** BASIC *****

Sub Main

End Sub

Function porTres(x)
  porTres = x*3
End Function

En el documento recientemente creado, utilizamos la fórmula "=porTres(A1)" para multiplicar por 3 la celda A1. Calc encuentra la macro y ejecuta la función.


Cabe destacar que los nombres de función en Calc no son case sensitive.

Luego de probar la función, guardamos el documento, lo cerramos y lo volvemos a abrir. Si la configuración de seguridad de macros se establece como "Medio" (se cambia desde "Herramientas > Opciones... > OpenOffice.org > Seguridad > Seguridad de macros..."), Calc nos advierte que el documento contiene macros y pueden ser peligrosas, presionamos "Activar Macros" para permitir la ejecución de las macros o "Desactivar Macros" si la macro es un virus.


Cuando el documento carga, Calc no encuentra la función (en la celda muestra "#NAME?"). Esto sucede porque cuando un documento se crea, automáticamente contiene una librería llamada "Standard", ésta librería es cargada en memoria automáticamente cuando se carga el documento, pero el resto no (incluyendo nuestra librería "libTestMacros"). Calc no contiene una función llamada "porTres", por lo tanto busca la función en todas las librerías de macros visibles. Como la librería "testMacros" no está visible (porque aún no ha sido cargada) Calc no encuentra la función.

Desde "Herramientas > Macros > Organizar macros > OpenOffice.org Basic..." expandimos el documento testMacros.ods y observamos que el ícono de la librería "libTestMacros" es diferente (notar grisado), esto significa que no está cargada en memoria. Si presionamos el signo '+' del ícono, vemos que éste cambia, lo que nos indica que se ha cargado en memoria.


Desafortunadamente, la celda que utiliza la función "porTres" sigue mostrando error, esto se debe que Calc no recalcula automáticamente los valores luego de cargar la librería, a menos que se modifique el contenido (podemos probar agregando +0 luego de la llamada a la función). La solución habitual es guardar las funciones en la librería "Standard", aunque si la macro es muy grande podemos crear una función stub con el nombre deseado dentro de la librería "Standard". Esta función stub carga automáticamente la librería deseada (la primera vez que es invocada) y llama a la función original. Para probar esto renombramos nuestra función "porTres" a "porTres_implementacion":

Function porTres_implementacion(x)
  porTres_implementacion = x*3
End Function

Luego creamos la función stub dentro de la librería "Standard" con el siguiente contenido:

Function porTres()
  If NOT BasicLibraries.isLibraryLoaded("libTestMacros") Then
    BasicLibraries.LoadLibrary("libTestMacros")
  End If
  porTres = porTres_implementacion()
End Function

La sentencia condicional verifica que la librería esté cargada, si no es así la carga en memoria y luego llama a la función original de la librería "libTestMacros". Una vez terminado guardamos, cerramos y reabrimos el documento, esta vez la función trabaja correctamente.


Consideraciones adicionales:

La función creada utiliza un parámetro 'x' el cual no es verificado dentro del código, es decir, antes de ser utilizado no se verifica que exista, por lo tanto, si llamamos a la función "porTres" sin parámetros el resultado será un error de ejecución de la macro. Si se desea que un parámetro sea opcional, debe utilizarse el calificador "OPTIONAL". También puede verificarse el parámetro utilizando la función "IsMissing(x)" que retorna verdadero si falta el parámetro. También debe verificarse que el valor sea numérico. El programador de macros (y de cualquier lenguaje) puede ser tan cuidadoso como desee. Cuanto más cuidadoso sea más robusto será el código, aunque tratándose de macros, cuanto mayor sea la cantidad de chequeos más lenta será la ejecución.
Los argumentos pasados a macros son siempre parámetros por valor, si se desea utilizar un parámetro por referencia, debe enviarse la referencia como un string (por ejemplo: "A1:C3") y luego se debe parsear el contenido. Se puede acceder a las celda A1 de la Hoja 1 del documento a través de una llamada:

ThisComponent.getSheets().getByIndex(0).GetCellByPosition(0,0)


Para más información sobre programación de macros de Calc referirse a:

http://www.pitonyak.org/oo.php
Lo más leido en marzo
Y si, se fue otro mes, así que hoy hago el típico repaso con los artículos más leídos.
Marzo fue un mes ocupado, estuve con algunas cosas de red y preparando una charla de seguridad para la universidad, así que no pude dedicar demasiado al blog.
Como se darán cuenta al leer los títulos, en marzo se publicaron casi todos artículos para Windows, haciendo un buen repaso a cómo funciona la autenticación, dónde y cómo se almacenan las credenciales y aún más importante, las debilidades.
Por si no lo notaron, decidí agregar un panel que liste temas en los que estoy trabajando, como para que se den una idea de lo que pueden tratar próximos artículos. La lista no tiene ningún orden especial y puede que publique cosas que no se encuentran ahí, pero voy a tratar de mantenerlo actualizado.
Sin más preámbulos los dejo con el top 5 de lo que ustedes lectores eligieron este mes:

1. Crear máquina virtual en CentOS usando Xen. Un recontra clásico entre los artículos más leídos. En este artículo hago un repaso sobre cómo crear y configurar una máquina virtual usando Xen y CentOS.

2. Rompiendo a lo grande: XSS avanzado. La serie de artículos XSS es la que más me enorgullece, y me alegra mucho que lo encuentren interesante. En este artículo pueden ver lo peligroso que es el XSS y técnicas avanzadas para explotarlo.

3. Cruzando información, Cross-Site Scripting (XSS). Como dije en el punto anterior, esta serie me encanta. Para este artículo diseñé una explicación con ejemplos donde se puede ver lo fácil de explotar, y lo peligroso.

4. Cracking passwords Windows y Active Directory. No esperaba ver tan rápido este artículo en el top 5, pero tampoco es tan sorprendente. Windows es el SO más utilizado y así lo noto al hacer la revisión de artículos, casi siempre están entre los más leídos. Con este artículo explico el almacenamiento de las credenciales en Windows y lo fácil que es obtenerlas/crackearlas gracias a flojas implementaciones de los protocolos.

5. Tunear logs de SQL Server. Otro clásico del top 5. Espero con este artículo mostrar el funcionamiento de los logs de SQL Server, cómo activarlos y configurarlos para obtener lo que necesitamos.