Operation Poisoned News:
Hong Kong Users Targeted with Mobile
Malware via Local News Links
Technical Brief
By Elliot Cao, Joseph C. Chen, William Gamazo Sanchez, Lilang Wu, and Ecular Xu

Contents
1

2

3

4

5

Attack Chain
1.1 Watering hole attack tactic
1.2 Infection chain
Exploits Analyses
2.1 The JavaScriptCore exploit
2.1.1 Bug triggering
2.1.2 The addrof/fakeobj primitives
2.1.3 Arbitrary address read/write primitive
2.1.4 Shellcode execution
2.2 Kernel exploit
iOS Malware lightSpy
3.1 Startup loader
3.2 Light: The main malicious control agent
3.3 BasicInfo module (Command ID 11000)
3.4 ShellCommandaaa module (Command ID 20000)
3.5 KeyChain module (Command ID 31000)
3.6 Screenaaa module (Command ID 33000)
3.7 SoftInfoaaa module (Command ID 16000)
3.8 FileManage module (Command ID 15000)
3.9 WifiList module (Command ID 17000)
3.10 Browser module (Command ID 14000)
3.11 Locationaaa module (Command ID 13000)
3.12 The iOS WeChat module (Command ID 12000)
3.12.1
The framework for stealing information
3.12.2
WeChat collected Information
3.13 iOS QQ module (Command ID 25000)
3.14 iOS Telegram module (Command ID 26000)
Android Malware dmsSpy
4.1 Distribution
4.2 Behavior Analysis
Appendix

Trend Micro discovered a watering hole attack against iOS users in Hong Kong that first became active inJanuary 2020. The campaign designed several webpages disguised as local news pages then injected
them with an iframe that loads an iOS exploit. The iOS exploit flow was designed to exploit vulnerable
iOS versions 12.1 and 12.2 on several models ranging from the iPhone 6S to the iPhone X.
Users with unpatched iPhones that access the concerned links will be infected with an iOS malware thatcan spy on and take full control of the devices. We found that the campaign tricked users into clicking on
the malicious news links by posting them on popular forums in Hong Kong.
The iOS malware, which we named "lightSpy" (detected by Trend Micro as IOS_LightSpy.A), is a modular
backdoor that allowed the attacker to remotely execute a shell command and manipulate files on theinfected device. It is also implemented with several functionalities through different modules for exfiltrating
data from the infected device including:
•
•
•
•
•
•
•
•

Hardware information
Contacts
Keychain
SMS messages
Phone call history
GPS location
Connected Wi-Fi history
Browser history of Safari and Chrome

The malware also reports the surrounding environment of the device by:••

Scanning local network IP address
Scanning available Wi-Fi network

The campaign also employs modules specifically designed to exfiltrate data from popular messenger
applications such as QQ, WeChat, and Telegram.
Our research revealed the campaign also targeted Android devices in 2019. We found URL links of amalicious APK file posted on public Hong Kong-based Telegram channels. The message that the threat
actors sent was disguised as a promotion of a seemingly legitimate application luring Android users to
install it on their devices. The malware can also exfiltrate device information, contacts, and SMS
messages. We named the Android malware "dmsSpy" (detected as AndroidOS_dmsSpy.A).
The design and functionality of the operation suggest that it is not a targeted attack but one that aims tocompromise mobile devices as many as possible for backdoor and surveillance. We dubbed thecampaign "Operation Poisoned News."

1 Attack Chain
1.1 Watering hole attack tactic
On February 19, we started noticing a watering hole attack targeting iOS users. The malicious webpage
crafted by the attacker contained three iframe links to three different sites, with only one that was visibleon the browser. The visible link connected to a page from a legitimate news website to make users
believe they are looking at the original news website. One invisible iframe connected back to thewebserver for the visitor statistic. Another invisible iframe connected to another server, which hosted themain script of the iOS exploit.

Figure 1. HTML code of the malicious website with three iframes

The threat actors further tricked users on the source of these malicious news webpages by posting themon four different forums of Hong Kong-based users. All of these four forums are popular and provide theirown mobile applications for their users. Operation Poisoned News usually posted the topic on the general
discussion section of the forums.
The forum post includes the title of the news, the pictures from the news, and the malicious link the threat
actors prepared. The forum accounts we found were registered right before the malicious link was posted.
We believe it was directly posted by the campaign, and not a case where people reshared the news links
from another source.
The news topics selected as lure were mostly related to sexually implied headlines or those related to the
COVID-19 disease. We believe these topics weren’t used to target specific users.

