Rootkit : Amenaza en la red

Escrito por David García Martín
Seguridad
5

Cada día aparecen nuevas amenazas en la red y ésta es una de las mas modernas y peligrosas.

Se define un rootkit como un programa, generalmente de carácter malicioso, que se esconde a si mismo o a otros camuflando su presencia mediante diversas técnicas; siempre añadiendo código al kernel del sistema; ya sea en forma de drivers o de módulos.

Existe una tercera forma, de la que daremos un ejemplo; que consiste en inyectar código dentro de un archivo JAVA que se instala al descargar y ejecutar una distribución cualquiera.

Lo que se propone aquí es inyectar nuestro código dentro de una de las clases de JAVA para modificar su comportamiento. El ejemplo de este artículo será inocuo; pero no obstante se podría ,incluso, ejecutar una consola remota y mandar comandos de distinta índole, con lo que la máquina afectada se vería secuestrada por el atacante.

Para este artículo se requieren unas nociones mínimas del lenguaje JAVA y un conocimiento de como funciona dicho lenguaje al ejecutar y compilar código. No obstante, si dichos requerimientos no se cumplen, el lector podrá disfrutar de los ejemplos y ver su funcionamiento.

Para empezar, escogeremos una clase que se encuentra en cualquier paquete JAVA de cualquier versión; como por ejemplo la clase Math o la clase PrintStream. La primera se utiliza para realizar operaciones matemáticas y la segunda para imprimir por consola.

– El primer paso sería localizar la clase; que se debería encontrar en los paquetes típicos de JAVA.

– El segundo paso sería desensamblarlo para obtener el bytecode.

– El tercer paso sería modificar dicho bytecode para agregar código y provocar la funcionalidad no deseada por el usuario final (la consola remota, la ejecución de troyanos, etc…).

– El cuarto paso, volver a ensamblarlo.

– Y el quinto y último paso copiarlo a su lugar original dentro su paquete.
Todos estos pasos serán detallados convenientemente e ilustrados con un ejemplo.

Pasos previos:

Es necesario tener instalado el JDK1 .6.0_18 de JAVA.

Realizar una copia de seguridad del paquete rt.jar de JAVA. Dicha copia es necesaria, porque con lo que se realiza en este manual vamos a sobreescribir dicho paquete con una clase con código inyectado.

Herramientas necesarias:

Necesitaremos 3 herramientas:

-Un editor de texto plano (el notepad de Windows sirve, pero desde REDESZone.net recomendamos Notepad++ o Scite

Descarga Notepad++
Descarga Scite

Jasper Dissasemble. Este programa lo utilizaremos para obtener el bytecode del archivo .class (PrintStream.class).

Descarga Jasper

Jasmin assembler. Este otro programa lo utilizaremos para, una vez cambiado el código e inyectado, crear el .class final.

Descargar Jazmin

Primer paso: Localizar la clase.

La clase que en este caso necesitaremos utilizar se encuentra dentro del paquete rt de JAVA y se llama PrintStream. ¿Por qué hemos elegido esta clase?. La respuesta es sencilla: esta clase es ejecutada en un 99% de las aplicaciones JAVA de escritorio y web; si bien en aplicaciones web sólo tiene sentido en depuración; será utilizada igualmente, es una clase muy común. El motivo de que esa tan común es que se utiliza para imprimir por consola.

El paquete rt suele estar dentro de C:Archivos de programaJavajdk1.6.0_18jrelib ( en sistemas windows).

Cogemos el rt.jar y lo copiamos. Una vez copiado, nos vamos sobre dicha copia y lo abrimos con winrar o winzip. Nos debería salir algo como esto:

Java RootKit

Nos vamos a la ruta java/io y ahí dentro encontraremos el archivo .class que estamos buscando (PrintStream.class) y lo extraemos a una carpeta de nuestra conveniencia.

Segundo paso: Obteniendo el bytecode

Para obtener el bytecode del archivo .class, lo que necesitamos es utilizar el programa Jasper. Este programa se utiliza por línea de comandos y el que nos interesa es:

java -jar Jasper.jar nombreClase.class

Sustituyendo nombreClase.class por el nombre de la clase que nos ocupa, PrintStream.class

Este programa creará una estructura de carpetas idéntica a la del paquete de JAVA donde se encuentre la clase en cuestión; es decir, si la clase se encuentra en el paquete myPaquete.directorio.nombreClase.class; entonces el programa creará la carpeta myPaquete, dentro de esa carpeta creará otra llamada directorio y dentro de esa otra carpeta estará un archivo llamado nombreClase con extensión .j

Con esta captura de pantalla se ve mas fácilmente:

Java RootKit

Tercer paso: modificar el bytecode

Este es, quizás, el paso mas complicado de explicar. El bytecode de JAVA es el resultado del funcionamiento de dicho lenguaje: se utiliza este bytecode para ser ejecutado en cualquier máquina virtual de JAVA.

Un bytecode tiene este aspecto:

.method public <init>()V
.limit stack 1
.limit locals 1
.var 0 is this Linit/PepeJframe; from LABEL0x0 to LABEL0x9
.line 12
LABEL0x0:
aload_0
invokespecial java/lang/Object/<init>()V
.line 15
aload_0
invokevirtual init/PepeJframe/println()V
.line 16
return
LABEL0x9:
.end method

Es poco intuitivo y no demasiado fácil de modificar, en principio.

Lo que se recomienda en este manual, aunque no es imprescindible, es crear el código que queramos inyectar con cualquier IDE de JAVA (eclipse es el recomendado por redeszone), tomar el class generado por el compilador y descompilarlo con Jasper. Una vez realizado ese paso, podríamos coger el bytecode que nos interesa e inyectarlo en la clase que queramos modificar.

Nuestra modificación creará una simple ventana cuando ejecutemos el constructor de la clase, que inyectaremos nosotros también.

El bytecode de ese proceso es el expuesto arriba y que volvemos a repetir:

.method public <init>()V
.limit stack 1
.limit locals 1
.var 0 is this Linit/RedesZoneJframe; from LABEL0x0 to LABEL0x9
.line 12
LABEL0x0:
aload_0
invokespecial java/lang/Object/<init>()V
.line 15
aload_0
invokevirtual init/RedesZoneJframe/println()V
.line 16
return
LABEL0x9:
.end method

Este bytecode crea lo siguiente en código JAVA:

public RedesZoneJframe()
{

JFrame pepe=new JFrame(“Esto ha sido una inyección de código.”);
JPanel panel=new JPanel();

JLabel la=new JLabel(“Esta ventana es la prueba de la inyeccion de codigo”);
panel.add(la);
pepe.add(panel);
panel.setSize(100,100);
panel.setVisible(true);
pepe.setVisible(true);
pepe.setSize(400,400);
pepe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

Y esta captura es el resultado de la ejecución de dicho código:

Java RootKit

Como se puede observar, es una simple ventana con un inocente mensaje, pero en este código inyectado podríamos haber programado que se lanzara un socket y se quedara a la escucha para ejecutar comandos; sólo la inventiva del atacante limita las posibilidades.

Cuarto paso: Ensamblando el bytecode para obtener el .class final

En este paso necesitamos utilizar el Jasmin para ensamblar de nuevo. Como el programa Jasper, el programa Jasmin se utliza bajo línea de comandos. El comando que debemos ejecutar es:

java -jar Jasmin.jar nombreClase.j

sustituyendo nombreClase.j por el nombre de nuestra clase, que sería PrintStream.j

El resultado de este programa es la creación de una carpeta con la misma estructura que al de Jasper y el archivo .class, PrintStream.class, que será la clase con el código inyectado.

Una vez realizado esto, sólo hemos de irnos al paquete que cogimos inicialmente, rt.jar, abrirlo con winrar e irnos a la carpeta

java/io/ y arrastrar nuestro PrintStream.class ahí y cerrar el winrar cuando termine. Una vez hayamos realizado esto, vamos a la carpeta

C:Archivos de programaJavajdk1.6.0_18jrelib y lo copiamos.

Java RootKit

A partir de ahora, sólo tendríamos que realizar un programa que ejecutara el constructor de la clase PrintStream, en principio completamente inocua, esperar que una supuesta víctima ejecutara ese programa y ver los resultados.

Se pone un ejemplo de dicha clase aquí:

package init;

import java.io.PrintStream;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class RedesZoneJavaRootkit{

public RedesZoneJavaRootkit()
{
System.out.println(“Una prueba”);
}

public static void main (String [] args)
{
new PrintStream();//aquí se lanzaria nuestro codigo inyectado
new RedesZoneJavaRootkit();//comportamiento real del programa

}

Conclusiones

Como se puede observar, el programa que hemos realizado parece completamente válido y seguro: llama a una clase que es propiedad de Oracle y que no parece contener nada raro (PrintStream) pero sin embargo, gracias a nuestro código inyectado, el comportamiento de la clase cambia; en este caso de modo inocente, pero las posibilidades son infinitas.

Desde RedesZone esperamos que el artículo haya resultado instructivo, esperamos vuestros comentarios.


Noticias relacionadas

Comentarios


5 comentarios
  1. Usuario ADSLZONE 31 Oct, 10 12:52

    Estimados amig@s,

    Como programador que soy, me es muy reconfortante y agradezco mucho el trabajo que alguien ha plasmado en este tutorial, porque si bien nunca me he dedicado a este tipo de «programas», da una idea del peligro real de ciertas aplicaciones en principio inócuas.

    Muchas gracias por vuestro trabajo y os anímo a que sigais por este camino.

    Un saludo desde Vigo. usuario yyeeaahh.

    Gracias.

    Responder
    0
    1. Sergio De Luz 31 Oct, 10 13:04

      Todo el mérito es de Ethiel, es una máquina en Seguridad Informática, seguramente haya más material de este tipo (depende de Ethiel 😀 ).

      Saludos

      Responder
      0
  2. ethiel 31 Oct, 10 15:38

    En esta página, el mérito es de todo el equipo, nada de mío. 😀

    Responder
    0
  3. luicson 01 Nov, 10 20:35

    Hola,

    buen post…sí señor.

    Pero tengo una duda…cuando dices “lanzar un socket” a qué te refieres? Yo entiendo por socket los dos pares direccion/puerto de fuente y destino. No es así?

    Un saludo y de nuevo felicidades por este nuevo site.

    Luicson

    Responder
    0
  4. ethiel 01 Nov, 10 22:05

    Quiero decir que podrías lanzar un socket y dejarlo a la escucha para recibir conexiones entrantes desde cualquier lugar de internet (imaginemos un escenario con IP fija o con ese mismo programa dando la IP a cualquier sitio remoto al que el atacante se conectaría para ver dicha IP y a continuación conectarse al ordenador víctima).

    Para explicarlo mejor:
    1) Maquina infectada: El programa de la máquina infectada se conecta a http://www.todopiratas.org y deja la IP de dicha máquina
    2) Máquina atacante: Se conecta a todopiratas.org, obtiene dicha IP y lanza el socket para conectarse a la máquina anterior.
    3) Lanza comandos y hace lo que quiere con el ordenador.

    Espero que ahora haya quedado mas claro. 😀

    Responder
    0