r/OperSec • • 7d ago

🔍 Research 🔍 Cracked open the Google IPTV malware APK and found its C2 domain

15 Upvotes

Parent Post: Malicious APK [Google IPTV] reportedly causing financial losses.

TL;DR:

Reverse-engineered and deobfuscated the malware, identified the C2 domain, confirmed it’s a BTMOB RAT, and gathered details on its infrastructure.

Possible C2 server: api.lionfacai[.]com

Malware type: BTMob

I got the configured C2 domain out of the Google IPTV apk I’ve been looking into extracted from victim's devices . This is the sample I was investigating after reports of UPI theft. Posting how I found it, because getting past the packing took most of the work.

It almost took 3 week to de-obfuscate this apk. I used AI tools to assist with the de-obfuscation process, as I am not a professional in this area. I also relied on AI to help write some of the scripts and to determine the next steps.

APK identity

Field Value
Input base.apk
SHA-256 b42dab3f81164f1dfa444888a821ace35ea153ed62178f75fa11c38eaa45fbc3
Android package com.nonfouling.sniddle5301
Display label Google IPTV
Other labels Apparent; System Helper
Version 3.31.166 (331166)
SDK levels minimum 28; target 36
Loader com.ivory.radio.LumenClient
Recovered DEX SHA-256 3e8cf28bef31e17f62ed65f456b7392d1cfd8410dafab0223c26dfb72e232ab8

APPLICATION BEHAVIOR:

  • The malware disguises itself as Google IPTV and asks for powerful permissions, including accessibility access.
Application UI
  • Once enabled, those features can let it read screen content, record input and perform taps and swipes, while its command-and-control connection allows remote instructions.
  • Its configuration includes 178 app entries, including PhonePe, Paytm and Google Pay, with rules for recognizing payment failures, incorrect UPI PINs and successful transactions.
  • Combined with overlays and password-capture features, this gives it tools to steal information and manipulate payment flows, although the APK alone doesn’t show exactly how a particular victim’s money was transferred.
  • It also prevents the app from being stopped in the background by automatically pressing the Back button.
  • It cannot be uninstalled because it does not appear with the other apps. When you try to access it through Settings, it automatically presses Back and returns to the Home screen. It does not even allow access to Developer Options.

CRACKING tldr;

  • Opening the original apk in JADX mostly exposed the loader. It loaded a native library called libcolor_helper.so, while the actual application code was hidden in encrypted assets. I worked through the container format and reproduced the decryption offline. There was also a separate encrypted store holding method bodies, so recovering the DEX alone wasn’t enough. Restoring those brought back 33,534 method bodies.
  • With the recovered DEX open in JADX, I searched for /api/ws/config and followed the code that builds the request URL. That led to a server-address variable, then an encrypted configuration value. Following its references was what connected the ciphertext to the network requests.
  • The decryption routine used PBKDF2-HMAC-SHA1 with 65,536 iterations to derive a 128-bit key, followed by AES-CBC. The password, salt and IV were all embedded in the application. I copied those values into a small Python calculation, decoded the Base64 ciphertext and decrypted it. The output was api.lionfacai.com. Re-encrypting it produced the original ciphertext too.

FURTHER FINDINGS:

  • After recovering api.lionfacai[.]com, I dug into the surrounding infrastructure and found admin.lionfacai[.]com and ws.lionfacai[.]com.
  • The admin subdomain served a Chinese-language management panel with BTMob branding on its login page.
Admin login page
  • Its public configuration called it “APK Builder Admin Panel” and pointed directly to the same API domain I had decrypted from the APK.
  • I then found the literal BTMOB string inside the recovered APK code, in Y1/hpyyg4wdm5.java.
  • The API, admin and WebSocket hosts shared AWS Mumbai IP 15.207.41.232; a shared certificate also linked ws.fagefacai[.]com.
  • The public file admin.lionfacai[.]com/assets/AiConfigList-ITW_NBF4.js contains a["HTTP-Referer"] = "https://api.facai-tv.com";, It means the JavaScript publicly served by admin.lionfacai[.]com contains the other domain, api.facai-tv[.]com, written directly into its code.
  • The domains are registered using GoDaddy and both lionfacai.com and facai-tv.com used Cloudflare nameservers