Figure 2. List of news topics posted by the campaign

Figure 3. Forum post with the link to malicious site

We also found a second type of watering hole website that did not use an iframe to load news websites.
The page directly copied the original news page and injected the iframe linked to the campaign's exploit
server. Our telemetry data shows this type of watering hole was distributed in Hong Kong starting January
2. However, we were not able to identify where the malicious link was distributed at that time.

Figure 4. Copied news page with an iframe that loads the remote exploit

On March 20, the watering hole attack from Operation Poisoned News continued, as the campaign
posted on a forum regarding a supposed schedule for protests in Hong Kong. The link leads to the same
infection chain as in the earlier cases.

Figure 5. Link to malicious site claiming to be a protest schedule

1.2 Infection chain
The attack takes advantage of iOS versions 12.1 and iOS 12.2, which targets iPhone models from the 6S
up to the iPhone X. The following figure shows how the exploit checks for different supported iOS anddevice versions.

Figure 6. Code checking for target iOS devices

The full exploit chain involves exploiting a silently patched Safari bug on multiple recent iOS versions anda customized kernel exploit. Once the Safari browser renders the exploit, a silently patched bug is taken
advantage of, which leads to the exploitation of a known kernel vulnerability to gain root privileges. The
exploited kernel bug has been assigned with the CVE ID CVE-2019-8605.
However, the silently patched bug exploited on Safari does not have an assigned CVE ID; someresearchers also noted an associated history of failed patches.
After compromising the devices, the attacker installs undocumented and sophisticated spyware formaintaining control over devices and exfiltrating information. The spyware has a modular design withmultiple capabilities, such as:•••

Modules update
Remote command dispatch per module
Complete shell command module

Many of the modules were designed for data exfiltration; for example, there are modules for stealing
information from WeChat and Telegram. The following image shows the full attack chain and names themodules initially downloaded and configured.

Figure 7. lightSpy infection chain

Because the malware was previously undocumented, we named it "lightSpy." Light is the module
manager of this iOS spyware architecture. While analyzing the payload.dylib payload, we noticed that the
decoded configuration file used by launchctl shows a URL that points to /androidmm/light, which hints that
there is probably also an Android version of lightSpy.

Figure 8. Config file hints at Android counterpart

The payload, payload.dylib, is signed using the Apple developer certificate chain, probably to evadedetection. The campaign is relatively new, based on the signature date (Nov. 29, 2019).

Figure 9. Signed time indicates late November 2019

The next sections describe each stage of the full attack chain for iOS, including an analysis of thelightSpy malware. The final section covers the Android APK and how it is related to the Operation
Poisoned News campaign.

2 Exploits Analyses
Even when the exploited bug and code execution techniques used in the captured exploit are known in
the research community, this section will cover the exploit stages, providing some details focusing on
what is unique to the analyzed samples.

2.1 The JavaScriptCore exploit
To briefly describe the exploit used to deploy lightSpy, the following sections will be covered:

1. Bug triggering: The use of the “silently patched” vulnerability
2. The addrof/fakeobj primitives: The use of generic exploit primitives to build anarbitrary R/W primitive from faked objects.
3. Arbitrary address read/write primitive: Take advantage of the final WebAssembly
arbitrary R/W primitives to overwrite the WebAssembly object
4. Shellcode execution: The exploit shellcode execution that precedes the kernel exploit to
get root privileges on the devices

2.1.1 Bug triggering
This bug was accidentally found by @qwertyoruiop in hxxp://rce[.]party/wtf.js. It has since been fixed anddoes not have a CVE number assigned. It is a JIT (just-in-time)-type confusion bug in Safari’s JavaScript
engine JavaScriptCore.

Figure 10. Key parts of the PoC

1. The for loop triggers the JIT bug on the function victim()
2. In the function victim(), the expression “let r = 5 in oj;” triggers the function has() callback
3. Because the flag “hack” has been set to 1 after the loop calling function victim() being JITed,the “if” branch is executed and confuse[1] is set to an object. So the array “confuse” isconverted from “ArrayWithDouble” to “ArrayWithContigous” by this callback
The problem is JIT does not know there could be a side effect in this callback and the second element of“confuse” is a pointer, which was a number, and still treats the array “confuse” as “ArrayWithDouble”,
causing the type confusion.

