1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=958 The following code in frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp doesn't validate the parameter params.num_bssid, and then copies that number of elements into a stack-allocated wifi_bssid_hotlist_params structure. I don't think this can be reached from an untrusted_app context; but it can be reached from a context with system_api_service access; so a compromised platform app or one of several lower privileged system services (bluetooth, nfc etc.). static jboolean android_net_wifi_setHotlist( JNIEnv *env, jclass cls, jint iface, jint id, jobject ap){ JNIHelper helper(env); wifi_interface_handle handle = getIfaceHandle(helper, cls, iface); ALOGD("setting hotlist on interface[%d] = %p", iface, handle); wifi_bssid_hotlist_params params; memset(¶ms, 0, sizeof(params)); params.lost_ap_sample_size = helper.getIntField(ap, "apLostThreshold"); JNIObject<jobjectArray> array = helper.getArrayField( ap, "bssidInfos", "[Landroid/net/wifi/WifiScanner$BssidInfo;"); params.num_bssid = helper.getArrayLength(array); if (params.num_bssid == 0) { ALOGE("setHotlist array length was 0"); return false; } for (int i = 0; i < params.num_bssid; i++) { // <--- no validation on num_bssid JNIObject<jobject> objAp = helper.getObjectArrayElement(array, i); JNIObject<jstring> macAddrString = helper.getStringField(objAp, "bssid"); if (macAddrString == NULL) { ALOGE("Error getting bssid field"); return false; } ScopedUtfChars chars(env, macAddrString); const char *bssid = chars.c_str(); if (bssid == NULL) { ALOGE("Error getting bssid"); return false; } parseMacAddress(bssid, params.ap[i].bssid); // <--- params.ap has 128 elements. mac_addr addr; memcpy(addr, params.ap[i].bssid, sizeof(mac_addr)); char bssidOut[32]; snprintf(bssidOut, sizeof(bssidOut), "%0x:%0x:%0x:%0x:%0x:%0x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ALOGD("Added bssid %s", bssidOut); params.ap[i].low = helper.getIntField(objAp, "low"); params.ap[i].high = helper.getIntField(objAp, "high"); } See attached for a POC which causes a crash before the function with the corrupted stack frame returns and checks the stack cookie. LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA [---------------------------------------------------------------------REGISTERS----------------------------------------------------------------------] *X0 0x80000000 <-- 0x0 *X1 0x0 *X2 0x707882c3e0 <-- u'c0:1d:b3:3f:01:...' *X3 0x3 *X4 0x709bf05fc0 <-- stpx28, x27, [sp, #-0x60]! *X5 0x709c1f07b0 (art::gJniNativeInterface) <-- 0x0 *X6 0x709bf27034 <-- cbzx2, #0x709bf27040 /* u'b' */ *X7 0x284801ff284800ff *X8 0xc01d0142c01d0229 *X9 0x1 *X100xc01d0142c01d0141 *X110x7082dff4e8 <-- 0x41013fb31dc0 X120x0 *X130x0 *X140x0 *X150x33511e057221be *X160x709f0035a0 (pthread_getspecific@got.plt) --> 0x709efaad5c (pthread_getspecific) <-- movz w8, #0x8000, lsl #16 *X170x709efaad5c (pthread_getspecific) <-- movz w8, #0x8000, lsl #16 *X180x0 *X190x707882c3e0 <-- u'c0:1d:b3:3f:01:...' *X200x7082dfe0a0 --> 0x70833c1470 --> 0x7083381c0c (android::JNIObject<_jobject*>::~JNIObject()) <-- adrp x2, #0x70833c2000 *X210x7082dfe0b8 --> 0x70833c1490 --> 0x7083381c70 (android::JNIObject<_jstring*>::~JNIObject()) <-- adrp x2, #0x70833c2000 *X220x7082dfe078 <-- 0x0 *X230xb1da807287fa8cf *X240x709f00e86c (je_tsd_tsd) <-- 0xa880000000 *X250x7082dfe8d8 <-- u'c0:1d:b3:3f:1:4...' *X260x200011 *X270x7082dfe0d0 <-- 0x100000000001 *X280x707882c3e0 <-- u'c0:1d:b3:3f:01:...' *SP 0x70815310f0 <-- 0x0 *PC 0x709efaada8 (pthread_getspecific+76) <-- ldrx10, [x10, #0xe0] [------------------------------------------------------------------------CODE------------------------------------------------------------------------] => 0x709efaada8L <pthread_getspecific+76>ldrx10, [x10, #0xe0] 0x709efaadacL <pthread_getspecific+80>cmpx10, x9 0x709efaadb0L <pthread_getspecific+84>b.ne #pthread_getspecific+56 <0x709efaad94> ... 0x709efaad94L <pthread_getspecific+56>movx0, xzr 0x709efaad98L <pthread_getspecific+60>strxzr, [x8] 0x709efaad9cL <pthread_getspecific+64>ret 0x709efaada0L <pthread_getspecific+68>addx10, x10, x8, lsl #4 0x709efaada4L <pthread_getspecific+72>addx8, x10, #0xe8 => 0x709efaada8L <pthread_getspecific+76>ldrx10, [x10, #0xe0] 0x709efaadacL <pthread_getspecific+80>cmpx10, x9 0x709efaadb0L <pthread_getspecific+84>b.ne #pthread_getspecific+56 <0x709efaad94> [------------------------------------------------------------------------CODE------------------------------------------------------------------------] 155 in bionic/libc/bionic/pthread_key.cpp [-----------------------------------------------------------------------STACK------------------------------------------------------------------------] 00:0000| sp0x70815310f0 <-- 0x0 ... 04:0020| 0x7081531110 --> 0x3f800000 <-- 0x0 05:0028| 0x7081531118 <-- 0x0 ... [---------------------------------------------------------------------BACKTRACE----------------------------------------------------------------------] >f 0 709efaada8 pthread_getspecific+76 f 1 709efd2394 je_free+68 f 2 709efd2394 je_free+68 f 3 709efd2394 je_free+68 f 4 709efd2394 je_free+68 f 5 7083387d10 f 6 7083387d10 f 7 7083387d10 Program received signal SIGSEGV (fault address 0x1d0142c01d0221) pwndbg> bt #0pthread_getspecific (key=<optimized out>) at bionic/libc/bionic/pthread_key.cpp:160 #10x000000709efd2394 in je_tsd_wrapper_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609 #2je_tsd_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609 #3je_tsd_fetch () at external/jemalloc/include/jemalloc/internal/tsd.h:614 #4je_free (ptr=0x707882c3e0) at external/jemalloc/src/jemalloc.c:1932 #50x0000007083387d10 in _JNIEnv::ReleaseStringUTFChars (utf=0x707882c3e0 "c0:1d:b3:3f:01:"..., string=0x200011, this=0x7091fd2b00) at libnativehelper/include/nativehelper/jni.h:851 #6ScopedUtfChars::~ScopedUtfChars (this=<synthetic pointer>, __in_chrg=<optimized out>) at libnativehelper/include/nativehelper/ScopedUtfChars.h:45 #7android::android_net_wifi_setHotlist (env=0x7091fd2b00, cls=<optimized out>, iface=<optimized out>, id=0x690a3633, ap=<optimized out>) at frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp:799 #80x000000709b1a084c in ?? () Fixed in https://source.android.com/security/bulletin/2016-12-01.html Proof of Concept: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40945.zip |