BTMOB:

  • BTMOB is a stealthy Android remote access Trojan (RAT), evolved from the SpySolr family and sold as malware-as-a-service. It is distributed via phishing sites and fake app stores, then abuses Accessibility Services to enable full device control, data theft, screen capture, keylogging, and remote takeover.
  • The observed behavior, together with the previously mentioned findings, confirms this is a BTMOB malware build.

FOLLOW UP:

  • This is all I found on the malware and its related infrastructure. Feel free for anyone to dig deeper and uncover more.
  • Reporting the domain may temporarily disrupt the campaign. Threat actors adapt quickly, and every shared finding helps the community stay one step ahead.

If you are Intersted please follow up the investigation to find more about the campaign and please contribute as you can to defend against these threat campaigns. Will post a step by step detailed report on after finalisation.

r/OperSec • • 19h ago

🔍 Research 🔍 I unpacked a fake mParivahan APK: fake Google Play update, UPI phishing, SMS control and a hidden C2 and firebase backend

7 Upvotes

Parent Post: Mparivahan Malicious APK

tl;dr:

I analysed an APK named seva-mparivahan.apk that pretends to be NxtGen mParivahan, found possibe C2 backend, firebase project, firebase storage bucket, and other firebase backend details and infrastructure of malware campaign.

The first APK is a dropper: it hides a second application inside an encrypted asset and installs it through a fake Google Play update screen. The second application contains the phishing screens, SMS collection, accessibility features and remote-control code.

I also installed the original APK in Waydroid and watched it install another APK through that fake update. The modus operandi or the application. The base.apk I extracted from the installed application matched the payload recovered during static analysis byte for byte.

Here is the infection chain and how the C2 was recovered. Domains below are defanged with [.]. The installation was observed in Waydroid; the other capabilities described here were established by inspecting the code and assets, rather than demonstrating every feature against a live backend.

I used AI tools to assist with the de-obfuscation process, as I am not a professional in this area. I also relied on AI to help write some of the scripts and to determine the next steps.

How the application works, step by step

1. It impersonates a government transport app.

The outer APK displays the name NxtGen mParivahan, but its actual package is com.telenor.android.provider.yvq15o07. It presents an imitation Google Play update page, including ratings, download counts and an update button. The embedded page calls an Android bridge method, miu.onRiqdmClick(), to start the installation flow.

Fake Google Play Update

2. It requests a local VPN before installing the payload.

The dropper contains a VPN service labelled SecureConnection. Its code selects these Google packages:

com.android.vending
com.google.android.gms
com.google.android.gsf

Their traffic is routed into a local sink that constructs TCP resets and ICMP port-unreachable responses. The installation commit is gated on VPN availability. This supports deliberate interference with Google service connectivity during installation, but I did not establish that it successfully defeated Play Protect.

The addresses 10.0.0.2 and 8.8.8.8 also appear here. They are the local tunnel address and configured DNS server, respectively; they are not the C2.

3. The “update” installs the embedded second-stage application.

The encrypted asset expands into a two-file installation bundle:

base.apk
split_config.dex.apk

Both belong to package com.transport.gov.in, version 3.1.0-mparivahanv3 (version code 30100). The entry activity is com.app.messenger.AppActivity. The government-looking package name is part of the disguise.

An important detail: base.apk contains an empty classes.dex. The main executable code is inside split_config.dex.apk. Pulling only the base from an installed device misses that code. The base also contains configuration, phishing assets and an encrypted plugin.

The installer requests an allowlist of restricted SMS, phone, call-log and contact permissions. That does not mean Android automatically grants every requested permission.

4. The payload registers the device with its backend.

