Skip to content
KitploitKITPLOIT
उपकरणएक्सप्लॉइटब्लॉग
Log in
जमा करें
उपकरणएक्सप्लॉइटब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
ThisSeemsWrong — CVE-2024-49746 के लिए राइटअप और एक्सप्लॉइट: Android का Parcel::continueWrite उन File Descriptors को बंद करता है जो बाद में उपयोग किए जाते हैं | Kitploit
उपकरण/GitHubGitHub/michalbednarski/thisseemswrong
एंड्रॉइड सुरक्षाशोषण फ्रेमवर्कभेद्यता विश्लेषणजानकारी एकत्र करनापेलोड डेवलपमेंटबाइनरी शोषण
GitHubmichalbednarski/thisseemswrong

ThisSeemsWrong

CVE-2024-49746 के लिए राइटअप और एक्सप्लॉइट: Android का Parcel::continueWrite उन File Descriptors को बंद करता है जो बाद में उपयोग किए जाते हैं

रिपॉजिटरी देखें
4715611 महीने पहलेKitploit द्वारा समीक्षित

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

इस समस्या का समाधान CVE-2024-49746 के रूप में सामने आया: बुलेटिन, पैच

"यह गलत लगता है"

उपरोक्त शीर्षक Parcel::continueWrite विधि से एक टिप्पणी है, जो वास्तव में Parcel ऑब्जेक्ट्स का आकार बदलने के लिए जिम्मेदार है, या तो जब उपयोगकर्ता द्वारा स्पष्ट रूप से अनुरोध किया जाता है (उदाहरण के लिए setDataSize() के माध्यम से) या जब वर्तमान डेटा क्षमता बहुत छोटी होने पर किसी write विधि को कॉल किया जाता है।```cpp status_t Parcel::continueWrite(size_t desired) { // SNIP: Validate desired size // SNIP: Assign kernelFields & rpcFields from variant member of this class // SNIP: Count number of objects (Binder handles and File Descriptors) // that will be present after resize and assign to objectsSize

if (mOwner) {
    // If the size is going to zero, just release the owner's data.
    if (desired == 0) {
        freeData();
        return NO_ERROR;
    }

    // If there is a different owner, we need to take
    // posession.
    uint8_t* data = (uint8_t*)malloc(desired);
    // SNIP: Check if malloc succeeded
    binder_size_t* objects = nullptr;

    if (kernelFields && objectsSize) {
        objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t));
        // SNIP: Check if calloc succeeded

        // Little hack to only acquire references on objects
        // we will be keeping.
        size_t oldObjectsSize = kernelFields->mObjectsSize;
        kernelFields->mObjectsSize = objectsSize;
        acquireObjects();
        kernelFields->mObjectsSize = oldObjectsSize;
    }
    // SNIP: rpcFields handling for non-/dev/binder Parcels

    if (mData) {
        memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
    }
    if (objects && kernelFields && kernelFields->mObjects) {
        memcpy(objects, kernelFields->mObjects, objectsSize * sizeof(binder_size_t));
    }
    // ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
    if (kernelFields) {
        // TODO(b/239222407): This seems wrong. We should only free FDs when
        // they are in a truncated section of the parcel.
        closeFileDescriptors();
    }
    mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
           kernelFields ? kernelFields->mObjectsSize : 0);
    mOwner = nullptr;

    // SNIP: Allocation count tracking
    // SNIP: Assign data and objects to this object
} else if (mData) {
    // SNIP: Resize data owned by this instance of Parcel
} else {
    // SNIP: Allocate initial data for currently empty Parcel
}

return NO_ERROR;

}

[जब वह टिप्पणी पेश की गई थी](https://android.googlesource.com/platform/frameworks/native/+/53b6ffe5af3951e8784c451ef8c4ff19f3d6b196%5E!/), `closeFileDescriptors()` कॉल को `IPCThreadState::freeBuffer()` (जो उपरोक्त कोड में `mOwner()` फंक्शन पॉइंटर के माध्यम से कॉल किया जाता है) से `continueWrite()` मेथड में ले जाया गया, हालाँकि तर्क पहले जैसा ही था। आखिरकार, `Parcel` Android IPC का मुख्य भाग है और यदि कोर IPC फ़ाइल डिस्क्रिप्टर बंद कर रहा था तो यह स्पष्ट समस्या होनी चाहिए न कि छिपी हुई

जो हमें महत्वपूर्ण भाग तक लाता है: उपरोक्त कोड का उपयोग कब किया जाता है? इसका उपयोग तब किया जाता है जब Parcel वर्ग Binder ड्राइवर से प्राप्त डेटा का स्वामित्व स्थानांतरित करता है (जो उस समय [`/dev/binder` `mmap`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/native/libs/binder/ProcessState.cpp;l=587-592;drc=187efe18e3de6258af0230198c881915cc695567) में रहता है और इसमें लिखा नहीं जा सकता (उस मेमोरी में लिखने के किसी भी प्रयास से `SIGSEGV` होगा)), अर्थात `Parcel` या तो इनकमिंग ट्रांजेक्शन डेटा होता है (`data` आर्गुमेंट जो [`onTransact()`](https://developer.android.com/reference/android/os/Binder#onTransact(int,%20android.os.Parcel,%20android.os.Parcel,%20int)) को पास किया जाता है) या इनकमिंग रिप्लाई (अर्थात, `Parcel` ऑब्जेक्ट जो [`transact()`](https://developer.android.com/reference/android/os/IBinder#transact(int,%20android.os.Parcel,%20android.os.Parcel,%20int)) कॉल में `reply` आर्गुमेंट के रूप में पास किया गया था, `transact()` उस `Parcel` ऑब्जेक्ट के अंदर रेफरेंस सेट करता है)

व्यवहार में, हम `if (mOwner)` ब्लॉक में केवल तभी प्रवेश करेंगे जब सिस्टम [ट्रांजेक्शन डेटा को रिलीज़ करने के लिए `setDataSize(0)` कॉल करता है](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/native/libs/binder/IPCThreadState.cpp;l=1483-1488;drc=187efe18e3de6258af0230198c881915cc695567), लेकिन उस स्थिति में हम `if (desired == 0)` में भी प्रवेश करेंगे जो जल्दी लौट जाता है। वैध सिस्टम उपयोग के दौरान ऐसा कोई मामला नहीं है जहां हम "यदि कोई भिन्न मालिक है, तो हमें कब्ज़ा लेना होगा" पथ में प्रवेश करें

# "कब्ज़ा लेने" पथ को ट्रिगर करना

अपने पिछले एक्सप्लॉइट में मैंने [वह मामला दिखाया था जहाँ `createFromParcel()` वास्तव में उस `Parcel` पर `writeInt(0)` कॉल कर सकता है जिससे उसे पढ़ना चाहिए](https://github.com/michalbednarski/TheLastBundleMismatch#side-effects)। जबकि वहाँ के फिक्स ने `AccountManagerService` के अंदर किसी भी गैर-`Intent` `createFromParcel()` विधियों के निष्पादन को रोक दिया, `createFromParcel()` से `writeInt(0)` वाला पथ बरकरार रखा गया

पुनर्कथन के लिए, [`PackageParser` के अंदर हमारे पास निम्नलिखित कोड है](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/content/pm/PackageParser.java;l=7789-7795;drc=7d3ffbae618e9e728644a96647ed709bf39ae759):```java
final Class<T> cls = (Class<T>) Class.forName(componentName);
final Constructor<T> cons = cls.getConstructor(Parcel.class);

