Easily Extracting (“encrypted”) Messages from Threema, TextSecure, Chadder, WhatsApp, Hangouts and Co.

Eric | May 9, 2014

Max Kolhagen (bachelor student) and Siegfried Rasthofer demonstrate how a malicious application with no permission can be used to read incoming messages from WhatsApps, Hangouts, etc. and even “encrypted” messages sent through Threema, TextSecure or Chadder with ease.

Notifications

Many messaging apps, such as WhatsApp or Hangouts have this nice feature of getting notifications when an SMS or message is received. The notification contains the full message including the name of the sender. Besides these “standard” messaging apps, there are also apps which support an end-to-end encryption for a secure communication between two users. The most common end-to-end encryption apps are: Threema, TextSecure and Cheddar. Also these apps support this nice feature. The image on the right shows an example of an incoming “encrypted” messages from Threema and TextSecure.

But wait a second… Aren’t these message supposed to be encrypted? This was the point where it got interesting to us and we tried to find out whether it is possible and how can we extract a text from the notification bar.

How can one programmatically access the notification bar?

Well, there may be many different possibilities for extracting data from the notification bar. We will introduce two in the following, one method which works only on Android version greater than 4.3 and one which works for 4.2 and below.

Up until Android 4.3 every developer who wanted to get information from the notification bar, needed to use an AccessibilityService. This particular service was originally intended to help developers build services that enable users with limited perception to engage with Android OS.

In order to being able to access notifications you need to tell the service what kind of events you want to subscribe to:

@Override
protected void onServiceConnected() {
  super.onServiceConnected();

  AccessibilityServiceInfo info = new AccessibilityServiceInfo();
  info.flags = AccessibilityServiceInfo.DEFAULT;
  info.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
  info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;

  this.setServiceInfo(info);
}

In our case we are subscribing to notification events only (TYPE_NOTIFICATION_STATE_CHANGED). Now every time a notification is posted, updated or removed the following method is called in which we can extract the desired data:

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
  if (event.getEventType() != AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)
    return;

  Notification notification = (Notification) event.getParcelableData();

  Log.d(TAG, "Incoming notification!");
  Log.d(TAG, "App: " + event.getPackageName());
  Log.d(TAG, "Ticker: " + notification.tickerText);
}

This was always considered a “hacky” solution, so with Android Jelly Bean (4.3), accessing notification became a lot easier. In order to do that, a service called NotificationListenerService was introduced. This service’s only purpose is to provide access to all notifications with a much simpler interface.

@Override
public void onNotificationPosted(StatusBarNotification sbn) {
  Log.d(TAG, "Incoming notification!");
  Log.d(TAG, "App: " + sbn.getPackageName());
  Log.d(TAG, "Ticker: " + sbn.getNotification().tickerText);
}

This example does exactly the same as the AccessibilityService but without the event registration process and the usage of Parcelable objects.

NotiReader: Installation

To sum it up, with either of these services we gain access to all notifications on the device. The alarming part about this is, that we do not need any permission to do so.

As you can see in the image, the installation of an app that implements both of the previously mentioned services does not outline a single permission!

Extracting the notifications’ content.

Up to this point we are able to access the notifications, but how do we access the messages of different messaging apps?

You probably already noticed that one of the log statements included the package name of the app that posted the corresponding notification. We can use that information to differ if a certain notification belongs to a known messaging app or not.

Extracting the actual content then depends on how the messaging app displays their messages in the notification bar. Some, like the Stock Android SMS/MMS app, already display the whole message content inside the ticker text. Therefore, we are able to extract the message without further effort:

int indexDelimiter = ticker.indexOf(':');

if (indexDelimiter == -1)
  return null;

String sender = ticker.substring(0, indexDelimiter);
String message = ticker.substring(indexDelimiter + 2);

For others, though, this is a bit trickier since they only show the message in the real notification itself (see first image).

In order to access their content you have to understand how notifications are displayed on the system level. They are built using a sequence of reflective actions that are performed on a blank notification view. Furtunately we are able to access these actions by also using reflections:

RemoteViews views = notification.contentView;
Class<?> rvClass = views.getClass();

// access private list mActions
Field field = rvClass.getDeclaredField("mActions");
field.setAccessible(true);

Then we can browse that list of actions for the ones that are responsible for posting text. Since we know exactly how each messaging app displays their notifications, we are now able to precisely locate and extract the content that we are interested in.

Cool, so let’s try it on different messaging apps!

For that purpose we developed an app called NotiReader which, as mentioned, does not require any permission. It is able to extract and store incoming messages, displayed in the notification bar.

The following image shows an example of NotiReader:

NotiReader App

The fact that this application does not require any permission causes a serious problem, because an attacker is able to extract sensitive information from incoming SMS messages such as the TAN of a banking transaction without being detected. If one would extend this app with a single permission, the Internet-permission, she would be able actually steal all these sensitive data. Other research has already shown some approaches were data can be sent over the Internet without any permission. This shows, that it is even worse and this application could steal your personal data with zero permissions.

Is it really as bad as it sounds?

Fortunately NO due to two reasons:

1) SMS/MMS (stock app), Hangouts, Facebook Messenger, Threema and TextSecure have the ability to disable information shown in the notification bar. Unfortunately, in all of these apps, these settings are NOT activated by default! A user has to find this setting in the app and then disable it.

Settings: ThreemaSettings: SMS (Stock)

Other apps we examined, like WhatsApp and Cheddar, do currently not support such features. Threema and SMS/MMS furthermore allow only showing a notification that does not reveal anything about the message’s content itself, which is a good trade-off.

2) The extraction of information from the notification bar requires an additional manual activation of either the NotificationListenerService (which can be activated under Settings – Security – Notification access) or the AccessibilityService (Settings – Accessibility). In both cases the user gets a security alert from the Android OS:

Dialog: NotificationListenerServiceDialog: AccessibilityService

These are good news, but one has to think about apps, which have to activate these services for their internal functionality. Can we trust these apps that they do not steal our personal data?

Cross-posted from SEEBlog