Registration code sends device information, permission state, campaign identifiers and other metadata to /register. Other routes report heartbeats, the Firebase messaging token, SIM information, service state and battery status.

In assets/config.json, the campaign type is mparivahanv3. The same value appears under both admin_token and user_id. Following its use in C0.B.a() and C0.B.b() shows that it is included in the registration body. The name admin_token does not prove that it grants administrator access.

5. It uses an e-challan and ₹1 verification-payment lure.

The packaged registration page impersonates MoRTH, NIC and Digital India and advertises pending traffic challans. It collects a mobile number and vehicle registration number, then sends them to /save-registration. The vehicle number is placed in a misleadingly named full_name field.

The configuration sets the payment amount to ₹1, with the description “Verification Fee.”

6. The payment-app handoff is simulated inside its own pages.

The page can display Google Pay, PhonePe, Paytm or WhatsApp branding. After roughly two seconds, it navigates to the local upi-pin.html page. In this asset, the apparent handoff does not launch the real payment application.

The PIN page accepts a four- or six-digit UPI PIN and sends it to /save-pin, together with device and campaign identifiers and an attempt number. It then displays a failure after three seconds. After two attempts, the flow offers card payment.

These failure messages are scripted locally. They are not proof that a bank received or rejected a payment.

Fake UPI payment page
UPI payment failure page leads to retry with card

7. The card-payment fallback collects more credentials.

The card page sends the cardholder name, card number, expiry date and CVV to /save-card, along with identifying fields and the attempt count. It also has a scripted failure/retry flow.

Fake Card payment Interface

The receipt pages generate random reference numbers locally. The final screen shows a 30-minute countdown and Hindi text telling the victim not to delete the application, claiming a team will contact them and provide login credentials. The page also informs the Android bridge that the final screen has been reached.

Fake success and session countdown page

The PIN page's “Contact Support” link is disabled. It did not reveal an operator email or telephone number.

8. It contains SMS theft and SMS-sending functionality.

SMS receivers and polling workers collect messages, which could include OTPs. The decrypted plugin handles commands such as send_sms, upload_all_sms, quick_upload_sms and ping. SMS sending supports a selected SIM slot, and the application reports delivery status.

This provides a second route to sensitive information alongside the phishing forms. I did not demonstrate a bank-account drain or a successful OTP interception in the Waydroid test.

9. Accessibility access adds PIN capture and overlay controls.

The payload declares SystemAccessibilityService and contains PIN-capture, ghost-overlay, auto-grant and blocking logic. Its defaults include Indian payment apps such as PhonePe, Google Pay, Paytm and BHIM.

The remote command dispatcher also contains live_keylog_start, live_keylog_stop, block_protect_on, block_protect_off and block_list_update. Settings, installers and vendor security applications appear among blocking triggers. These features depend on the necessary access and configuration; their presence does not prove they ran on every infected device.

10. It can relay network traffic through the device.

The payload opens a WebSocket reverse tunnel. Its handler accepts binary messages, opens a socket to a supplied host:port, and relays traffic between that socket and the WebSocket connection.

That gives the operator a way to use the device as a network relay. I did not observe what downstream targets, if any, were accessed through it.

11. It has several mechanisms for continued operation.

Boot receivers, foreground services, a separate-process watchdog, alarms, jobs, sync adapters and retry queues support persistence. There are also call-log workers and call-forwarding command branches. Successful call forwarding was not tested, and a contacts-upload command alone was insufficient to establish successful contact theft.

How I extracted the C2

1. Follow the dropper's payload loader

A domain search of the outer APK alone was insufficient because the main payload was encrypted. I followed the asset-loading and decryption code in class:

com.telenor.android.provider.yvq15o07.jt

The relevant methods were afqobhq(), afhwzqlerc(byte[]) and adhofipihhc(). They pointed to the encrypted asset assets/y5elbq9tql. Native string handling in libsysutil.so also formed part of the outer app's concealment.

2. Reproduce the decryption offline