2.1.2 The addrof/fakeobj primitives
From a Phrack article, Saelo has introduced the addrof and fakeobj primitives. The addrof() function isused to leak the memory address of the given JavaScript object, and the fakeobj() function is used toaccept some given address and return a faked JavaScript object at that location.
Because of the JIT-type confusion bug, the primitives addrof and fakeobj can easily be implemented by
confusing a double and a pointer in the array:Figure 11. The addrof and fakeobj primitives

2.1.3 Arbitrary address read/write primitive
After getting addrof/fakeobj, it sprays 0x5000 Float64Array and a few WebAssembly objects. It is easy tobuild a faked and effective Structure ID of 0x5000, which matches the real Structure ID of the sprayed
Float64Array. Next, it uses the Structure ID and fakeobj to get a faked object, and adds the Structure ID
to get a faked WebAssembly.Memory object. It then creates a faked wasmInternalMemory, which has alarge size, and sets it as the faked WebAssembly.Memory object’s memory property.

Figure 12. Faked Structure ID, WebAssembly.Memory, and wasmInternalMemory (top),and Faked objects (bottom)

Finally, it gets a stable memory read/write primitive by this faked WebAssembly.Memory object:

Figure 13. Memory read/write primitives

2.1.4 Shellcode execution
After getting the arbitrary address read/write primitive, the exploit achieves the shellcode execution instage two.
It creates a JITed function and gets the function address by the exported symbol“startOfFixedExecutableMemoryPool”. After that, it builds a return-oriented programming (ROP) chain towrite the shellcode to the JIT page and creates a temporary stack to execute the ROP chain.

Figure 14. Temp stack for executing the ROP chainSince the payload contains the jailbreak code after the successful execution of the payload, it will get root
privilege.
The next section describes how the payload gets root privilege.

2.2 Kernel exploit
In this section, we mainly introduce the local privilege escalation exploit chain used in this attack. All the
exploit codes can be found in the payload.dylib payload.
In the jailbreak rootkit published on GitHub by @pwn20wnd & @sbingner, it integrates the following public
exploits:
Indicator

Attribution

Description

empty_list

CVE-2018-4243

iOS 11.0 - 11.3.1

multi_path exploit

CVE-2018-4241

iOS 11.2 - 11.3.1

async_wakeCVE-2017-13861

iOS 11.1.2

Voucher_swap

CVE-2019-6225

iOS 11.2 - iOS 12.1.2

mach_swap

CVE-2019-6225

iOS 11 - 12.1.2 (<=A9 devices
only)mach_swap2

CVE-2019-6225

iOS 11 - 12.1.2 (on A7 - A11
devices)

Table 1. Public exploits used by an iOS jailbreak rootkit

To support the iOS 12.2.* versions, this attack campaign used another vulnerability (CVE-2019-8605),
which was found by Google Project Zero member Ned Willamson. There are also different exploit
versions published on GitHub. In our findings, the campaign used the exploit host in sock_port, which
supports iOS 10.0-12.2 and extends the jailbreak ability.

Figure 15. Where the privilege escalation attack starts

Not only did the sock_port project use CVE-2019-8605 to get the receive rights of the kernel task port in
the get_tfp0() function, it also nearly supports most devices with system versions between 10.0 and 12.2.
Therefore, in the exploit chain of this campaign, it simply integrates these codes to help to achieve thetfp0, as shown in the following figure.

Figure 16. The get_tfp0() function

Figure 17. The get_tfp0 function in payload.dylib, which is the same as the sock_port project

Figure 18. After getting the tfp0, it initializes the patch handler, which can help find the address of necessary function
symbols

Figure 19. Combining the kernel slides, it resets the real address for those symbols

Figure 20. The kernel task’s cred value is then stolen for the current process so that it becomes root

