Hello!
Today, I wanted to talk about the Android MMRAT Banking Trojan. This trojan has a ton of features and was covered very well by a recent Trend Micro blog post here:
and for those of you wanting IOCs, they posted those here:
I used this information, a long with some PCAPs I scored to make a few rules in the ETOPEN ruleset:
- 2048084 ET MOBILE_MALWARE Android/MMRAT Data Exfiltration Attempt
- 2048085 ET MOBILE_MALWARE Android/MMRAT CnC Checkin M1
- 2048086 ET MOBILE_MALWARE Android/MMRAT CnC Checkin M2
I want to make sure its known before I dive into the rest of this post, that I’m not necessarily a reverse engineer by trade. I picked up a thing or two over time, and I just happen to notice patterns in the network traffic as I’m analyzing it. If you happen to be a professional reverse engineer and you would like to add your two cents, please feel free to do so, as we can all learn from your experience.
I wanted to talk about the network traffic I observed to create these rules. First, I’m going to talk about rule 2048084, since its a straightforward HTTP protocol rule:
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET MOBILE_MALWARE Android/MMRAT Data Exfiltration Attempt"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/system/apps"; http.header; content:"Authorization|3a 20|Bearer"; http.user_agent; content:"okhttp/"; http.request_body; content:"|7b 22|deviceId|22 3a 22|"; startswith; pcre:"/^[a-f0-9]{16}/R"; content:"|22 2c 22|appInfos|22 3a 5b 7b 22|packageName|22 3a 22|"; fast_pattern; reference:url,www.trendmicro.com/en_us/research/23/h/mmrat-carries-out-bank-fraud-via-fake-app-stores.html; reference:md5,5b90ee49ed678379f1a8be9683b3fc99; classtype:trojan-activity; sid:2048084; rev:1; metadata:affected_product Android, attack_target Client_Endpoint, created_at 2023_09_13, deployment Perimeter, former_category MOBILE_MALWARE, malware_family MMRAT, performance_impact Low, confidence High, signature_severity Major, updated_at 2023_09_13, reviewed_at 2023_09_13; target:src_ip;)
Here is an accompanying screencap of the pcap for reference:
This rule is pretty straightforward as it is a plaintext HTTP POST request to the C2 server to the /systems/apps URI endpoint. We pay attention to the Authorization: Bearer HTTP header, as well as the “okhttp” user-agent. Then, we move the request body, in JSON format. The malware POSTS the Android Device ID, which is a 16 character hex string, followed by a complete list of applications installed on the phone.
All in all, a fairly straightforward HTTP rule, right? Well, let’s take a closer look at the CnC Checkin rules, and their corresponding traffic. Here is an ASCII dump of the stream of traffic:
Now, If you’re paying attention, you might already notice some interesting patterns here, let me further divide this data into the content I used to create the M1 and M2 CNC rules, and share some of my observations.
So, here’s the M1 CnC Checkin rule:
alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET MOBILE_MALWARE Android/MMRAT CnC Checkin M1"; flow:established,to_server; content:"|01 10 03 22 10|"; offset:1; fast_pattern; pcre:"/^[a-f0-9]{16}/R"; content:"|13|20"; byte_jump:1,0, from_beginning; isdataat:!3,relative; reference:url,www.trendmicro.com/en_us/research/23/h/mmrat-carries-out-bank-fraud-via-fake-app-stores.html; reference:md5,5b90ee49ed678379f1a8be9683b3fc99; classtype:trojan-activity; sid:2048085; rev:1; metadata:affected_product Android, attack_target Client_Endpoint, created_at 2023_09_13, deployment Perimeter, former_category MOBILE_MALWARE, malware_family MMRAT, performance_impact Low, confidence High, signature_severity Major, updated_at 2023_09_13, reviewed_at 2023_09_13; target:src_ip;)
Now, let’s compare that to a hexdump of the traffic I used to create this rule:
The first thing I noted in this traffic is that the first byte of data section is the length of the entire C2 packet, minus two bytes (0x90 = 144
). However, the size of this C2 packet is variable, depending on the type of system sending information back to the C2 server, so we can make use of byte_jump:1,0, from_beginning; isdataat:!3,relative;
to confirm the size constraints of the packet. If you want to know more about using byte_jump and isdataat, Brandon Murphy did an excellent write-up on combining the two of these rule options here.
Immediately after that I noticed that the next five bytes of the packet were consistently across at least two different samples (which, isn’t a huge sample size, buuut I worked with what I had): content:"|01 10 03 22 10|" offset:1; fast_pattern
I’m not entirely sure what the hex values of the first four bytes of that content match are supposed to signify, but the final byte, 0x10
is a length field for the data that immediately comes after that content match – a 16 character hexidecimal string (in ascii format). If you take look at the POST image, that I included with data exfiltration rule, you notice that this string of letters and numbers appears to be an Android Device ID, so we can use pcre:"/^[a-f0-9]{16}/R";
to match on this string immediately after that content match.
Now, this malware transmits a ton of other data. I’ve noticed that for all the fields I could identify, the data itself is preceded by a hex value, indicating the number of bytes that particular is, and also has an additional byte appended AFTER that field whose purpose I wasn’t able to identify at this time. Let’s go over the data I was able to identify:
- The system name (QEMU) preceded by the number of bytes (
0x04
) - The system model (StandardPC(i440FX+PIIX,1996)) preceded by the number of bytes (
0x1c = 28 bytes
)
– Note: this indicates that this sample was run on a QEMU VM - The version of Android running on the hardware (8.1.0), in ascii format, preceded by the number of bytes (
0x05
)
– Codename: Oreo - Android SDK/API version (27) in ascii format, preceded by the number of bytes (
0x02
) - Screen Geometry (1024x768) in ascii format, preceded by the number of bytes (
0x08
) - Timezone Designation (EST) in ascii format, preceded by the number of bytes (
0x03
) - System dialect (en_US) in ascii format, preceded by the number of bytes (
0x05
) - Datetime stamp (2023-09-11 20:21:40), preceded by the number of bytes (`0x13 = 19’)
- Version code of the malicious application (varies – I’ve seen ascii 53 (mm.user), and ascii 10 (badoo date) used as version codes), preceded by the number of bytes (
0x02
) - Version name of the malicious application (varies – I’ve seen 1.0.9 (badoo date) and 2.1.3 (mm.user)), preceded by the number of bytes (
0x05
)
In one run, this was all the data transmitted in this C2 check-in, but another version (2.13/mm.user), there are another two fields, a single byte field that reads “0”, and 3-byte field that reads “dev” – perhaps indicating that developer mode is enabled? All I have is speculation here, unfortunately.
Now due to the nature of this traffic being highly variable, the only other static content I could use to create a signature here was content:"|13|20"
– the very beginning of the datetime stamp, plus its size value.
Now, let’s take a look at the M2 rule:
lert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET MOBILE_MALWARE Android/MMRAT CnC Checkin M2"; flow:established,to_server; content:"|10|"; offset:5; pcre:"/^[a-f0-9]{16}/R"; content:"|01 01 34 90 01 01|"; fast_pattern; endswith; byte_jump:1,0, from_beginning; isdataat:!2,relative; threshold:type limit, count 1, seconds 180, track by_src; reference:url,www.trendmicro.com/en_us/research/23/h/mmrat-carries-out-bank-fraud-via-fake-app-stores.html; reference:md5,5b90ee49ed678379f1a8be9683b3fc99; classtype:trojan-activity; sid:2048086; rev:1; metadata:affected_product Android, attack_target Client_Endpoint, created_at 2023_09_13, deployment Perimeter, former_category MALWARE, malware_family MMRAT, performance_impact Low, confidence High, signature_severity Major, updated_at 2023_09_13, reviewed_at 2023_09_13; target:src_ip;)
and the corresponding dump from the packet:
I wasn’t ablte to identify as much with this packet as with the M1 packet. Here are the similarities:
- The very first byte of the payload, like the M1 packet is a size value of the entire payload, minus 1 byte. So, this allows us to use byte_check:1,0,from_beginning; isdataat:!2,relative; to confirm the size of this C2 packet.
- 7 bytes in, there is a size value for the android Device ID field (
0x10
) followed by the same 16 byte hexidecimal (in ascii representation value). This allowed me to use:content:"|10|"; offset:5; pcre:"/^[a-f0-9]{16}/R";
in the rule.
The rest of the fields in this packet are a mystery to me. However, I noticed that the final six bytes of the packet – content:"|01 01 34 90 01 01|"; fast_pattern
were identical in both of the packet captures I had available.
For those who want to look into this themselves, and want to know what samples I used for my analysis here are the links to the malware in virustotal:
As always, I hope this opens up additional insight. Good luck, happy hunting, and if you have corrections or thoughts you would like to add, feel free to do so – constructive criticism is always welcome!
Tony “da_667” Robinson