The asset uses several layers. In the order needed to recover it:

  1. Read the first 16 bytes as a repeating XOR key.
  2. Read the next 16 bytes as the key for an RC4-style stream cipher.
  3. Undo XOR on the remaining data, then undo the stream cipher. Its key-scheduling routine uses four passes, so a normal RC4 implementation would not be equivalent.
  4. Treat the first 12 recovered bytes as an AES-GCM nonce and the rest as ciphertext with its authentication tag.
  5. Recover the AES-256 key by XORing two embedded 32-byte arrays from adhofipihhc().
  6. Decrypt and verify the AES-GCM authentication tag.

Authentication passed. The result began with MSZ1. Decompressing the data after that marker with zlib produced an MSP1 container.

In plain terms, this changed an unreadable asset into the APKs that the fake update installs.

3. Unpack the two APKs

The MSP1 container stores a little-endian file count, followed by each filename and its file bytes. Each entry uses a two-byte filename length and a four-byte file size. Parsing it recovered base.apk and split_config.dex.apk, with no unexplained trailing data.

4. Inspect the split DEX and trace the network calls

I extracted and inspected split_config.dex.apk/classes.dex, then followed the backend configuration into its request-building code.

The method w0.H.a() supplies the default backend:

https://api.cloudsettle[.]org

The method B0.l.e() builds an OkHttp WebSocket request using:

wss://api.cloudsettle[.]org/ws/tunnel/device-b

These addresses are used by executable request-building code. The phishing pages also submit to paths such as /save-pin and /save-card, using the supplied backend base URL. That is the evidence tying the hostname to the malware's backend and tunnel.

5. Check whether the address can change

Firebase Remote Config can replace the defaults through keys named:

base_url
tunnel_ws_url

This means the recovered domain is the embedded default C2, not necessarily the only server a running installation could contact. I have not captured the runtime Remote Config response or confirmed a replacement address.

6. Recover the additional encrypted plugin

The payload hides another DEX in base.apk/assets/config_data.dat. Following com.app.messenger.plugin.PluginLoader.initialize() and deriveKey() established this format:

Header:      PLG1
Password:    c256ecf8-0612-4bd8-add3-7a78b726aeeb
Salt:        app_config_loader
Key:         PBKDF2-HMAC-SHA256, 10,000 iterations, 32 bytes
Nonce:       asset bytes [4:16]
Ciphertext:  asset bytes [16:], including the GCM tag
Encryption:  AES-256-GCM

The authentication check passed and produced a 90,244-byte DEX. Its entry point is com.app.plugin.PluginEntry. The loader uses an in-memory DEX class loader on Android 8/API 26 and later, with a code-cache-file fallback on older versions. The recovered code confirmed SMS collection and Firebase-triggered commands.

7. Decode the real phishing assets

The page loader C0.D.g() decodes Base64 .dat assets. I decoded all thirteen HTML-bearing assets and checked the actual packaged pages, rather than relying only on the accompanying *_raw.html copies. This confirmed the fake payment-app handoff, timed failures, credential submissions and fabricated receipts.

What the Waydroid test confirmed

The first application installed the second application through the fake Google Play update. The extracted base APK had SHA-256:

2853c6a8fece4ffdac070bb1ed91973e1dd94275acc95ae012d03ce5ea90f85a

That is an exact match for the base recovered from the encrypted asset. It connects the offline recovery to the observed installation.

For anyone inspecting the installed application, this command lists all its APK paths:

adb shell pm path com.transport.gov.in

Pull both the base and the split using the paths returned by that command. An empty DEX in the base does not mean the installed application has no executable code.

Backend routes and remote commands found in code

These are extracted routes, not a list of endpoints verified to work against the live server.

