कॉन्टेंट रिज़ॉल्वर

OWASP कैटगरी: MASVS-PLATFORM: Platform Interaction

खास जानकारी

दस्तावेज़ के मुताबिक, ContentResolver एक “क्लास है, जो ऐप्लिकेशन को कॉन्टेंट मॉडल का ऐक्सेस देती है”. ContentResolvers, इन सोर्स से मिले कॉन्टेंट के साथ इंटरैक्ट करने, उसे फ़ेच करने या उसमें बदलाव करने के तरीके उपलब्ध कराते हैं:

  • इंस्टॉल किए गए ऐप्लिकेशन (content:// यूआरआई स्कीम)
  • फ़ाइल सिस्टम (file:// यूआरआई स्कीम)
  • Android की ओर से उपलब्ध कराए गए एपीआई (android.resource:// यूआरआई स्कीम) के साथ काम करता है.

संक्षेप में कहें, तो ContentResolver से जुड़ी कमज़ोरियां, कन्फ़्यूज़्ड डेप्युटी क्लास से जुड़ी होती हैं. ऐसा इसलिए, क्योंकि हमलावर, सुरक्षित कॉन्टेंट को ऐक्सेस करने के लिए, कमज़ोर ऐप्लिकेशन के विशेषाधिकारों का इस्तेमाल कर सकता है.

जोखिम: गैर-भरोसेमंद file:// यूआरआई के आधार पर गलत इस्तेमाल

file:// यूआरआई में मौजूद जोखिम की आशंका का फ़ायदा उठाकर, ContentResolver का गलत इस्तेमाल किया जाता है. इससे, यूआरआई में बताए गए फ़ाइल डिस्क्रिप्टर को वापस लाने की ContentResolver की क्षमता का गलत इस्तेमाल होता है. इस जोखिम की वजह से, ContentResolver API के openFile(), openFileDescriptor(), openInputStream(), openOutputStream() या openAssetFileDescriptor() जैसे फ़ंक्शन पर असर पड़ता है. इस जोखिम का गलत इस्तेमाल किया जा सकता है. इसके लिए, हमलावर पूरी तरह या कुछ हद तक file:// यूआरआई को कंट्रोल करता है. इससे ऐप्लिकेशन को उन फ़ाइलों को ऐक्सेस करने के लिए मजबूर किया जा सकता है जिन्हें ऐक्सेस करने की अनुमति नहीं है. जैसे, इंटरनल डेटाबेस या शेयर की गई प्राथमिकताएं.

हमले का एक संभावित तरीका यह हो सकता है कि कोई दुर्भावनापूर्ण गैलरी या फ़ाइल पिकर बनाया जाए. जब इसका इस्तेमाल कोई जोखिम भरा ऐप्लिकेशन करता है, तो यह दुर्भावनापूर्ण यूआरआई दिखाता है.

इस तरह के हमले के कुछ वैरिएंट हैं:

  • हमलावर के कंट्रोल में मौजूद file:// यूआरआई, जो ऐप्लिकेशन की इंटरनल फ़ाइलों की ओर ले जाता है
  • file:// यूआरआई का कुछ हिस्सा हमलावर के कंट्रोल में है. इसलिए, यह पाथ ट्रैवर्सल के लिए संवेदनशील है
  • file:// यूआरआई, हमलावर के कंट्रोल वाले सिंबॉलिक लिंक (सिमलंक) को टारगेट कर रहा है. यह सिंबॉलिक लिंक, ऐप्लिकेशन की इंटरनल फ़ाइलों की ओर ले जाता है
  • यह पिछले वैरिएंट की तरह ही है. हालांकि, इसमें हमलावर बार-बार सिमलंक टारगेट को किसी भरोसेमंद टारगेट से बदलकर, ऐप्लिकेशन की इंटरनल फ़ाइलों पर सेट कर देता है. इसका मकसद, सुरक्षा जांच और फ़ाइल पाथ के इस्तेमाल के बीच रेस कंडीशन का फ़ायदा उठाना है

असर

इस कमज़ोरी का असर इस बात पर निर्भर करता है कि ContentResolver का इस्तेमाल किस काम के लिए किया जा रहा है. ज़्यादातर मामलों में, इससे ऐप्लिकेशन के सुरक्षित डेटा को बाहर निकाला जा सकता है. इसके अलावा, बिना अनुमति के काम करने वाले लोग या कंपनियां, सुरक्षित डेटा में बदलाव कर सकती हैं.

जोखिम कम करने के तरीके

इस जोखिम को कम करने के लिए, फ़ाइल डिस्क्रिप्टर की पुष्टि करने के लिए यहां दिए गए एल्गोरिदम का इस्तेमाल करें. पुष्टि होने के बाद, फ़ाइल डिस्क्रिप्टर का सुरक्षित तरीके से इस्तेमाल किया जा सकता है.

Kotlin

fun isValidFile(ctx: Context, pfd: ParcelFileDescriptor, fileUri: Uri): Boolean {
    // Canonicalize to resolve symlinks and path traversals.
    val fdCanonical = File(fileUri.path!!).canonicalPath

    val pfdStat: StructStat = Os.fstat(pfd.fileDescriptor)

    // Lstat doesn't follow the symlink.
    val canonicalFileStat: StructStat = Os.lstat(fdCanonical)

    // Since we canonicalized (followed the links) the path already,
    // the path shouldn't point to symlink unless it was changed in the
    // meantime.
    if (OsConstants.S_ISLNK(canonicalFileStat.st_mode)) {
        return false
    }

    val sameFile =
        pfdStat.st_dev == canonicalFileStat.st_dev &&
        pfdStat.st_ino == canonicalFileStat.st_ino

    if (!sameFile) {
        return false
    }

    return !isBlockedPath(ctx, fdCanonical)
}

fun isBlockedPath(ctx: Context, fdCanonical: String): Boolean {
    // Paths that should rarely be exposed
    if (fdCanonical.startsWith("/proc/") ||
        fdCanonical.startsWith("/data/misc/")) {
        return true
    }

    // Implement logic to block desired directories. For example, specify
    // the entire app data/ directory to block all access.
}

Java

boolean isValidFile(Context ctx, ParcelFileDescriptor pfd, Uri fileUri) {
    // Canonicalize to resolve symlinks and path traversals
    String fdCanonical = new File(fileUri.getPath()).getCanonicalPath();

    StructStat pfdStat = Os.fstat(pfd.getFileDescriptor());

    // Lstat doesn't follow the symlink. 
    StructStat canonicalFileStat = Os.lstat(fdCanonical);

    // Since we canonicalized (followed the links) the path already, 
    // the path shouldn't point to symlink unless it was changed in the meantime
    if (OsConstants.S_ISLNK(canonicalFileStat.st_mode)) {
        return false;
    }

    boolean sameFile =
        pfdStat.stDev == canonicalFileStat.stDev && pfdStat.stIno == canonicalFileStat.stIno;

    if (!sameFile) {
        return false;
    }

    return !isBlockedPath(ctx, fdCanonical);
} 

boolean isBlockedPath(Context ctx, String fdCanonical) {
        
        // Paths that should rarely be exposed
        if (fdCanonical.startsWith("/proc/") || fdCanonical.startsWith("/data/misc/")) {
            return true;
        }

        // Implement logic to block desired directories. For example, specify
        // the entire app data/ directory to block all access.
}


जोखिम: भरोसेमंद न होने वाले content:// URI के आधार पर गलत इस्तेमाल

content:// यूआरआई की कमज़ोरी का इस्तेमाल करके, ContentResolver का गलत इस्तेमाल तब होता है, जब हमलावर के कंट्रोल वाले पूरे या कुछ यूआरआई को ContentResolver एपीआई को पास किया जाता है. ऐसा उस कॉन्टेंट पर कार्रवाई करने के लिए किया जाता है जिसे ऐक्सेस करने का इरादा नहीं था.

इस तरह के हमले के दो मुख्य उदाहरण हैं:

  • ऐप्लिकेशन, अपने इंटरनल कॉन्टेंट पर काम करता है. उदाहरण के लिए: हमलावर से यूआरआई मिलने के बाद, ईमेल ऐप्लिकेशन बाहरी फ़ोटो के बजाय, अपने इंटरनल कॉन्टेंट देने वाले से डेटा अटैच करता है.
  • यह ऐप्लिकेशन, प्रॉक्सी के तौर पर काम करता है. इसके बाद, हमलावर के लिए किसी दूसरे ऐप्लिकेशन का डेटा ऐक्सेस करता है. उदाहरण के लिए: ईमेल ऐप्लिकेशन, ऐप्लिकेशन X से ऐसा डेटा अटैच करता है जिसे ऐसी अनुमति से सुरक्षित किया गया है जो आम तौर पर हमलावर को उस अटैचमेंट को देखने से रोकती है. यह अटैचमेंट करने वाले ऐप्लिकेशन के लिए उपलब्ध होता है. हालांकि, यह शुरू में उपलब्ध नहीं होता. इसलिए, यह कॉन्टेंट हमलावर को नहीं भेजा जाता.

हमले का एक संभावित तरीका यह है कि नुकसान पहुंचाने वाली गैलरी या फ़ाइल पिकर बनाया जाए. जब कोई कमज़ोर ऐप्लिकेशन इसका इस्तेमाल करेगा, तो यह नुकसान पहुंचाने वाला यूआरआई दिखाएगा.

असर

इस जोखिम का असर, ContentResolver से जुड़े कॉन्टेक्स्ट के हिसाब से अलग-अलग होता है. इससे ऐप्लिकेशन के सुरक्षित डेटा को बाहर निकाला जा सकता है या बिना अनुमति वाले पक्ष, सुरक्षित डेटा में बदलाव कर सकते हैं.

जोखिम कम करने के तरीके

सामान्य

आने वाले यूआरआई की पुष्टि करें. उदाहरण के लिए, अनुमति देने वाली संस्थाओं की सूची का इस्तेमाल करना एक अच्छा तरीका माना जाता है.

यूआरआई, ऐसे कॉन्टेंट देने वाले को टारगेट करता है जिसे एक्सपोर्ट नहीं किया गया है या जिसे अनुमति से सुरक्षित किया गया है. यह कॉन्टेंट देने वाला, जोखिम वाले ऐप्लिकेशन से जुड़ा है

देखें कि यूआरआई आपके ऐप्लिकेशन को टारगेट करता है या नहीं:

Kotlin

fun belongsToCurrentApplication(ctx: Context, uri: Uri): Boolean {
    val authority: String = uri.authority.toString()
    val info: ProviderInfo =
        ctx.packageManager.resolveContentProvider(authority, 0)!!

    return ctx.packageName.equals(info.packageName)
}

Java

boolean belongsToCurrentApplication(Context ctx, Uri uri){
    String authority = uri.getAuthority();
    ProviderInfo info = ctx.getPackageManager().resolveContentProvider(authority, 0);

    return ctx.getPackageName().equals(info.packageName);
}

या अगर टारगेट की गई कंपनी को एक्सपोर्ट किया जाता है, तो:

Kotlin

fun isExported(ctx: Context, uri: Uri): Boolean {
    val authority = uri.authority.toString()
    val info: ProviderInfo =
            ctx.packageManager.resolveContentProvider(authority, 0)!!

    return info.exported
}

Java

boolean isExported(Context ctx, Uri uri){
    String authority = uri.getAuthority();
    ProviderInfo info = ctx.getPackageManager().resolveContentProvider(authority, 0);       

    return info.exported;
}

इसके अलावा, अगर यूआरआई को साफ़ तौर पर अनुमति दी गई है, तो यह जांच इस आधार पर की जाती है कि अगर डेटा को ऐक्सेस करने की अनुमति साफ़ तौर पर दी गई है, तो यूआरआई नुकसान पहुंचाने वाला नहीं है:

Kotlin

// grantFlag is one of: FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
fun wasGrantedPermission(ctx: Context, uri: Uri?, grantFlag: Int): Boolean {
    val pid: Int = Process.myPid()
    val uid: Int = Process.myUid()
    return ctx.checkUriPermission(uri, pid, uid, grantFlag) ==
            PackageManager.PERMISSION_GRANTED
}

Java

// grantFlag is one of: FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
boolean wasGrantedPermission(Context ctx, Uri uri, int grantFlag){
    int pid = Process.myPid();
    int uid = Process.myUid();

    return ctx.checkUriPermission(uri, pid, uid, grantFlag) == PackageManager.PERMISSION_GRANTED;
}

यूआरआई, अनुमति से सुरक्षित ऐसे ContentProvider को टारगेट करता है जो किसी ऐसे ऐप्लिकेशन का है जो कमज़ोर ऐप्लिकेशन पर भरोसा करता है.

यह हमला इन स्थितियों में किया जा सकता है:

  • ऐप्लिकेशन के ऐसे इकोसिस्टम जहां ऐप्लिकेशन, कस्टम अनुमतियां या पुष्टि करने के अन्य तरीकों को तय करते हैं और उनका इस्तेमाल करते हैं.
  • अनुमति प्रॉक्सी के ज़रिए किए जाने वाले हमले. इनमें हमलावर, रनटाइम अनुमति (जैसे कि READ_CONTACTS) रखने वाले किसी ऐसे ऐप्लिकेशन का गलत इस्तेमाल करता है जिसमें सुरक्षा से जुड़ी कमियां होती हैं. ऐसा करके, वह सिस्टम प्रोवाइडर से डेटा हासिल करता है.

जांच करें कि यूआरआई की अनुमति दी गई है या नहीं:

Kotlin

// grantFlag is one of: FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
fun wasGrantedPermission(ctx: Context, uri: Uri?, grantFlag: Int): Boolean {
    val pid: Int = Process.myPid()
    val uid: Int = Process.myUid()
    return ctx.checkUriPermission(uri, pid, uid, grantFlag) ==
            PackageManager.PERMISSION_GRANTED
}

Java

// grantFlag is one of: FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
boolean wasGrantedPermission(Context ctx, Uri uri, int grantFlag){
    int pid = Process.myPid();
    int uid = Process.myUid();

    return ctx.checkUriPermission(uri, pid, uid, grantFlag) == PackageManager.PERMISSION_GRANTED;
}

अगर कॉन्टेंट उपलब्ध कराने वाली अन्य कंपनियों के कॉन्टेंट का इस्तेमाल करने के लिए अनुमति की ज़रूरत नहीं है, तो इन कंपनियों के कॉन्टेंट का इस्तेमाल करने पर साफ़ तौर पर पाबंदी लगाएं. जैसे, जब ऐप्लिकेशन, इकोसिस्टम के सभी ऐप्लिकेशन को पूरा डेटा ऐक्सेस करने की अनुमति देता है.