intentsList = new ArrayList<>(N);
for (int i = 0; i < N; ++i) {
    intentsList.add(cons.newInstance(in));
}

इसलिए, हमारे पास Parcel ऑब्जेक्ट हो सकता है, जो createFromParcel में पारित किया गया था, सिस्टम में उपलब्ध किसी भी public कंस्ट्रक्टर को पारित किया जा सकता है जो एकल Parcel तर्क स्वीकार करता है

और अन्यत्र हमारे पास निम्नलिखित कोड है:```java public PooledStringWriter(Parcel out) { mOut = out; mPool = new HashMap<>(); mStart = out.dataPosition(); out.writeInt(0); // reserve space for final pool size. }

इसलिए, "take possession" पथ को ट्रिगर करने के लिए, हमें `onTransact()` पर `data` के रूप में पारित `Parcel` पर मनमाना `readParcelable` कॉल की आवश्यकता है, इस एक्सप्लॉइट में मैं इसके लिए [वही पथ उपयोग कर रहा हूँ जो मैंने पहले एक अलग में उपयोग किया था](https://github.com/michalbednarski/LeakValue#putting-parcelables-in-system_server-and-retrieving-them)। मेरे पास `readParcelable` कॉल `PackageParser$Activity.CREATOR.createFromParcel()` है, जो बदले में `PooledStringWriter` नाम पढ़ता है और उसका कंस्ट्रक्टर कॉल करता है और उसके बाद `Parcel` डेटा समाप्त हो जाता है, इसलिए `writeInt()` को Parcel को पुनः आवंटित करने की आवश्यकता होती है, जो हमारे "take possession" पथ में प्रवेश करता है

यहाँ ध्यान देने योग्य है, यदि उस बिंदु पर `Parcel` डेटा का अंत नहीं होता, तो `writeInt()` डेटा को उसी स्थान पर अधिलेखित करने का प्रयास करेगा, जो `/dev/binder` `mmap` द्वारा समर्थित डेटा के मामले में `SIGSEGV` की ओर ले जाएगा

# फ़ाइल डिस्क्रिप्टर सैनिटाइज़र
टूल डाउनलोड करें