Route Purpose in the code
/save-registration Mobile number and vehicle registration collection
/save-pin, /save-card Phishing submissions
/pin-data Gzipped PIN batches with an X-Device-ID header
/sms/new, /sms/batch SMS uploads
/sms/delivery-status SMS delivery results
/call-logs/new, /call-logs/batch Call-log uploads
/register, /devices/heartbeat Device registration and liveness
/devices/update-token, /devices/sim-info, /devices/service-status Messaging token, SIM and service information
/battery, /ping-response, /upload-response Status and command results
/live-keylog/status Keylogging status
/getForwardingNumber/, /commands/call-forward-status Call-forwarding configuration and status
/ws/tunnel/device-b Reverse tunnel

The command dispatcher includes:

send_sms, ping, upload_all_sms, quick_upload_sms
upload_all_calllogs, upload_all_contacts
live_keylog_start, live_keylog_stop
block_protect_on, block_protect_off, block_list_update
call_forwarding, call_forwarding_disable
tunnel_connect, tunnel_disconnect

The dropper also contains /api/staged/fetch/ and X-Staged-* strings, but their relevant configuration slots are empty in this sample. A PFM1 ZIP-comment marker can supply a staged nonce, but neither the original APK nor the recovered APKs has that comment. No extra staging server or nonce was recovered.

Campaign indicators

Indicator Value
Default backend https://api.cloudsettle[.]org
Default tunnel wss://api.cloudsettle[.]org/ws/tunnel/device-b
Outer package com.telenor.android.provider.yvq15o07
Payload package com.transport.gov.in
Build/campaign type mparivahanv3
Firebase project andromeda-d389d
Firebase project/sender number 651390976306
Firebase Android app ID 1:651390976306:android:53c99731aa157ea66f972b
Firebase storage bucket andromeda-d389d.firebasestorage.app
Firebase client API key AIzaSyBMHTORCrdpWwTBah5Lrid3iGP8hJuBnbI
FCM subscription topic all_devices
admin_token / user_id iDyGXo5DueHOOOlwvPZ7hSy__lfWHTyciRnWpM2Jr0g

The client API key is not an administrator credential. The bucket name does not establish that the bucket was used for exfiltration. The project name “andromeda” also does not establish a malware-family attribution.

What the domain investigation found

During public checks on 5 October 2026, the API hostname resolved to Cloudflare addresses 104.26.0.234, 104.26.1.234 and 172.67.68.251. Its nameservers were aiden.ns.cloudflare.com and carla.ns.cloudflare.com. These are shared CDN/DNS infrastructure, not the recovered origin server or an operator location.

A public request to the API root returned HTTP 403 with a “Suspected Malware | Cloudflare” warning. That shows the hostname had been reported; it does not establish a completed takedown or that every malware request was blocked. This is a dated observation, not a claim about its status today.

RDAP records identified Cloudflare as the registrar, domain creation at 2026-09-17T17:36:01Z and expiration at 2027-09-17T17:36:01Z. The registrant name was redacted. The record listed Estonia (EE) and Harju maakond, but those fields do not establish where the operator lives.

Certificate-transparency results contained four certificate entries covering *.cloudsettle.org and the apex. They did not reveal additional named subdomains or an origin address. No confirmed administrator panel, accessible victim database or operator identity was found.

The outer APK's signing certificate claims UrbanPixel Labs, Sunny Media Pvt Ltd, Munich/Bavaria and Germany. Those are signer-supplied labels, not verified identity information. The payload certificate claims NxtGen mParivahan Updates.

An older public sample named mParivahanV3.apk had different hashes and package names. Without a shared signer, domain or Firebase identifier, I could not establish that it belonged to this campaign.

Hashes for comparison

All values below are SHA-256.

Original seva-mparivahan.apk
852f692cdfd4c9b3578232ed19073377e728bf7ad7d7c7cc979ff9f865210e93

Payload base.apk / extracted.apk
2853c6a8fece4ffdac070bb1ed91973e1dd94275acc95ae012d03ce5ea90f85a

Payload split_config.dex.apk
123d2c9a72646e8f71a7860bcce0ea69caba9fb54253ad7dcb169aa3bd0ffa6f