After that, it first gets the address of the IOSurfaceRootUserClient port then uses it to get the address of
the actual client and vtable. It then creates a fake client with a fake vtable and overwrites the existingclient with the fake one. Lastly, the IOUserClient::getExternalTrapForIndex function in vtable gets
replaced with the ROP gadget (add x0, x0, #0x40; ret;) so it can use IOConnectTrap6 to call any functionin the kernel as the kernel itself.

Figure 21. Code overwriting with the fake client and fake vtable

Figure 22. Code showing the completed jailbreak operation

3 The iOS Malware lightSpy
After gaining full kernel privilege, it downloads many malicious libraries to target applications.

Figure 23. Downloaded modules

3.1 Startup loader
The tool launchctl loads or unloads daemons or agents. After downloading all the payloads, the exploit
spawns a daemon using launchctl with “ircbin.plist” as the argument.

Figure 24. The launchctl tool is used with ircbin.plist as the argument

This daemon uses irc_loader as an executable. This loader is just a launcher and will be used to start up
the main malicious agent deployed on the target side. It first parses the C&C “IP:PORT” address then thedownload address.

Figure 25. The irc_loader as an executable

The startup parameters are hidden in the irc_loader binary and are encrypted with the AES algorithm.
After decryption, the parameters are shown in the following figure.

Figure 26. The parameters after decryption

After getting these parameters, it will use them to launch another module called “light”.

Figure 27. Loading the "light” module3.2 Light, the main malicious control agent
After “light” starts up, it first initializes a database, which is used to store all the control information.

Figure 28. Database is initialized for control information

The SQL statement includes the following:
CREATE TABLE IF NOT EXISTS t_transport_control (id integer PRIMARY KEY
AUTOINCREMENT, cmd integer, wifi integer, mobile integer
CREATE TABLE IF NOT EXISTS t_command_plan (id integer PRIMARY KEY
AUTOINCREMENT,type integer,start integer,stop integer,interval integer , interval_pos integer,cmd
integer,arg text NOT NULLCREATE TABLE IF NOT EXISTS t_command_record (id integer PRIMARY KEY
AUTOINCREMENT,cmd integer, arg text, status integer,type integer, response text, starttime
integer
CREATE TABLE IF NOT EXISTS t_config (id integer PRIMARY KEY AUTOINCREMENT, key text,
value text
CREATE TABLE IF NOT EXISTS t_dormant_control (id integer PRIMARY KEY
AUTOINCREMENT, key text, value integer
CREATE TABLE IF NOT EXISTS t_plugin (id integer PRIMARY KEY AUTOINCREMENT,nametext NOT NULL,version text,md5 text,url text,path text,classname text,initparam text,isupdate
integer,isdelete integer,downstatus integer

After that, it initializes a thread using the libwebsockets library to implement the messages' receiving
function.

Figure 29. Communication flow

The libwebsockets framework supports registering a callback broker as a protocol when creating the web
socket handler. After this thread starts, the callback broker is responsible for managing the status of thesocket handler.

Figure 30. Callback broker

The broker method (for managing the lifecycle of web socket handler) used an interrupted reason to trap
into a different handler method. Among those reasons, LWS_CALLBACK_CLIENT_RECEIVE reason,
whose value is 8, is responsible for receiving the commands sent from the C&C server in this attack event.

Figure 31. Broker method used for managing the lifecycle of the web socket handler

After getting the message, it will call the DealFrameCommand() function to deal with each kind of
message, such as config, command plan, and command execution messages.

Figure 32. A sample showing how it deals with command plan messages

An init() then thread initializes the plug-in loading. The initialized process is shown below.

Figure 33. Plug-in loading gets initialized

The plug-in loading method is notable: It first gets the plug-in name, path, and classname, then uses thepath to load the plug-in file through the dlopen() function. After that, it uses the objc_getClass() function to
get the exposed class object, with “classname” as the argument. This way, the Light module can get eachplug-in’s main class object and use these class objects to start up their own thread.

Figure 34. The objc_getClass() function with "classname" as argument

Figure 35. With baseinfoaaa.dylib module as an example, it first calls the init() method

Figure 36. It then starts up the run loop

After all the plug-ins load successfully, attackers can send the control commands for this malicious agent.
The agent will dispatch these commands to different modules.

Figure 37. The agent calls the ExeCommand:arg: function, which is in the CommandThread class, to execute thecommands

Figure 38. The ExeCommand:arg: function uses a related plug-in object to call their own StartCommand:Argv:
function for executing corresponding commands

3.3 BasicInfo module (Command ID 11000)
This module is mainly for gathering and uploading information such as iPhone hardware information,
contacts, SMS messages, and phone calls.

Figure 39. The BasicInfo module gathers different iPhone information

Figure 40. Code that gathers targets’ SMS information

3.4 ShellCommandaaa module (Command ID 20000)
This module is mainly used for executing shell commands.

Figure 41. The ShellCommandaaa module for executing shell commands

Figure 42. The popen function is used to fork a child process and execute shell commands

The module will upload the execution result if necessary. Here it uses the dictToJsonData() function toserialize the result and post the data to the hxxp://…/api/shell/result server.

Figure 43. ShellCommandaaa uses the dictToJsonData() function

3.5 KeyChain module (Command ID 31000)
This module is mainly for getting targets’ Keychain information. It uses the SecItemCopyMatching()
function with the following dictionary to copy Keychain items.

Figure 44. The SecItemCopyMatching() function

Figure 45. Each item, including the password, certificate, and key, is parsed and added into the return data object

Figure 46. Sensitive information is uploaded to the hxxp://…/api/keychain/ server3.6 Screenaaa module (Command ID 33000)
This module is mainly for scanning around the target device. The method it uses goes through these four
steps:
1. Determine the target device IP address and the subnet mask.
2. Calculate the range of possible addresses in its subnet. The range is obtained by using logicalAND operator, where operands are binary values of the IP address and subnet mask.

Figure 47. MMLANScanner start function

3. Iterate through the range and ping each IP address.

Figure 48. Ping operation via MMLANScanner

4. Upload the data to the hxxp://…./api/lan_devices/ server using thevoid __cdecl -[LanDevices mainPresenterIPSearchFinished:](LanDevices *self, SEL a2, id a3) function.

Figure 49. Uploading the data to the server

3.7 SoftInfoaaa module (Command ID 16000)
This module has two sub-command IDs: 16001 and 16002. Command 16001 is used to get the software
list, while command 16002 is used to get the process list.
The following figure shows how to get the installed software list (id __cdecl +[AppInfo getAppInfoList](ida1, SEL a2)). It mainly uses an undocumented application programming interface (API) called
installedApplications to achieve that.

Figure 50. Getting the installed software list

The following figure shows how it first calls the “ps -Aef” command to get the process list, then calls the
getRunningProcessesList function to parse for details.

Figure 51. Getting the process list information

Figure 52. Getting the process ID (PID), process path, app, to name a few

Lastly, it uploads the software list or process list information to the corresponding server.

Figure 53. Getting the software and running processes list

3.8 FileManage module (Command ID 15000)
This module is mainly used for file or directory operation, including the following sub-commands: getdirectory and file list, upload file, download file, delete file, create directory, rename file, move file, copy
file, and get the directories of applications.

Figure 54. Various FileManage module commands

3.9 WifiList module (Command ID 17000)
This module is mainly for getting Wi-Fi information, including Wi-FI history, where the command ID is
17001, and the Wi-Fi scan list has a command ID of 17002.

Figure 55. Getting the Wi-Fi history and scan list

Figure 56. Getting the Wi-Fi history by directly reading the data stored in the com.apple.wifi.plist fileFigure 57. Parsing each item to get the basic service set identifier (BSSID), SSID_STR, lastAutoJoined, lastJoined,
and even the password information

To get the Wi-Fi scan list, it loads the private MobileWiFi framework first and imported necessaryfunctions through the dlsym function.

Figure 58. The dlysym function

It also creates a Wi-Fi manager using the WiFiManagerClientCreate() function. It then uses
WiFiManagerClientCopyDevices to copy the devices and set it to UtilNetworksManager object.

Figure 59. The WiFiManagerClientCreate() function as Wi-Fi manager

It then uses the getScanList function to parse the detail properties, including the service set identifier(SSID), MAC, encryption type, and signal strength information.

Figure 60. The getScanList function

Figure 61. Uploading sensitive information to the corresponding server

3.10 Browser module (Command ID 14000)
It is mainly used to get the device’s browser history for Safari and Chrome. For Safari, it first loads thehistory database from the Safari application path.

Figure 62. Getting the Safari browser historyIt uses the following Structured Query Language (SQL) statement to query each browser item, thenparses each detail properties such as URL, title, and visit time information.
“select a.id,url,domain_expansion,title,visit_count,visit_time from history_items as a left join
history_visits as b on a.id=b.history_item where a.id>%d order by a.id asc”

Figure 63. Retrieving properties such as URL, title, and visit timeThe
browser
history
databaseof
Chromeislocatedinthe“/Library/Application
Support/Google/Chrome/Default/History” directory. The rest of the steps are almost similar to the ones
used to get the Safari history.

Figure 64. Getting the Chrome browser history

Figure 65. Uploading the history information to the hxxp://…/api/browser_history/ server

3.11 Locationaaa module (Command ID 13000)
This module is mainly used to get the targets’ iPhone location information. It includes two sub-commands.
When the command is 13002, it sets up the continuous configuration with the attacker’s parameters.

Figure 66. Command 13002

Figure 67. Parameters are primarily the update interval and duration

Figure 68. Command ID 13001, where a task is added to continue updating the location data using the given
configuration

Figure 69. Uploading the location details with the device info to the hxxp://…/api/location/ server

3.12 The iOS WeChat module (Command ID 12000)
This module is mainly used to collect the targets’ WeChat associated information, such as accountinformation, contacts, groups, messages, and files.

Figure 70. The gathered WeChat information

3.12.1

The framework for stealing information

The steps used to steal the information:
1. Get the users' WeChat accounts
To get the WeChat accounts' information, it first locates WeChat’s Documents directory and parses the
LoginInfo2.dat file. This file stores many of the accounts' information using a special format that includes
id_persion, phone, and name.

Figure 71. Retrieving LoginInfo2.dat, which contains account information

It then uses the id_persion value to compute an MD5 hash. Id_persion is a value, like “wxid_xxxx.”
WeChat supports multiple users, so it uses this hash to create each account‘s directory for storing
information such as account ID and usage.

Figure 72. Getting the id_persion value

After finding each account directory, all the properties, including id_persion, directory, phone, andnickname info for each account, will be collected.

Figure 73. Using the id_persion value to calculate a hash and using it to find each account directory

2. Use the collected accounts to get the corresponding information that command ID refers to
The following figure shows that attackers will repeatedly go through all accounts and execute the upload
function.

Figure 74. Attackers will repeatedly go through all accounts and execute the upload function

Figure 75. In the upload function, it uses the related handler execute getData() function to get the detailed content,
which it sends to the related server.

3.12.2

WeChat collected Information

WeChatAccountFigure 76. Collecting the head icons for each account

WeChatGroup

Figure 77. Gathering data in the WCDB_Contact.sqlite database

It queries this database using the “select dbContactChatRoom,dbContactRemark,userName,ROWID fromfriend where ROWID>%d” SQL statement. After that, it parses each item that contains the “chatroom”
string.

Figure 78. Parsing for the "chatroom" string

WeChatMessage
This part is mainly used to collect targets’ WeChat message information. To collect the messages, it firstly
collects all the friends from the WCDB_Contract.sqlite database and filters out unwanted ones like“newapp,” then saves the information into a global dictionary variable named “accountMD5” using the<UserName_MD5Hash, UserName> pattern.

Figure 79. Retrieving the WeChat friends list information and saving it to accountMD5

Figure 80. Opening a handler to the MM.sqlite database, which is used to save all the messaging information

In this database, all the messages sent to certain friends are saved in the Chat_UserNameHash table, so
it can iteratively go through all the tables and then save the messages with UserName_Hash for all
friends.

Figure 81. Sending saved messages to Chat_UserNameHash

It first used the “SELECT CreateTime,Des,MesLocalID,Message,type FROM %@ where MesLocalID>%d”
SQL statement to get all the message items. Among these columns, the MesLocalID is the name used tosave a message file. Type indicates the message type, including simple message, image, audio, video,
and open data, which can get the file type from suffix.
To get an audio message, it firstly sets up the message type, and then uses the“/accountHome/Audio/message_id.aud” path to read the content. This way, the attackers collect all themessages.

Figure 82. Getting an audio message

WeChatContacts
The contacts information is saved in the “WCDB_Contact.sqlite” database.

Figure 83. The WCDB_Contact.sqlite database pathIt uses the following SQL statement to get the contacts information:
select dbContactHeadImage,dbContactProfile,dbContactRemark,userName,ROWID from friend
where ROWID>%d order by ROWID

Among these columns, the dbContactHeadImage column is mainly used to store the head image
information; dbContactProfile stores each friend’s profile information, including country, province, and,city; and the dbContactRemark field stores each friend’s remark details, such as name and alias.

Figure 84. Getting contacts’ information

WeChatFile
This module is mainly used to collect all the messages’ file path, which is similar to the WeChatMessage
module.

Figure 85. WeChatFile module

We shared our analysis with Tencent, which responded with the following: “This report by Trend Micro isa great reminder of why it’s important to keep the operating system on computers and mobile devices up
to date. The vulnerabilities documented in the report, which affected the Safari web browser in iOS 12.1
and 12.2, were fixed in subsequent updates to iOS.
A very tiny percentage of our WeChat and QQ users were still running the older versions of iOS that
contained the vulnerability. We have already issued a reminder to these users to update their devices tothe latest version of iOS as soon as possible.
Tencent takes data security extremely seriously and will continue to strive to ensure that our products andservices are built on robust, secure platforms designed to keep user data safe.”

3.13 iOS QQ module (Command ID 25000)
The whole architecture of this module is nearly similar to that of the WeChat module.

Figure 86. The iOS QQ module

The only difference here is the location of the information and its format.

Figure 87. Getting the targets’ QQ information

3.14 iOS Telegram module (Command ID 26000)
The whole architecture of this module is nearly similar to that of the WeChat module as well.

Figure 88. The iOS Telegram module

Like the QQ module, the difference here is the location of the information and its format.
To get the targets’ account info, it first locates the “Documents” directory. It then goes through the“telegram-data” folder, then uses the regular expression “account-\\d+” to get the account list.

Figure 89. Getting the target’s account information

The other submodules are almost similar to the WeChat module.

Apple has been notified of this research through Trend Micro’s Zero Day Initiative (ZDI). We also reached
out to Telegram on our findings and have not received a response at the time of publication.

4 Android Malware dmsSpy
4.1 Distribution
While we were tracking the activity of the Operation Poisoned News campaign, we identified two URLs
linked to Android APK files with the domains they used. Both of the URLs were posted on public
Telegram channels used by users in Hong Kong in 2019. The messages were already deleted when wechecked the Telegram channels. However, we were able to find the text messages from the webpage of
the Telegram channel cached by the Google search engine.
One of the linked APKs was shared as an application for watching paid porn videos for free. The link was
already down when we checked it. For this one, we were not able to find the original APK file downloaded
from the link.

Figure 90. Shared message on Telegram with APK linked to the infrastructure of Operation Poisoned News

Another APK link was disguised as a calendar application for checking the schedule of upcoming politicalevents in Hong Kong. Though the link was also down, we managed to find the original file downloaded
from it.

Figure 91. A message on Telegram shared malicious APK of Operation Poisoned News

Figure 92. Malicious APK disguised as a calendar

4.2 Behavior Analysis
The calendar application shown above requires many sensitive permissions such as READ_CONTACTS,
RECEIVE_SMS,
READ_SMS,
CALL_PHONE,
ACCESS_LOCATION,
and
WRITE/READ
EXTERNAL_STORAGE.
When launched, it first collects device information such as device ID, brand, model, OS version, physicallocation, and SDcard file list. It then sends the collected information back to the C&C server.

Figure 93. Going through all files on SD cardFigure 94. Getting the location information

It also steals contact and SMS information stored in the device. Furthermore, it registers a receiver thatmonitors new incoming SMS messages and syncs messages with the C&C server in real-time.

Figure 95. The SMS receiver

USSD CodeOperator

Description*118*35#

CUniq

Check remaining credit andexpiry date*#130#

CMHK

Check remaining credit andexpiry date

*109#

hkcsl

Check main balance checking##107#

3HK

Check credit balance, mobilenumber and expiry date
*111#

hkcsl

Password inquiry

Table 2. Trying to dial certain USSD codes to query the device’s SIM card information

Figure 96. Dialing USSD code

The app can perform an update by querying the C&C server to fetch the URL of the latest APK file, thendownload and install it.

Figure 97. Getting the latest APK file URL

Figure 98. Installing the APK file

While checking the communication between the C&C server and the APK malware, we noticed that theserver did not disable the debug mode of the web framework, which allowed us to see the list of APIs
used for C&C communication. Some of the APIs have been used in the malicious calendar application.
We suspect that the attacker is still improving the payload to improve its capabilities.

One of the APIs, called “screen_shot,” implies that it may be able to get the screenshot of the device.
Another API of install_apk hints that the attackers would also have the capability to install the additional
APK file to infected devices.

Figure 99. The debug message leaked the APIs of the C&C server

Not only is the malicious APK downloaded from a server hosted with the domain used by Operation
Poisoned News, but the C&C domain also overlaps with the domain they used to host the malicious news
page for the watering hole attack. For that reason, we believe that the APK malware is operated by thesame campaign.

5 Appendix
MITRE ATT&CK Matrix™
iOS

Android

Indicators of Compromise (IoCs)
Indicator
d5239210a9bc0383f569e9ca095fe8
bdfb9a482bc0c77c8658fcecb23b8a2
6bc
4887389ffaf4257b37408eac9f1740e
abe805f830009cf58185757372f9036
673163c8b8deb3cdda9636c87379b1c
384dec207ce9f15f503ffb4b1ef8cfab
945
f3f14cdada70d49c3e381cc1b05860
18e6b983af8799d3e6c4bee3494c40
e1d6
23e8884c69176d5cf4da0260cdbb29
6301c0e0afccd473d57033ac1a06f2
27c3
ce5241de3a378a64266c56fe5094ec
bb8baa7afd677a3112db8074db78a5
5df1
07c30054c7c22b8b53638367c4c3ad
484a1a336b615e1a6944260d5ec79
7a66a
51d7ebd3af38432c68c913aef48fe26
a206fda4b52c9f09728df69cab13a4b3b0dfec52076249d91ec623ea5217735
2fbc8fb258db316eac85462c7b459f1
a2d
3c1bfbdfae91f1f248180c2102ed65fb
dec086a334193894db67b0461a048
5c5
1eec0e1ebeefc6667b6ee08e8dede5
cd36ca10697180f10e2d43a2fdebbe
efcb
650a5958a06b16aa819e4e8685874
6750b8c72a75f31bfdfb6b47fd38d72
b602
641d22e38b4135c56b7fb6037a6d76
098ffae9e84664993a3f4c07859b772
41e
3135efd29cb8b0fab961ddd7ec99e1
48dc4c5cca6c3303d60192dc966484
9545
54c27a8b48b96e63402698d3bba41
480a815d103c92084d467d3c664ee
c0a7f81c0316d0194e8008904679242d592
d1a2aeeb2bacef28c7854e4361692a085e7
6caa6342caefe3fea23353e850cb2c
974e8607c017661b7410de7a10004
b05ec
575890d6f606064a5d31b33743e056

Filename
payload.dylib

Attribution
lightSpy hash

Trend Micro Detection
IOS_LightSpy.A

lightlightSpy hash

IOS_LightSpy.A

ircbin.plist

lightSpy hash

IOS_LightSpy.A

baseinfoaaa.d
ylib

lightSpy hash

IOS_LightSpy.A

browserlightSpy hash

IOS_LightSpy.A

EnviromentalR
ecording

lightSpy hash

IOS_LightSpy.A

FileManage

lightSpy hash

IOS_LightSpy.A

ios_qqlightSpy hash

IOS_LightSpy.A

ios_telegram

lightSpy hash

IOS_LightSpy.A

ios_wechat

lightSpy hash

IOS_LightSpy.A

irc_loader

lightSpy hash

IOS_LightSpy.A

KeyChainlightSpy hash

IOS_LightSpy.A

locationaaa.dy
liblightSpy hash

IOS_LightSpy.A

Screenaaa

lightSpy hash

IOS_LightSpy.A

ShellComman
daaa

lightSpy hash

IOS_LightSpy.A

SoftInfoaaa

lightSpy hash

IOS_LightSpy.A

WifiList

lightSpy hash

IOS_LightSpy.A

HKcalander.admsSpyAndroidOS_dmsSpy.A

54b9ed9200758a9802491286c6a31
3139a45.134.1[.]180
45.83.137[.]83

app[.]poorgoddaay[.]com
movie[.]poorgoddaay[.]com

news[.]poorgoddaay[.]com

appledaily[.]googlephoto[.]vip

www[.]googlephoto[.]vip

app[.]hkrevolution[.]clubnews2[.]hkrevolution[.]clubsvr[.]hkrevolution[.]clubnews[.]hkrevolution[.]club

www[.]facebooktoday[.]cc

news[.]hkrevolt[.]com

www[.]messager[.]cloud

pk

Hahs
lightSpy C&C
IP address
Wateringhole exploit
serverdmsSpy C&C
domaindmsSpydownload
serverdomainWateringhole server
domainWateringhole server
domainWateringhole server
domaindmsSpydownload
serverdomainWateringhole server
domaindmsSpy C&C
domainWateringhole server
domainWateringhole server
domainWateringhole server
domainWateringhole server
domainTREND MICROTM RESEARCH
Trend Micro, a global leader in cybersecurity, helps to make the world safe for exchanging digital information.
Trend Micro Research is powered by experts who are passionate about discovering new threats, sharing key insights, andsupporting efforts to stop cybercriminals. Our global team helps identify millions of threats daily, leads the industry invulnerability disclosures, and publishes innovative research on new threats techniques. We continually work to anticipate new
threats and deliver thought-provoking research.
www.trendmicro.com