Analizando viejo stub.dll de troyano frutas RAT versión Piña

Todo empezó una vez de esas que andaba aburrido como siempre, y ejecute un .jar al parecer cualquiera, pero en realidad no, era un server de adwind (un programador que me parecia bastante talentoso), año 2017 más o menos en Noviembre.

Pues como se eso? primeramente intente decompilarlo de otras maneras absurdas ajajaj como por ejemplo, con CFF Explorer, sin resultado alguno, ya que este no contiene runPE, pues lo supe después.

Qué muestra el CFF explorer ?

cffExplorerAdwindStub

El stub.dll en realidad es un .jar (esta vez como no está cifrado nos bastaría con solo renombrarlo a .jar y ya) el código para extraer las clases del el stub.dll es el siguiente, lo que hace es leerlo completamente y guardarlo en un .jar

Leyendo el stub

public class CrearJar implements ShowData {

    (1)
    private static final Path STUB_PATH =  Paths.get("src/main/resources/stub.dll");
    (2)
    private static final Path DESTINO_STUB = Paths.get("src/main/resources/clasesStub.jar");

    public CrearJar() {
        init();
    }

    /**
    * lee el path donde esta el stub.dll y lo volca el contenido en un .jar
     */
    private void init() { (3)

        try(final JarInputStream jarInputStream = new JarInputStream(Files.newInputStream(STUB_PATH ));
        final BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(DESTINO_STUB ));
        final JarOutputStream jarOutputStream = new JarOutputStream(bos, jarInputStream.getManifest())) {

               JarEntry jarEntry;

               while((jarEntry = jarInputStream.getNextJarEntry()) != null) {
                   if(predicate(jarEntry)) {
                       getLogger().info(jarEntry.getName()); (4)
                       jarOutputStream.putNextEntry(jarEntry);
                       jarOutputStream.write(readAllBytes(jarInputStream));
                       jarOutputStream.flush();
                   }
               }
           }catch (IOException ex) {
               getLogger().severe(ex.getMessage(),ex);
           }
        }

    /**
    * Validar el jarEntry
    * @param jarEntry que se le hara el test
    * @return boolean true si son solo clases, y que no sean directorios, ni tengan $
    */
    private boolean predicate(final JarEntry jarEntry) { (5)
        final Predicate<Boolean> predicate = p -> !jarEntry.isDirectory()
                                                      && jarEntry.getName().endsWith(".class")
                                                      && !jarEntry.getName().contains("$"),
                                                      || jarEntry.getName().contains("_");
        return predicate.test(jarEntry);
    }

    /**
    *
    * @return all bytes from stub
    */
    private byte[] readAllBytes(final InputStream input) {
        try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
              final byte[] bytesread = new byte[1024];
              int dataRead;
              while((dataRead = input.read(bytesread)) != -1) {
                  baos.write(bytesread,0,dataRead);
              }
              return baos.toByteArray();
        } catch (IOException ex) {
            getLogger().severe(null,ex);
        }
        return new byte[0];
    }
}
1 Ruta del stub.
2 Ruta para los ficheros finales.
3 Ejecución del método init().
4 Se hace una impresión de todas las clases que están contenidas en dicho .jar .
5 Se permite imprimir solo si son clases, y que no sean directorios, ni tengan $.
19:08:06.783 [main] INFO CrearJar - Desinstala.class
19:08:06.783 [main] INFO CrearJar - Principal.class
19:08:06.783 [main] INFO CrearJar - extra/ClassLoaderMod.class
19:08:06.783 [main] INFO CrearJar - extra/Constante.class
19:08:06.783 [main] INFO CrearJar - extra/Constantes.class
19:08:06.783 [main] INFO CrearJar - extra/RegistryUtils.class
19:08:06.799 [main] INFO CrearJar - opciones/Archivo.class
19:08:06.799 [main] INFO CrearJar - opciones/DesUAC.class
19:08:06.799 [main] INFO CrearJar - opciones/EnviarFile.class
19:08:06.799 [main] INFO CrearJar - opciones/Informacion.class
19:08:06.799 [main] INFO CrearJar - opciones/Instalador.class
19:08:06.799 [main] INFO CrearJar - opciones/Interface_.class
19:08:06.799 [main] INFO CrearJar - opciones/Kille.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion1.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion10.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion12.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion13.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion14.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion2.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion5.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion6.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion7.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion7b.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion8.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion9.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion9b.class
19:08:06.799 [main] INFO CrearJar - opciones/OrdenCaptura.class
19:08:06.799 [main] INFO CrearJar - opciones/PassAll.class
19:08:06.799 [main] INFO CrearJar - opciones/Pina.class
19:08:06.799 [main] INFO CrearJar - opciones/WebBot.class
19:08:06.799 [main] INFO CrearJar - opciones/a.class
19:08:06.799 [main] INFO CrearJar - opciones/interfaceInfo.class
19:08:06.799 [main] INFO CrearJar - opciones/passFilezilla.class
19:08:06.799 [main] INFO CrearJar - opciones/passIDM.class
19:08:06.799 [main] INFO CrearJar - opciones/passNoip.class

Esta clase es la encargada de decifrar los .class con DES

La clase Constante

package extra;
import java.io.ByteArrayOutputStream;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class Constante {
   public Constante() {
   }

    public static byte[] Constantino(String contrasena, byte[] input) {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            SecretKeyFactory skf = SecretKeyFactory.getInstance(new String(new char[]{'D', 'E', 'S'}));
            DESKeySpec kspec = new DESKeySpec(contrasena.getBytes());
            SecretKey ks = skf.generateSecret(kspec);
            Cipher c = Cipher.getInstance(new String(new char[]{'D', 'E', 'S'}));
            c.init(2, ks);
            byte[] tmp = c.update(input, 0, input.length);
            out.write(tmp);
            tmp = c.doFinal();
            out.write(tmp);
            out.close();
            return out.toByteArray();
        } catch (Exception var8) {
            return null;
        }
     }
}

La clase Principal

Aquí esta la main class, el servidor lee el password contenido en un .xml, para descifrar los bytecodes en runtime y cargarlos en memoria por medio del custom Classloader, se ven otras versiones de arabes donde esa contraseña está expuesta por un endpoint aparentemente ofuscado.

adwind classMod

Versiones más nuevas de este troyano (Unrecom, Alien spy, JSocket etc), son anti-virtual machine, anti vmware, y más, aquí muestro algunos .exe que este malware bloquea, que en realidad el código que ejecuta dichas acciones esta cifrado en los .class correspondientes y ofuscados, el mismo paso del Classloader anterior es realizado, parece que el mismo procedimiento se ha heredado a través de las versiones de estos RAT

adwin1

Bloqueo de .exe

La cantidad de .exe que bloquean es algo alta de paso establecen conexión vía SSL/TLS

adwin2