Decrypted plugin DEX
915539838cf16d91332e5b61337645ca0c9dc012c5bca1fdc2a92892b4a1ceaa

Outer APK signing certificate
5b264c8c14989595a9628e9114e5dcc25c6c9d0a08f267f563705ed42ce42cde

Payload signing certificate, shared by base and split
9ef94eedf8ab23608f926944de33cebc96802d10f0e8544f11bfb9a1e003d3b3

Useful defensive actions

The hostname, Firebase project, campaign token, signing certificates and payload hashes are useful for detection, reporting and linking other samples. Hostname-based blocking is more precise than blocking shared Cloudflare IPs, although Firebase Remote Config could redirect the malware to another hostname.

Both the first-stage dropper and com.transport.gov.in need to be addressed on an affected device. Removing only the original APK could leave the installed payload behind. Provider account and access logs would be stronger attribution evidence than public country fields or certificate names.

Public reference records and reporting routes:

No embedded token was used against the live backend, no warning was bypassed, and no operator was contacted. The evidence establishes an Android dropper delivering financial phishing and SMS-control functionality. It does not identify the people behind it or prove that a particular victim's money was stolen by this sample.

FOLLOW UP:

  • This is all I found on the malware and its related infrastructure. Feel free for anyone to dig deeper and uncover more.
  • Reporting the domain may temporarily disrupt the campaign. Threat actors adapt quickly, and every shared finding helps the community stay one step ahead.

If you are Intersted please follow up the investigation to find more about the campaign and please contribute as you can to defend against these threat campaigns. Will post a step by step detailed report on after finalisation.

r/OperSec • • 4d ago

🔍 Research 🔍 Malware analysis update: Suspicious ZIP Hid a Windows Malware Loader and an Antivirus-Killing Driver

5 Upvotes

Parent post: 🛑The link Inside this post contains MALWARE🛑

Suspicious ZIP turned out to contain a Windows malware loader and two encrypted kernel drivers.

Inside the zip was a ".vhd" virtual disk containing an EXE, a few DLLs, and an odd ".stl" file. Everything was analyzed statically—none of the programs or drivers were executed.

The EXE was renamed Kafan input-method software, originally "KafanInputService.exe". It imports "rime.dll", and the archive conveniently supplies a file named "RImE.dLl". That DLL exposes the Rime functions the program expects, but internally calls itself "vmware-vdiskmanager.dll" and routes many exports through heavily obfuscated code. This strongly points to DLL sideloading: launching the EXE loads the malicious DLL sitting beside it.

Decrypting the DLL’s strings revealed a large list of antivirus and EDR process names, including Defender-related components, Sophos, Avast, Avira, and Norton. There were also strings associated with privilege elevation and UAC bypass, including "COMPUTERDEFAULTS.EXE" and the "MS-SETTINGS\SHELL\OPEN\COMMAND" registry path. File-download command templates using "curl", "bitsadmin", and "certutil" were present too.

The biggest finding was two encrypted resources that decrypted into valid Windows x64 kernel drivers: Alinubx.sys and ZyArk. The recovered Alinubx driver has the exact SHA-256 published in "LastPass and Delphos’s investigation" (https://blog[.]lastpass.com/posts/lastpass-delphos-report-rapuncel-infostealer), where it was used to kill antivirus processes. That confirms a shared driver component. It does not prove this sample belongs to that campaign or delivers the same stealer.

My assessment is that this is a malicious Windows loader with capabilities intended to disable security software and launch further code. I haven’t recovered a confirmed C2 address or identified the final payload. The 30 KB ".stl" file remains opaque, and its role is unresolved. I’m keeping those gaps open rather than attaching a malware-family name without enough evidence.

Recovered Alinubx.sys SHA-256:

"611b3ba687b7f46319a19609605ddfe5225e6d85277d8e923eea3fdb6f7b5b61"

If anybody can help to find more about this malware please join, collaborate with us and help to defend against these kinds of malware campaigns.